2012-09-08 23 views
1

我遇到了一個問題,我認爲這個問題與優化PowerVR GPU的GLSL編譯有關。在Adreno和Tegra GPU上,片段着色器工作得很好,但是在PowerVR(Motorola Droid)上,它在條件語句中產生了不正確的結果。 我通過更改片段着色器代碼中的條件語句解決了問題。我已經添加了else塊,而不是在塊if的塊中調用return塊,現在它在PowerVR上正常工作。PowerVR GPU上的着色器執行流問題

兩種着色器的邏輯都是完全相同的,在兩種情況下都設置爲gl_FragColor。 請解釋PowerVR OpenGL驅動程序的這種行爲,以便將來避免出現問題。爲什麼它以這種方式處理條件語句?

這裏是舊片段着色器,其工作方式不正確有關的PowerVR圖形芯片:

precision mediump float; 

varying vec3 vNormal; 
varying vec3 vViewVec; 
varying vec2 vTextureCoord; 

uniform sampler2D sTexturePumpkin; 

void main(void) 
{ 
const float sheen = 0.68; 
const float noiseScale = 0.05; 
const float furriness = 10.0; 
const vec4 lightDir = vec4(0.267260, 0.267260, -0.925820, 0.0); 

    vec4 color = texture2D(sTexturePumpkin, vTextureCoord/*vec2(0.0,0.0)*/); 
    if(vTextureCoord.y > 0.7) { // in this case PowerVR displays incorrect color 
    gl_FragColor = color; 
    return; 
    } 

    float diffuse = 0.5 * (1.0 + dot(vNormal, vec3(lightDir.x, lightDir.y, -lightDir.z))); 
    float cosView = clamp(dot(normalize(vViewVec), vNormal), 0.0, 1.0); 
    float shine = pow(1.0 - cosView * cosView, furriness); 

    gl_FragColor = (color + sheen * shine) * diffuse; // in this case PowerVR works correctly 
} 

新片段着色器的代碼,這對雙方的Adreno以及PowerVR GPU正常工作:

precision mediump float; 

varying vec3 vNormal; 
varying vec3 vViewVec; 
varying vec2 vTextureCoord; 

uniform sampler2D sTexturePumpkin; 

void main(void) 
{ 
const float sheen = 0.68; 
const float noiseScale = 0.05; 
const float furriness = 10.0; 
const vec4 lightDir = vec4(0.267260, 0.267260, -0.925820, 0.0); 

    vec4 color = texture2D(sTexturePumpkin, vTextureCoord/*vec2(0.0,0.0)*/); 
    if(vTextureCoord.y > 0.7) { 
    gl_FragColor = color; 
    } 
    else { 
    float diffuse = 0.5 * (1.0 + dot(vNormal, vec3(lightDir.x, lightDir.y, -lightDir.z))); 
    float cosView = clamp(dot(normalize(vViewVec), vNormal), 0.0, 1.0); 
    float shine = pow(1.0 - cosView * cosView, furriness); 
    gl_FragColor = (color + sheen * shine) * diffuse; 
    } 
} 
+2

它看起來像一個驅動程序錯誤。驅動程序錯誤,作爲錯誤,並不是真的可以「解釋」的東西。他們只是發生,而你處理它們。 –

+0

您可以使用vec3(lightDir.xy,-lightDir.z)。 – Jessy

+0

@NicolBolas我相信這不是GLSL編譯器中的錯誤,而是基於PowerVR GPU瓦片渲染和片段着色器執行的特殊性。我想在下面回答一些批評者。 – keaukraine

回答

3

OK所以經過深入調查,我發現它不是着色器編譯器的缺陷,而是處理片段着色器執行的特定方式。將一個簡單的discard;return;語句與其後的一些代碼放在一起通常是一個糟糕的主意。它仍然可以被執行並導致不可預知的結果。

有一些文章解釋了適用於discard;聲明的此行爲,並且正如我所看到的,return;也可能發生類似的行爲。 請在這裏閱讀:http://people.freedesktop.org/~idr/OpenGL_tutorials/03-fragment-intro.html#infinite-loop 正如在這裏所說的,在某些情況下,您甚至可以通過錯誤地使用discard;來實現無限循環。

片段着色器由GPU執行,而不是一次一個紋理元素,通常是批量爲2×2像素。這段並行運行的片段着色器會導致return;之後的代碼。

因此,對於片段着色器正確處理if語句,你必須始終使用elseif運營商,而不是簡單地通過return;discard;退出功能。這正是我所做的。