thread_position_in_grid究竟在金属计算内核着色器中意味着什么?

时间:2018-03-22 05:41:01

标签: ios kernel metal

虽然这是对计算着色器的不恰当使用,但我正在做一些实验,以确定是否可以使用一个来生成一般的UV渐变,其中图像的一个通道在x轴上从0到0线性地线性化通道在图像的y轴上从0到0。然而,当我通过thread_position_in_grid.x值除以图像宽度来改变纹理的b值来生成此图像时,我感到困惑。我在thread_position_in_grid位置编辑了纹理的像素:

enter image description here

是的,这是一个渐变,但它似乎并不是我想要的0-1的渐变。我将它放入图像编辑器中,确定它不是线性的。 (下面添加的部分显示了0-1的线性渐变)

enter image description here

似乎我不明白th​​read_position_in_grid值究竟是什么意思。我知道它与每个线程组和线程执行宽度的线程有关,但我不完全明白什么。我想我的最终目标是知道是否可以在计算着色器中生成下面的渐变,但我不明白发生了什么。

enter image description here

作为参考,我正在使用100x100纹理,并具有以下线程设置。真的我不知道为什么我使用这些值,但这是我在某处看到的推荐,所以我坚持使用它们。我希望能够将这个问题概括为其他纹理大小,包括矩形。

let w = greenPipeline.threadExecutionWidth
let h = greenPipeline.maxTotalThreadsPerThreadgroup / w
let threadsPerThreadgroup = MTLSizeMake(w, h, 1)
let threadgroupsPerGrid = MTLSize(width: (texture.width + w - 1) / w,
                                  height: (texture.height + h - 1) / h,
                                  depth: 1)
encoder.dispatchThreadgroups(threadgroupsPerGrid, threadsPerThreadgroup: threadsPerThreadgroup)

我的着色器看起来像这样:

kernel void green(texture2d<float, access::write> outputTexture [[texture(0)]],
                             uint2 position [[thread_position_in_grid]])
{
    if (position.x >= outputTexture.get_width() || position.y >= outputTexture.get_height()) {
        return;
    }
    outputTexture.write(float4(position.x / 100.0, 0.0, 0.0, 0.0), position);
}

关于这个着色器的两件事让我感到困惑,因为我无法解释它们:

  1. 我使用position作为坐标来写入纹理 令我困扰的是,这个位置无法生成渐变。
  2. 你不能用position.x / 100.0重新设置position.x / outputTexture.getWidth()值,即使它也应该是100.这样做会导致黑色图像。然而,当我制作一个使用outputTexture.getWidth()作为其值对所有颜色进行着色的着色器时,确实将所有颜色都设置为相当于100的值(或者因为四舍五入而更准确地为101)
  3. 可以使用position检查内核是否在边界内,但不能创建UV渐变。
  4. 发生了什么事?

1 个答案:

答案 0 :(得分:0)

thread_position_in_grid表示您想要它的意思,因为决定网格的大小以及网格中每个线程的作用。

在您的示例中,thread_position_in_grid是纹理中的像素坐标,因为您的网格大小等于纹理中的像素数(向上舍入到管道的最大线程执行宽度的倍数)。

如果您将threadGroupsPerGrid更改为:

,则可以看到此信息
let threadgroupsPerGrid = MTLSize(width: (texture.width/2 + w - 1) / w,
                                  height: (texture.height/2 + h - 1) / h,
                                  depth: 1)

现在只应填充纹理的前四分之一,因为网格只覆盖纹理宽度和高度的一半。

至于为什么你的纹理看起来很怪异,它可能与像素格式有关。毕竟,你正在写入红色组件,你的纹理会变成蓝色。