4

我正在寻找有关如何正确实现金属渲染循环的方向。我的渲染循环从AVPlayer.

这是我当前的实现:

  1. A以 60hz 的频率CVDisplayLink查询播放器的。AVPlayerItemVideoOutput如果有一个新帧,它会CVPixelBufferRef被捕获/保存*作为MTKView它将被渲染到的属性。(此时,之前捕获的视频帧被释放)。
  2. MyMTKView设置为isPausedenableSetNeedsDisplayto NO。换句话说,内部计时器的MTKView任务是定期调用其drawRect方法。
  3. drawRect我首先将 new-arrived* 转换CVPixelBuffer为 a MTLTexture,然后出现一堆渲染阶段。
  4. 最后,我presentDrawable在方法结束时调用drawRect

*注意:对 的互斥访问CVPixelBufferRef由一对 dispatch_semaphore_wait和控制dispatch_semaphore_signal

这是一种正确的做事方式吗? 尽管偶尔会丢失一些帧,但它似乎相当高效。在时间方面,Metal 的 Xcode 分析告诉我,我MTLCommandBuffer的运行时间通常不到 3 毫秒。

话虽如此,我看到了一些替代的可能性:

  • 放弃CVDisplayLink实现并抓住其中的框架drawRect
  • 反转渲染过程;显示之前捕获的帧并MTLTexture首先在drawRect方法中渲染,然后commit是 Metal 命令缓冲区并presentDrawable立即调用。在那之后,捕获下一个视频帧并在下一次调用之前运行它的渲染阶段(在退出drawRect之前这样做吗?)。drawRect

另一个问题:我的印象是CVDisplayLinkdrawRect方法都没有在这个配置的主线程上运行。我感到困扰的是,每当我松开应用程序的一个菜单时,视频帧的传递就会出现明显的卡顿——这是主线程进行 UI 更新并阻塞的症状。NSCollectionView当重新加载屏幕并在屏幕上显示其内容时,会观察到相同的行为。这让我相信我的假设是不正确的。如何MTKView制作这些渲染循环来避免这些问题? 想知道整个打开/配置是否也AVPlayer需要脱离主线程。

更新#1

我修复了鼠标悬停在任何项目上时会出现的“另一个问题”口吃问题。NSMenu这是我的解决方案:

  1. MTKViewisPaused=YES和配置每个enableSetNeedsDisplay=NO。这意味着draw视图需要显式调用才能呈现其内容。
  2. CVDisplayLink回调中,发出对on a的draw调用,因此:MTKViewdispatch_global_queue

__block MTKView *aView = ....;
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue, ^{ [aView draw]; });
4

0 回答 0