在金属中从“r16Snorm”纹理到“一半”变量的精度损失读数

Precision loss reading from `r16Snorm` texture to `half` variable in Metal

提问人:simd 提问时间:9/30/2023 最后编辑:simd 更新时间:9/30/2023 访问量:50

问:

我的假设是否正确,即将一个值从纹理读取到金属着色语言数据类型中总是不可避免地导致精度损失?从一开始就对我来说并不明显,因为它们都是 16 位格式。但我想可以在其区间 [-1, 1] 中存储更精确的值,但代价是删除此区间之外的任何值。基本上,如果我理解正确,格式没有任何指数位,并且将所有 16 位仅用于有效和符号,那么与 ..r16SNormhalf.r16SNormUNormSNormhalf

这是否意味着从其他任何东西中读取几乎都没有意义?或者也许有一种方法可以以某种方式“重新规范化”?r16SNormfloat

// texture is in .r16SNorm pixel format
texture2d<half, access::sample> texture [[texture(0)]] 

...

// float is fine
float value = texture.sample(sampler, pixel).x;

// half is never enough to store normalized 16-bit???
half value = texture.sample(sampler, pixel).x;
IOS 精密 金属 半精度浮点

评论

1赞 Spo1ler 9/30/2023
我想你回答了你自己的问题。但要详细说明。 是一个 16 位 IEEE 754 浮点数。 相反,format 只是一个表示定点数的整数。基本上,它是在采样时通过将其除以最大值并移动它来归一化的。如果比较 ulps,则一半无法容纳 16 位 snorm 值。halfSNorm
1赞 Spo1ler 9/30/2023
我很确定硬件无论如何都会在完整的 32 位浮点数中对值进行采样,然后它会将其“放入”32 位“变量”或 16 位变量中。因此,您在这里使用 float 保存的唯一内容是寄存器和 ALU。所以这是一个权衡。不,没有办法“重新规范化”它。你用第二个得到的一半是标准化的,只是不那么精确。sample
1赞 Spo1ler 9/30/2023
老实说,我不知道,但在这种确切的情况下,如果不在 32 位浮点中进行数学运算,就无法对 16 位标准数进行归一化,所以没关系。
1赞 Spo1ler 9/30/2023
但是 和 之间的区别是你可以用微基准来衡量的。texture2d<float, ...>texture2d<half, ...>
1赞 Spo1ler 9/30/2023
好吧,将要发出硬件指令的编译器不知道纹理中实际上会有哪些纹理格式,所以我认为它实际上不能做到这一点。我可能错了。

答: 暂无答案