2016-06-13 25 views
1

私はMetalとCocoaを学び、将来の実験のためのプラットフォームとして定型アプリケーションを作成しようとしています。このプロセスの一環として、私は60fpsで自身(または、より正確にはCAMetalLayerの内容)を再描画するビューを実装しています。また、教育目的のためにMTKViewを避けてください( "学習ココアの部分"のために)。ここで私は問題に取り組むてるかの省略コードスニペットです:継続的に再描画されるMetal NSViewを作成する正しい方法

@implementation MyMetalView // which is a subclass of NSView 

- (BOOL) isOpaque { 
    return YES; 
} 

- (NSViewLayerContentsRedrawPolicy) layerContentsRedrawPolicy { 
    return NSViewLayerContentsRedrawOnSetNeedsDisplay; 
} 

- (CALayer *) makeBackingLayer { 
    // create CAMetalLayer with default device 
} 

- (BOOL) wantsLayer { 
    return YES; 
} 

- (BOOL) wantsUpdateLayer { 
    return YES; 
} 

- (void) displayLayer:(CALayer *)layer { 
    id<MTLCommandBuffer> cmdBuffer = [_commandQueue commandBuffer]; 
    id<CAMetalDrawable> drawable = [((CAMetalLayer *) layer) nextDrawable]; 

    [cmdBuffer enqueue]; 
    [cmdBuffer presentDrawable:drawable]; 

    // rendering 

    [cmdBuffer commit]; 
} 

@end 

int main() { 
    // init app, window and MyMetalView instance 

    // invocation will call [myMetalViewInstance setNeedsDisplay:YES] 
    [NSTimer scheduledTimerWithTimeInterval:1./60. invocation:setNeedsDisplayInvokation repeats:YES]; 

    [NSApp run]; 
    return 0; 
} 

は、それは私が欲しいものを行うには正しい方法は何ですか?または、私は長い間、推奨されていないアプローチを選択しましたか?

答えて

1

NSTimerではなく、CVDisplayLinkを使用して、ディスプレイのリフレッシュレートと一致する必要があるアニメーションをドライブすることを強くお勧めします。

あなたはCVDisplayLinkRefを保持するIVARまたはプロパティを作成したいと思う:

CVDisplayLinkRef displayLink; 

次に、あなたのビューが画面上で起こっているとあなたがアニメーションを開始するときに、あなたが設定し、作成します、ディスプレイリンクを開始してください:

CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); 
CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self); 
CVDisplayLinkStart(displayLink); 

ディスプレイリンクコールバックは静的関数である必要があります。あなたのビューが表示を離れたとき

static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) 
{ 

    [(MyMetalView *)displayLinkContext setNeedsDisplay:YES]; 
    return kCVReturnSuccess; 
} 

:それは、ディスプレイのV-ブランク期間(物理的なV-空白がない現代のディスプレイ上で、これはまだ、通常の60Hzのリズムで起こる)の最初に呼び出されますあなたが一時停止したい場合、または、あなたが出て表示リンクを解放し、それnilにすることができます:

CVDisplayLinkRelease(displayLink); 
+0

私はちょうど 'MyDisplayLinkCallback'に直接私のレンダリングコードを呼び出すことができますか? –

+0

私は個人的に私の描画を 'updateLayer'実装または' updateLayer'によって呼び出されたメソッドに残しました。クラスの実装とコールバック(必要以上に大きい程度)を渡ってビューのコードを分割するのではなく、ビューの実装に戻す方法としてコールバック関数を使用する方が良いでしょう。 – warrenm

+0

私は 'setNeedsDisplay:YES'の代わりにコールバックからビューの' updateLayer'を呼び出すことを意味しました。私が正しく理解していれば、 'setNeedsDisplay:YES'のみ**スケジュール**将来、いつか再描画する予定です。これは追加の待ち時間を導入しますか? –

関連する問題