在 iOS 上的 Metal 中未触发 addPresentedHandler

Posted

技术标签:

【中文标题】在 iOS 上的 Metal 中未触发 addPresentedHandler【英文标题】:addPresentedHandler not being triggered in Metal on iOS 【发布时间】:2020-03-20 13:05:47 【问题描述】:

我已经尝试设置addPresentedHandler 有一段时间了,但没有运气。

我有一个addCompletedHandler 正在处理包含每帧要执行的渲染工作的命令缓冲区。我已经通过查看代码块中的断点来验证addCompletedHandler 是否正常工作。这些是在运行应用程序时触发的。但是,对于addPresentedHandler,代码块中没有触发断点(我还通过修改代码块中的变量并将printfs 插入代码块中进行了验证)。

我的渲染循环目前非常简单,看起来像这样(希望我已经提供了足够的):

注意:我正在使用 C++ 和 Objective-C++ 的强大组合。因此,下面显示的代码不是实际代码的直接表示。

dispatch_semaphore_wait(m_inFlightFramesSemaphore, DISPATCH_TIME_FOREVER);
m_drawables[m_currentFrameIndex] = [m_swapChain nextDrawable];
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor new];
renderPassDescriptor.colorAttachments[0].texture = m_drawables[m_currentFrameIndex].texture;
renderPassDescriptor.colorAttachments[0].level = 0;
renderPassDescriptor.colorAttachments[0].slice = 0;
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 1.0, 1.0, 1.0);

id<MTLCommandBuffer> commandBuffer = [m_commandQueue commandBuffer];
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor: renderPassDescriptor];
[renderEncoder setRenderPipelineState: m_pipelineState];
[renderEncoder setTriangleFillMode: MTLTriangleFillModeFill];
[renderEncoder setFrontFacingWinding: MTLWindingCounterClockwise];
[renderEncoder setCullMode: MTLCullModeBack];
/* set viewport and scissor (omitted here) */
[renderEncoder useResource: m_vertexBuffer usage: MTLResourceUsageRead stages: MTLRenderStageVertex];
[renderEncoder setVertexBuffer: m_vertexBuffer offset: 0 atIndex: 0];
[renderEncoder useResource: m_indexBuffer usage: MTLResourceUsageRead stages: MTLRenderStageVertex];
[renderEncoder drawIndexedPrimitives: MTLPrimitiveTypeTriangle indexCount: 6
  indexType: MTLIndexTypeUInt32 indexBuffer: m_indexBuffer indexBufferOffset: 0
  instanceCount: 1];
[renderEncoder endEncoding];
PresentDrawable(commandBuffer, m_drawables[m_currentFrameIndex]);
CommitFinalCommandBufferInFrame(commandBuffer);

最后两个函数调用实现如下:

void PresentDrawable(id<MTLCommandBuffer> commandBuffer, id<CAMetalDrawable> drawable)

    [drawable addPresentedHandler:^(id<MTLDrawable> dr) 
        m_framesPresented++;
        if (m_framesPresented == m_maxFrames)
        
            dispatch_semaphore_signal(m_lastFramePresentedSemaphore);
        
    ];

    [commandBuffer presentDrawable:drawable];


void CommitFinalCommandBufferInFrame(id<MTLCommandBuffer> commandBuffer)

    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) 
        dispatch_semaphore_signal(m_inFlightFramesSemaphore);
    ];

    [commandBuffer commit];
    m_framesSubmitted++;
    m_currentFrameIndex = (m_currentFrameIndex + 1) % m_maximumDrawableCount;

我不明白为什么 addPresentedHandler 代码块没有被触发,而 addCompletedHandler 块是......我错过了什么明显的东西吗?

谢谢!

【问题讨论】:

【参考方案1】:

我没有发现您的代码有任何问题,我已经检查过它是否有效。

void PresentDrawable(id<MTLCommandBuffer> commandBuffer, id<CAMetalDrawable> drawable)

    [drawable addPresentedHandler:^(id<MTLDrawable> dr) 

        printf("Handler \n");
        m_framesPresented++;
        if (m_framesPresented == m_maxFrames)
        
            dispatch_semaphore_signal(m_lastFramePresentedSemaphore);
        
    ];

    [commandBuffer presentDrawable:drawable];

【讨论】:

嗯...我得再仔细检查一遍。感谢您的验证。【参考方案2】:

在我的问题中,我没有提到我在 iPhone 11 Pro Max (v13.3) Simulator 上运行。在尝试实际的 iPhone 11 (v13.3.1) 时,我的问题中实现的addPresentHandler 成功触发。我试图确定模拟器上的这种功能限制是否在任何地方都有记录,但结果却是空的。

如docs 中所述,addPresentedHandler 需要 ios 版本 10.3。这也反映在 MTLDrawable.h 中的定义中:

- (void)addPresentedHandler:(MTLDrawablePresentedHandler)block
                             API_AVAILABLE(ios(10.3))
                             API_UNAVAILABLE(macos, macCatalyst);

我找不到任何关于模拟器版本限制的信息。

【讨论】:

以上是关于在 iOS 上的 Metal 中未触发 addPresentedHandler的主要内容,如果未能解决你的问题,请参考以下文章

Cordova 设备在 iOS 中未触发

使用 Flutter App 在 iOS 中未触发 UNUserNotificationCenterDelegate didReceive

iOS Metal:启用用户交互

XLForms 中未触发的事件

iOS上的safari中未显示电话号码

METAL渲染是什么?