2016-02-19 57 views
1

我是使用OpenGL編寫Android應用程序的團隊的一部分。我們有很多着色器代碼模擬使用浮點數的雙精度數學。 (具體來說,我們在Andrew Thall的Extended-Precision Floating-Point Numbers for GPU Computation中實現了這些算法。)它在應用程序的DirectX版本中運行良好,但我發現在Android上,GLSL編譯器正在以代數方式優化一些代碼,應該被保留下來,但實際上它會改變行爲,因爲優化會拋出浮點錯誤。例如,在以下幾點: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)它是編譯器依賴的。另一個編譯器可能不需要它,而另一個編譯器可以想象將數值優化爲。有沒有一種「正確」的方法來解決這個問題,並確保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」代表這兩個「力」和「鬧劇」,因爲你迫使操作,但需要是白癡。)它們分別複製(a + b)和(a - b)的功能,但是以編譯器不應該優化的方式,不使用分支並使用fast builtin來完成工作。所以上面的錯誤保留「添加」功能就變成了:

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

請注意,我們不總是需要使用我們的「FRC」功能(例如方程找到錯誤),但只有在地方的編譯器可能已經完成了優化。

回答

0

不可以。在GLSL中沒有約束方式來控制優化。如果編譯器認爲假設誤差項爲零是合理的,那麼它將爲零。

+0

這是...有點令人失望。 :/但thx。 – BLee