【发布时间】:2019-05-03 21:19:49
【问题描述】:
注意:在许多方面,这是How do you synchronize a Metal Performance Shader with an MTLBlitCommandEncoder? 的后续行动@
当顺序命令编码器之间需要显式同步以及由于 Metal 的架构而不需要同步时,我仍然有点困惑。
在上面链接的问题中,引用了 Apple 的文档:
内存屏障
命令编码器之间
在给定命令编码器中执行的所有资源写入在下一个命令编码器中可见。渲染和计算命令编码器都是如此。
我将此解释为暗示MTLRenderCommandEncoder 不需要与先前的MTLBlitCommandEncoder 显式同步,如果它们都在同一个命令缓冲区中并且一个接一个地出现。
然而,Apple 自己的示例代码似乎与此相矛盾。在Image Filter Graph with Heaps and Fences 中,表明需要MTLFence 来同步对首先在MTLBitCommandEncoder 中使用的纹理的访问,然后是两个连续的MTLComputeCommandEncoder 调用。 (一个用于水平模糊,另一个用于垂直模糊。)
See:
AAPLFilter.m (L:199)
AAPLRenderer.m (L:413)
这些命令编码器在同一个命令缓冲区中执行。为什么第一个MTLComputeCommandEncoder 需要显式等待blit 完成,为什么第二个计算编码器需要等待第一个计算编码器,如果如上所述,“在给定命令编码器中执行的所有资源写入都是在下一个命令编码器中可见。”?
伪示例代码:
- (void)drawInMTKView:(nonnull MTKView *)view {
id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
id<MTLTexture> masterTexture = self.masterTexture;
id<MTLTexture> incomingTexture = [self dequeueRenderedTextureIfPresent];
id<MTLBlitCommandEncoder> blitEncoder = commandBuffer.blitCommandEncoder;
[blitEncoder copyFromTexture:incomingTexture ... toTexture:masterTexture];
[blitEncoder endEncoding];
id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor];
// Is synchronization with the blit encoder required here?
//
// The fragment shader is going to sample from masterTexture and will
// expect that the blit command above will have been completed.
[renderEncoder setFragmentTexture:masterTexture atIndex:0];
[renderEncoder drawPrimitives:...];
[commandBuffer commit];
}
在上面的伪代码中,渲染命令编码器是否必须显式等待 blit 命令编码器完成?在我的previous question 的回答中,我相信答案是“不”。但是查看 Apple 使用栅栏和事件的示例代码,我相信答案是“是”。
如果不需要同步,那么这个伪代码和苹果的示例代码有什么不同呢?
编辑#1:
感谢 Ken 在下面的回答,我很快在 Apple 的开发者论坛上找到了一个相关主题,其中涵盖了这个确切的问题。
苹果开发者论坛:MTLFence detailed behaviour?
正如 Ken 正确指出的那样,要理解的关键细节是跟踪纹理和未跟踪纹理之间的区别。
【问题讨论】: