iOS 上的 Metal 未触发 addPresentedHandler
addPresentedHandler not being triggered in Metal on iOS
一段时间以来,我一直在尝试设置 addPresentedHandler
,但没有成功。
我有一个 addCompletedHandler
正在处理包含每帧要执行的渲染工作的命令缓冲区。我已经通过在代码块中设置断点来验证 addCompletedHandler
是否正常工作。这些在 运行 应用程序时触发。但是,对于 addPresentedHandler
,代码块内没有断点被触发(我还通过修改代码块中的变量并将 printf
s 插入块中进行了验证)。
我的渲染循环目前非常简单,看起来像这样(希望我提供的足够多):
注意:我使用的是 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
代码块是……我是不是漏掉了什么明显的东西?
谢谢!
我没有发现您的代码有任何问题,我已经检查过它是否有效。
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];
}
在我的问题中,我没有提到我在 iPhone 11 Pro Max (v13.3) 模拟器上 运行。在尝试实际的 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);
我在任何地方都找不到任何关于模拟器版本限制的提及。
一段时间以来,我一直在尝试设置 addPresentedHandler
,但没有成功。
我有一个 addCompletedHandler
正在处理包含每帧要执行的渲染工作的命令缓冲区。我已经通过在代码块中设置断点来验证 addCompletedHandler
是否正常工作。这些在 运行 应用程序时触发。但是,对于 addPresentedHandler
,代码块内没有断点被触发(我还通过修改代码块中的变量并将 printf
s 插入块中进行了验证)。
我的渲染循环目前非常简单,看起来像这样(希望我提供的足够多):
注意:我使用的是 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
代码块是……我是不是漏掉了什么明显的东西?
谢谢!
我没有发现您的代码有任何问题,我已经检查过它是否有效。
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];
}
在我的问题中,我没有提到我在 iPhone 11 Pro Max (v13.3) 模拟器上 运行。在尝试实际的 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);
我在任何地方都找不到任何关于模拟器版本限制的提及。