Opengl 为什么人们在GLSL中写0.00390625而不是1.0/256.0?

Opengl 为什么人们在GLSL中写0.00390625而不是1.0/256.0?,opengl,glsl,Opengl,Glsl,我见过很多类似这样的GLSL代码: vec2 x = y * 0.00390625; 通常,为了清楚起见,我会这样写: vec2 x = y * (1.0 / 256.0); 或作为: vec2 x = y / 256.0; 使用顶级版本是否合理?在我看来,如果您的编译器不支持数字文本的常量折叠,或者不支持简单的强度缩减,那么它将非常可怜 因此,我的问题可以重新表述:您是否真的会遇到不支持不断折叠或强度降低的GLSL编译器?我只是在考虑OpenGL实现中的GLSL编译器,而不是GLSL优化

我见过很多类似这样的GLSL代码:

vec2 x = y * 0.00390625;
通常,为了清楚起见,我会这样写:

vec2 x = y * (1.0 / 256.0);
或作为:

vec2 x = y / 256.0;
使用顶级版本是否合理?在我看来,如果您的编译器不支持数字文本的常量折叠,或者不支持简单的强度缩减,那么它将非常可怜


因此,我的问题可以重新表述:您是否真的会遇到不支持不断折叠或强度降低的GLSL编译器?我只是在考虑OpenGL实现中的GLSL编译器,而不是GLSL优化器。

我不是编译器专家,但如果GLSL编译器不进行简单的常量折叠,我会非常惊讶。因此,我认为可以安全地假设在以下情况下常数的除法在编译时得到计算:

vec2 x = y * (1.0 / 256.0);
第二个案例实际上更有趣:

vec2 x = y / 256.0;

如果这是C或C++代码,我的理解是编译器会使用<强> > < /强>默认的乘法替换。原因是由于舍入不同,无法保证结果与最后一位相同。如需参考,请参阅中的答案,其中一个答案确认,例如,除非使用了

-frecipracal math
编译器选项,否则gcc不会进行替换

然而,GLSL是另一种情况。OpenGLESGLSL规范特别允许这种类型的转换:

C++标准要求表达式必须按操作优先级指定的顺序进行计算,如果结果相同或结果未定义,则只能重新分组。不得应用影响操作结果的其他变换。GLSL ES通过以下方式放宽这些要求:

浮点除法可以用倒数和乘法代替


有趣的是,这不是完整(即非ES)GLSL规范的一部分。它确实有精度要求,即除法误差最多可达2.5 ULP(最后的单位)。按照我的解释,如果用乘法代替除法满足精度要求,那么这种替换是合法的。但为了确保您的代码尽可能高效,在可能的情况下使用乘法而不是除法似乎更安全。

我特别选择了256,因为两种情况下舍入都是相同的。这个答案写得很好,但不幸的是,它没有真正回答问题,这就是是否有理由相信您的GLSL编译器可能不支持强度降低或持续折叠。@DietrichEpp这取决于驱动程序和大多数开发人员,无论如何都会在谨慎方面出错。我希望在野外挖掘一些GLSL编译器的实际经验,因为我们似乎被一堆不同质量的编译器困住了,很难检查它们的输出。如果您对GCC的情况感到好奇,您会发现只要启用了优化,就可以在不使用
-frecipracal math
的情况下降低浮点除法强度。有趣的是,即使在
-O0
下,整数除法也会简化为乘法。