GLSL中常数和常数之间的浮点行为不同 [英] Differing floating point behaviour between uniform and constants in GLSL

查看:157
本文介绍了GLSL中常数和常数之间的浮点行为不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在GLSL中实现模拟的双精度,并且观察到一个奇怪的行为差异,导致GLSL中存在细微的浮点错误.

I am trying to implement emulated double-precision in GLSL, and I observe a strange behaviour difference leading to subtle floating point errors in GLSL.

考虑以下片段着色器,写入4浮点纹理以打印输出.

Consider the following fragment shader, writing to a 4-float texture to print the output.

layout (location = 0) out vec4 Output
uniform float s;
void main()
{
  float a = 0.1f;
  float b = s;

  const float split = 8193.0; // = 2^13 + 1

  float ca = split * a;
  float cb = split * b;

  float v1a = ca - (ca - a);
  float v1b = cb - (cb - b);

  Output = vec4(a,b,v1a,v1b);
}

这是我观察到的输出

统一的GLSL输出:

a = 0.1            0x3dcccccd
b = 2.86129e-06    0x36400497
v1a = 0.0999756    0x3dccc000
v1b = 2.86129e-06  0x36400497

现在,使用b1b2的给定值作为输入,v2b的值没有预期的结果.或至少它的结果与CPU上的结果不同(如此处所示):

Now, with the given values of b1 and b2 as inputs, the value of v2b does not have the expected result. Or at least it does not have the same result as on CPU (as seen here):

C ++输出:

a = 0.100000     0x3dcccccd
b = 0.000003     0x36400497
v1a = 0.099976   0x3dccc000
v1b = 0.000003   0x36400000

请注意v1b值的差异(0x364004970x36400000).

Note the discrepancy for the value of v1b (0x36400497 vs 0x36400000).

因此,为了弄清楚正在发生的事情(以及谁是对的),我尝试重做GLSL中的计算,使用稍有修改的着色器将常量替换为常量,然后将常量替换为常量.

So in an effort to figure out what was happening (and who was right) I attempted to redo the computation in GLSL, replacing the uniform value by a constant, using a slightly modified shader, where I replaced the uniform by it value.

layout (location = 0) out vec4 Output
void main()
{
  float a = 0.1f;
  float b = uintBitsToFloat(0x36400497u);

  const float split = 8193.0; // = 2^13 + 1

  float ca = split * a;
  float cb = split * b;

  float v1a = ca - (ca - a);
  float v1b = cb - (cb - b);

  Output = vec4(a,b,v1a,v1b);
}

这次,我得到与相同计算的C ++版本相同的输出.

This time, I get the same output as the C++ version of the same computation.

带有常量的GLSL输出:

a = 0.1            0x3dcccccd
b = 2.86129e-06    0x36400497
v1a = 0.0999756    0x3dccc000
v1b = 2.86102e-06  0x36400000

我的问题是,什么使浮点计算在均匀变量和常量之间表现出不同?这是幕后的编译器优化吗?

My question is, what makes the floating point computation behave differently between a uniform variable and a constant ? Is this some kind of behind-the-scenes compiler optimization ?

这是我笔记本电脑的英特尔GPU中的OpenGL供应商字符串,但是我在nVidia卡上也观察到了相同的行为.

Here are my OpenGL vendor strings from my laptop's intel GPU, but I also observed the same behaviour on a nVidia card as well.

Renderer : Intel(R) HD Graphics 520
Vendor   : Intel
OpenGL   : 4.5.0 - Build 23.20.16.4973
GLSL     : 4.50 - Build 23.20.16.4973

推荐答案

因此,如 @njuffa 所述,在注释中,通过对 precise修饰符依赖于严格的IEEE754操作的值,解决了该问题:

So, as mentioned by @njuffa, in the comments, the problem was solved by using the precise modifier on the values which depended on rigorous IEEE754 operations:

layout (location = 0) out vec4 Output
uniform float s;
void main()
{
  float a = 0.1f;
  float b = s;

  const float split = 8193.0; // = 2^13 + 1

  precise float ca = split * a;
  precise float cb = split * b;

  precise float v1a = ca - (ca - a);
  precise float v1b = cb - (cb - b);

  Output = vec4(a,b,v1a,v1b);
}

输出:

a = 0.1            0x3dcccccd
b = 2.86129e-06    0x36400497
v1a = 0.0999756    0x3dccc000
v1b = 2.86102e-06  0x36400000

很可能只需要最后一个precise来约束导致其计算的操作,以避免不必要的优化.

it is higly probable that only the last precise are needed to constrain the operations leading to its computation to avoid unwanted optimizations.

这篇关于GLSL中常数和常数之间的浮点行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆