我在3840x2160监视器上设置了四个1920x1080 MTKView
实例作为NSWindow
的子视图,作为调试配置。想象一下,我的四个视图以象限编号(右上角为“ 1”,然后逆时针旋转)。在这些视图上播放了四个视频。通过专用于每个CVPixelBuffers
的渲染循环,从每个AVPlayer
捕获它们的CVDisplayLink
。每个MTKView
被配置为通过这四个相同的CVDisplayLink
回调进行手动绘制。其中的MTKView
draw
调用位于@autoreleasepool
内部。
所有这些在大约95%的时间内都可以很好地运行-在Radeon R9 M395,iMac 5k 2015后期(带融合驱动器)上,GPU内存使用率为75%,GPU处理率为20%。 Xcode中的Metal Trace使我所有的GPU渲染每帧花费不超过5毫秒。
我正试图找出为什么某些视频出现约5%的时间断断续续的情况。 GPU帧捕获为我提供了一个线索,但是我不确定该怎么办。
在每个MTKView
drawRect
调用中,我对我分配的纹理和最多两个传入的CVPixelBuffer
纹理(即用于从一个视频到另一个视频)。我不要求或触摸其中的currentRenderPassDescriptor
。
在完成这批MTLComputeCommandEncoder
的工作之后,我进行了一次最终遍历,将MTLRenderCommandEncoder
和一组顶点与最终的计算纹理结果作为输入:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
dispatch_semaphore_wait(self.inflightSemaphore, DISPATCH_TIME_FOREVER);
id<MTLCommandBuffer> commandBuffer = [metalCommandQueue commandBuffer];
<do 4 passes of compute work>
// ********* The next line is where WARNINGS (see below) occur ***********
MTLRenderPassDescriptor *renderPassDescriptor = self.currentRenderPassDescriptor;
id<MTLDrawable> currentDrawable = nil;
if (renderPassDescriptor) {
currentDrawable = self.currentDrawable;
[self doVertexWork:inputTexture
onCommandBuffer:commandBuffer
withDescriptor:renderPassDescriptor];
}
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
dispatch_semaphore_signal(self.inflightSemaphore);
}];
if (currentDrawable)
[commandBuffer presentDrawable:currentDrawable];
[commandBuffer commit];
commandBuffer=nil;
}
如果执行GPU帧捕获,我会注意到帧率为120fps,4个绘制调用,4个命令缓冲区和4个渲染编码器。但是,在指示的行上我总共收到7条警告:
CAMetalLayer nextDrawable Called Early
(一次)CAMetalLayer nextDrawable was Called Unnecessarily
(三次)Command Buffer was not Enqueued and Committed in this Frame
(三次-命令在1,3,4象限上缓冲)顺便说一句,Xcode提供了有关提早通话的说明:"Your application called CAMetalLayer nextDrawable earlier than needed. This may block execution until a CAMetalDrawable is available. Delay the call to nextDrawable until the drawing is needed for encoding".
我在文档中注意到被阻止的执行发生了一秒钟,这与我偶尔看到的断断续续的时间(即每1秒左右更新一次)相符。
在进行顶点工作时,在endEncoding
调用中,我收到"CAMetalDrawable used from Earlier Frame"
警告(三次,仅来自象限1,2,4的纹理)。
有趣的旁注:当帧捕获暂停的事物时,第3象限的图像在第2象限中复制,而第2象限的图像不可见。
由于我遵循在此看到的所有示例所使用的技术,因此我无法真正弄清问题所在。
任何帮助将不胜感激。
更新#1
基于Ken-Thomases有用的评论,我在绘制调用中创建了命令缓冲区后立即插入了以下行:
[metalCommandQueue insertDebugCaptureBoundary];
这几乎解决了所有声称的问题,但我仍然偶尔会看到1秒的断断续续。唯一剩下的问题是一个一致的CAMetalLayer nextDrawable was Called Unnecessarily
,其中的注释是“您的应用程序名为CAMetalLayer nextDrawable
,但在框架中没有使用返回的CAMetalDrawable
”。无论是否发生口吃,都会发生这种情况。
据我所知,这个nextDrawable
通话有时对我来说是停滞不前。