如何将 Metal Performance Shader 与 MTLBlitCommandEncoder 同步?
How do you synchronize a Metal Performance Shader with an MTLBlitCommandEncoder?
我正在尝试更好地理解使用 Metal Performance Shaders
和 MTLBlitCommandEncoder
时的同步要求。
我有一个 MTLCommandBuffer
设置如下:
使用MTLBlitCommandEncoder
将纹理A的一个区域复制到纹理B中。纹理A比纹理B大。我正在提取一个"tile"从纹理 A 复制到纹理 B.
使用 MPSImageBilinearScale
金属性能着色器,将纹理 B 作为源纹理,将第三个纹理纹理 C 作为目标。此金属性能着色器将缩放并可能将纹理 B 的内容转换为纹理 C。
如何确保 blit 编码器在金属性能着色器开始尝试缩放纹理 B 之前完全完成将数据从纹理 A 复制到纹理 B?我是否还需要为此担心,或者命令缓冲区的串行特性是否已经为我解决了这个问题?
Metal 有栅栏的概念,使用 MTLFence
来同步对资源的访问,但无论如何我看不到让金属性能着色器在栅栏上等待。 (而 waitForFence:
出现在编码器上。)
如果我不能使用 fences 并且我确实需要同步,推荐的做法是将 blit 编码器入队,然后在入队着色器和调用 [=18 之前在命令缓冲区上调用 waitUntilCompleted
=]第二次?例如:
id<MTLCommandBuffer> commandBuffer;
// Enqueue blit encoder to copy Texture A -> Texture B
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
[blitEncoder copyFromTexture:...];
[blitEncoder endEncoding];
// Wait for blit encoder to complete.
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
// Scale Texture B -> Texture C
MPSImageBilinearScale *imageScaleShader = [[MPSImageBilinearScale alloc] initWithDevice:...];
[imageScaleShader encodeToCommandBuffer:commandBuffer...];
// Wait for scaling shader to complete.
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
我认为我需要将中间副本复制到纹理 B 中的原因是因为 MPSImageBilinearScale
似乎缩放了它的整个源纹理。 clipOffset
对输出有用,但不适用于实际缩放或变换。因此,需要将图块从纹理 A 提取到与图块本身大小相同的纹理 B 中。然后缩放和变换将 "make sense". 忽略这个脚注,因为我忘记了一些基本的数学原理,并且已经想出了如何使缩放变换的平移属性与 clipRect 一起工作。
Metal 会为您解决这个问题。驱动程序和 GPU 以串行方式在命令缓冲区中执行命令。 ("as though" 允许 运行 事情并行或乱序以提高效率,但前提是结果与串行完成时的结果相同。)
当 CPU 和 GPU 使用相同的对象时会出现同步问题。还可以在屏幕上呈现纹理。 (您不应该渲染到屏幕上显示的纹理。)
有一个section of the Metal Programming Guide是处理shaders对资源的读写访问的,虽然不完全一样,但是应该让你放心:
Memory Barriers
Between Command Encoders
All resource writes performed in a given command encoder are visible
in the next command encoder. This is true for both render and compute
command encoders.
Within a Render Command Encoder
For buffers, atomic writes are visible to subsequent atomic reads
across multiple threads.
For textures, the textureBarrier
method ensures that writes
performed in a given draw call are visible to subsequent reads in the
next draw call.
Within a Compute Command Encoder
All resource writes performed in a given kernel function are visible
in the next kernel function.
MPS 位于 Metal 之上(大部分)。它不会取代它(大部分)。您可能会假设它使用的是您正在使用的常用命令编码器。
有几个领域需要 MTLFences,特别是在与渲染编码器和 MTLHeaps 互操作时。如果可用,请在 MPSImages 和缓冲区类型上使用同步方法,而不是自己滚动。
我正在尝试更好地理解使用 Metal Performance Shaders
和 MTLBlitCommandEncoder
时的同步要求。
我有一个 MTLCommandBuffer
设置如下:
使用
MTLBlitCommandEncoder
将纹理A的一个区域复制到纹理B中。纹理A比纹理B大。我正在提取一个"tile"从纹理 A 复制到纹理 B.使用
MPSImageBilinearScale
金属性能着色器,将纹理 B 作为源纹理,将第三个纹理纹理 C 作为目标。此金属性能着色器将缩放并可能将纹理 B 的内容转换为纹理 C。
如何确保 blit 编码器在金属性能着色器开始尝试缩放纹理 B 之前完全完成将数据从纹理 A 复制到纹理 B?我是否还需要为此担心,或者命令缓冲区的串行特性是否已经为我解决了这个问题?
Metal 有栅栏的概念,使用 MTLFence
来同步对资源的访问,但无论如何我看不到让金属性能着色器在栅栏上等待。 (而 waitForFence:
出现在编码器上。)
如果我不能使用 fences 并且我确实需要同步,推荐的做法是将 blit 编码器入队,然后在入队着色器和调用 [=18 之前在命令缓冲区上调用 waitUntilCompleted
=]第二次?例如:
id<MTLCommandBuffer> commandBuffer;
// Enqueue blit encoder to copy Texture A -> Texture B
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
[blitEncoder copyFromTexture:...];
[blitEncoder endEncoding];
// Wait for blit encoder to complete.
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
// Scale Texture B -> Texture C
MPSImageBilinearScale *imageScaleShader = [[MPSImageBilinearScale alloc] initWithDevice:...];
[imageScaleShader encodeToCommandBuffer:commandBuffer...];
// Wait for scaling shader to complete.
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
我认为我需要将中间副本复制到纹理 B 中的原因是因为 忽略这个脚注,因为我忘记了一些基本的数学原理,并且已经想出了如何使缩放变换的平移属性与 clipRect 一起工作。MPSImageBilinearScale
似乎缩放了它的整个源纹理。 clipOffset
对输出有用,但不适用于实际缩放或变换。因此,需要将图块从纹理 A 提取到与图块本身大小相同的纹理 B 中。然后缩放和变换将 "make sense".
Metal 会为您解决这个问题。驱动程序和 GPU 以串行方式在命令缓冲区中执行命令。 ("as though" 允许 运行 事情并行或乱序以提高效率,但前提是结果与串行完成时的结果相同。)
当 CPU 和 GPU 使用相同的对象时会出现同步问题。还可以在屏幕上呈现纹理。 (您不应该渲染到屏幕上显示的纹理。)
有一个section of the Metal Programming Guide是处理shaders对资源的读写访问的,虽然不完全一样,但是应该让你放心:
Memory Barriers
Between Command Encoders
All resource writes performed in a given command encoder are visible in the next command encoder. This is true for both render and compute command encoders.
Within a Render Command Encoder
For buffers, atomic writes are visible to subsequent atomic reads across multiple threads.
For textures, the
textureBarrier
method ensures that writes performed in a given draw call are visible to subsequent reads in the next draw call.Within a Compute Command Encoder
All resource writes performed in a given kernel function are visible in the next kernel function.
MPS 位于 Metal 之上(大部分)。它不会取代它(大部分)。您可能会假设它使用的是您正在使用的常用命令编码器。
有几个领域需要 MTLFences,特别是在与渲染编码器和 MTLHeaps 互操作时。如果可用,请在 MPSImages 和缓冲区类型上使用同步方法,而不是自己滚动。