带有“ nextDrawable”的难以捉摸的金属问题

时间:2018-10-21 16:25:52

标签: metal metalkit

我在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通话有时对我来说是停滞不前。


0 个答案:

没有答案