金属SIMD的最小和最大操作无法进行浮点

时间:2018-12-10 21:57:53

标签: floating-point gpgpu simd metal compute-shader

简短的问题

为什么我从带有浮点数的Metal 2.1中的simd_minsimd_max函数中得到未定义的行为?

更新:似乎这仅发生在Radeon Pro 560X GPU上,而不发生在Intel UHD Graphics 630上。

背景

根据Metal Shading Language Guide第5.14节,常见的标量或向量,整数或浮点类型支持simd_minsimd_max函数。

对于simd_max,规范规定:

  

T simd_max(T data)

     

返回所有数据的最大值   SIMD组中的活动线程和   将结果广播到中的所有活动线程   SIMD组。

测试用例

要对此进行测试,我正在执行以下测试内核,其输入缓冲区为128个随机浮点数,范围为0..100:

kernel void simdMaxDebugKernel(
                          const device float *buffer [[ buffer(0) ]],
                          device float *output [[ buffer(1) ]],
                          uint id [[ thread_position_in_grid ]])
{
    output[id] = simd_max(buffer[id]);
}

通过检查,将128值缓冲区分为两个64值SIMD组。因此,我希望输出中的前64个值将分别设置为第一个SIMD组和最后一个SIMD组的最大值。

测试结果

我得到了一些意想不到的结果:

inputs  [simd_float1]   128 values  
[0] Float   94.3006362
[1] Float   98.1107177
[2] Float   85.3725891
[3] Float   45.1457863
...
[63] Float  36.5486336
[64] Float  56.5494308
[65] Float  45.6249847
[66] Float  34.8077431

actual  [simd_float1]   128 values  
[0] Float   94.3006362
[1] Float   NaN
[2] Float   -3.80461845E+20
[3] Float   0.0000000000000000000000000000000000000212763294
...
[63] Float  0
[64] Float  56.5494308
[65] Float  -2467.3457
[66] Float  0.0000000000010178117
...

expectedMax simd_float1 99.4676971

在我看来,每个SIMD组的第一个SIMD通道的值都只是被复制,其余的未定义。

相比之下,如果按如下所示使用到uint的转换,则内核的行为符合预期:

output[id] = (float)simd_max((uint)buffer[id]);

actual  [simd_float1]   128 values  
[0] Float   99
[1] Float   99
[2] Float   99
...
[63] Float  99
[64] Float  96
[65] Float  96
...

测试配置

  • Mac OS 10.14.2(18C54)
  • MacBook Pro(15英寸,2018年)
  • Radeon Pro 560X 4096 MB
  • XCode版本10.1(10B61)

0 个答案:

没有答案