Android GLSL编译器优化会导致浮点操作的错误行为

Android GLSL编译器优化会导致浮点操作的错误行为,android,opengl-es,glsl,glsles,Android,Opengl Es,Glsl,Glsles,我是使用OpenGL编写Android应用程序团队的一员。我们有很多着色器代码使用浮点模拟双精度数学。(特别是我们在Andrew Thall中实现了算法。)它在DirectX版本的应用程序中运行良好,但我发现在Android上,GLSL编译器优化了一些代码,在代数上,应该保留行为,但实际上,它改变了行为,因为优化正在丢弃浮点错误。例如,在以下情况下: vec2 add(float a, float b) { float sum = a + b; float err = b - (

我是使用OpenGL编写Android应用程序团队的一员。我们有很多着色器代码使用浮点模拟双精度数学。(特别是我们在Andrew Thall中实现了算法。)它在DirectX版本的应用程序中运行良好,但我发现在Android上,GLSL编译器优化了一些代码,在代数上,应该保留行为,但实际上,它改变了行为,因为优化正在丢弃浮点错误。例如,在以下情况下:

vec2 add(float a, float b) {
    float sum = a + b;
    float err = b - (sum - a);
    return vec2(sum, err);
}
编译器会将错误值e简化为0,因为这在代数上是正确的,但当考虑到浮点错误时,情况当然并非总是如此

我尝试了“#pragma optimize(off)”,但它不是标准的,也没有效果。我发现的唯一可行的方法是创建一个“零”统一浮点,该浮点保持设置为0,并将其添加到战略位置的违规值中,因此上述函数的工作版本是:

vec2 add(float a, float b) {
    float sum = a + b;
    sum += zero;
    float err = b - (sum - a);
    return vec2(sum, err);
}
这显然不理想。1) 这是一个PITA,用于跟踪哪些地方需要这样做,2)它依赖于编译器。另一个编译器可能不需要它,另一个编译器可以将e值优化到零。有没有“正确”的方法来解决这个问题并确保GLSL编译器不会优化掉实际的行为

编辑: 虽然技术上的答案看起来仍然是“不”,但我找到了一个更好的解决办法,并希望在这里记录下来。“零”统一方法确实开始因更复杂的表达式/链式操作而失败。我发现的解决方法是创建两个加减函数:

float plus_frc(float a, float b) {
    return mix(a, a + b, b != 0);
}

float minus_frc(float a, float b) {
    return mix(0, a - b, a != b);
}
(frc代表“force”和“farce”,因为您正在强制执行操作,但其必要性是愚蠢的。)它们分别复制了(a+b)和(a-b)的功能,但编译器不应以某种方式进行优化,不使用分支并使用a来完成工作。因此,上述保留错误的“添加”函数变为:

vec2 add(float a, float b) {
    float sum = plus_frc(a, b);
    float err = b - (sum - a);
    return vec2(sum, err);
}

请注意,我们并不总是需要使用“frc”函数(例如,用于查找err的等式),而是仅在编译器可以进行中断优化的地方使用。

否。GLSL中没有绑定方式来控制优化。如果编译器认为假设错误项为零是合理的,那么它将为零。

否。没有绑定方式来控制GLSL中的优化。如果编译器认为假设错误项为零是合理的,那么它将为零