首页 > 解决方案 > 金属质感的右边缘有异常

问题描述

当我在 Macbook Pro 上的集成英特尔 GPU 上运行此代码时,我没有任何问题。但是当我在带有 AMD GPU 的 iMac 上运行它时,这个简单的“Hello World”给了我右边缘的伪像:

在此处输入图像描述

着色器非常简单:

kernel void helloworld(texture2d<float, access::write> outTexture [[texture(0)]],
                     uint2 gid [[thread_position_in_grid]])
{
    outTexture.write(float4((float)gid.x/640,
                            (float)gid.y/360,0,1),
                     gid);
}

我尝试以两种不同的方式查看纹理的内容,但都产生了问题:

将纹理转换为 CIImage 并在 NSImageView 中查看它,或者getBytes直接调用和复制像素数据并从中手动构建 PNG(完全跳过 CIImage)。无论哪种方式都会产生这种奇怪的伪影,因此它确实存在于纹理本身中。

有什么想法会导致这种问题吗?

更新:

令人着迷的是,这个问题似乎与threadsPerThreadgroup但我不确定为什么会这样。

上面的图像是使用每组 24 个线程创建的。如果我将其更改为 16,则伪影将移至底部边缘。

我对此不明白的是,gid无论实际运行的是什么线程组,都应该固定位置,不是吗?因为那是整个图像中各个线程的位置。

标签: gpumetal

解决方案


使用dispatchThreadgroups(),可以为宽度*高度网格之外的网格位置调用计算内核。您必须明确地不执行以下操作:

if (gid.x >= 640 || gid.y >= 360)
    return;

否则,您将尝试在纹理边界之外写入(使用其中一些分量大于 1 的颜色)。这有未定义的结果。

使用dispatchThreads(),Metal 会为您处理此问题,并且不会在您指定的网格大小之外调用。

每组 24 和 16 个线程之间的行为差​​异在于它是否均匀地划分为 640 和 360。不均匀地划分的是被过度调用的维度。


推荐阅读