在GPU进行纹理处理(或计算)时,Metal 在 1D、2D 或 3D 网格上执行设置的内核函数。
网格中的每个点都代表内核函数的一个实例,称为线程(Threads)。
例如,在图像处理中,网格通常是线程的 2D 矩阵, 代表整个图像, 每个线程对应于正在处理的图像的单个像素。
线程被组织成线程组(Threadgroups),这些线程组一起执行并且可以共享一个公共内存块。虽然有时内核函数被设计为使线程彼此独立运行,但线程组中的线程在其工作集上协作也很常见。
下图显示了计算内核如何将正在处理的图像划分为线程组,以及每个线程组如何由单独的线程组成。每个线程处理一个像素。
按网格中的位置识别线程
一个线程可以通过它在网格中的位置来识别;正是这个独特的位置允许内核函数为每个线程做不同的事情。
下面的示例内核函数显示了线程在网格中的位置如何作为参数传递给函数。在这种情况下,参数gid
是表示 2D 坐标的向量,用于读取和写入纹理中的特定位置。
kernel void
grayscaleKernel(texture2d<half, access::read> inTexture [[texture(AAPLTextureIndexInput)]],
texture2d<half, access::write> outTexture [[texture(AAPLTextureIndexOutput)]],
uint2 gid [[thread_position_in_grid]])
{
if((gid.x >= outTexture.get_width()) || (gid.y >= outTexture.get_height()))
{
return;
}
half4 inColor = inTexture.read(gid);
half gray = dot(inColor.rgb, kRec709Luma);
outTexture.write(half4(gray, gray, gray, 1.0), gid);
}
复制代码
[[thread_position_in_grid]]
是一个属性限定符。属性限定符,可以通过它们的双方括号语法来识别。该属性限定符,表示这个值是,线程在网格中的位置。
例如,给定一个由 16 x 16 线程组成的网格,该网格划分为 8 x 4 线程的 2 x 4 线程组,单个线程(在图 中以红色显示)在网格中的位置为 (9,10):
按线程组中的位置识别线程
使用以下代码,可以根据线程在其线程组中的位置以及该线程组在网格中的大小和位置来计算线程在网格中的位置:
kernel void
myKernel(uint2 threadgroup_position_in_grid [[ threadgroup_position_in_grid ]],
uint2 thread_position_in_threadgroup [[ thread_position_in_threadgroup ]],
uint2 threads_per_threadgroup [[ threads_per_threadgroup ]])
{
uint2 thread_position_in_grid =
(threadgroup_position_in_grid * threads_per_threadgroup) +
thread_position_in_threadgroup;
}
复制代码
[[threadgroup_position_in_grid]]
线程组在网格中的位置
[[thread_position_in_threadgroup]]
线程在其线程组中的位置
例如:线程在网格中位置为(1,2)的线程组中,其在该线程组中的位置为(1,2)