2014-02-06 62 views
1

我的other post打算收集有關GLSL自旋鎖的種類的一般信息,但不幸的是沒有它的結果,也沒有解決我的問題。因此,一個具體的問題。我將問題簡化爲一個簡單的例子,如下所示:GLSL原子圖像訪問

這個微不足道的問題使得屏幕尺寸的紋理顏色和鎖定紋理。在第一遍中,顏色全部設置爲零(着色器1)。在第二遍中,繪製了兩個三角形,其中幾何着色器四倍和稍微偏移(着色器2)。片段着色器以原子方式遞增紋理的顏色。在通過三時,顏色被可視化(着色器3)。

着色器1:

//Vertex 
#version 440 
uniform mat4 mat_P; 
in vec4 _vec_vert_a; 
void main(void) { 
    gl_Position = mat_P*_vec_vert_a; 
} 

//Fragment 
#version 440 
layout(rgba32f) coherent uniform image2D img0; 
void main(void) { 
    imageStore(img0,ivec2(gl_FragCoord.xy),vec4(0.0,0.0,0.0,1.0)); 
    discard; 
} 

着色器2:

//Vertex 
#version 440 
in vec4 _vec_vert_a; 
out vec4 vert_vg; 
void main(void) { 
    vert_vg = _vec_vert_a; 
} 

//Geometry 
#version 440 
#define REPS 4 
layout(triangles) in; 
layout(triangle_strip,max_vertices=3*REPS) out; 
uniform mat4 mat_P; 
in vec4 vert_vg[3]; 
void main(void) { 
    for (int rep=0;rep<REPS;++rep) { 
     for (int i=0;i<3;++i) { 
      vec4 vert = vert_vg[i]; 
      vert.xy += vec2(5.0*rep); 
      gl_Position = mat_P*vert; EmitVertex(); 
     } 
     EndPrimitive(); 
    } 
} 

//Fragment 
#version 440 
layout(rgba32f) coherent uniform image2D img0; 
layout(r32ui) coherent uniform uimage2D img1; 
void main(void) { 
    ivec2 coord = ivec2(gl_FragCoord.xy); 
    bool have_written = false; 
    do { 
     bool can_write = (imageAtomicExchange(img1,coord,1u)!=1u); 
     if (can_write) { 
      vec4 data = imageLoad(img0,coord); 
      data.xyz += vec3(1.0,0.0,0.0); 
      imageStore(img0,coord,data); 
      memoryBarrier(); 
      imageAtomicExchange(img1,coord,0); 
      have_written = true; 
     } 
    } while (!have_written); 
    discard; 
} 

着色器3:

//Vertex 
#version 440 
uniform mat4 mat_P; 
in vec4 _vec_vert_a; 
void main(void) { 
    gl_Position = mat_P*_vec_vert_a; 
} 

#version 440 
layout(rgba32f) coherent uniform image2D img0; 
void main(void) { 
    vec4 data = imageLoad(img0,ivec2(gl_FragCoord.xy)); 
    gl_FragData[0] = vec4(data.rgb/4.0, 1.0); //tonemap 
} 

主循環:

  1. 啓用着色器1
  2. 渲染全屏四
  3. glMemoryBarrier(GL_ALL_BARRIER_BITS);

  4. 啓用着色器2

  5. 渲染的兩個小三角形
  6. glMemoryBarrier(GL_ALL_BARRIER_BITS);

  7. 啓用的Shader 3

  8. 呈現全屏四

注意,在步驟3和6 I [想我]可能有使用GL_SHADER_IMAGE_ACCESS_BARRIER_BIT。以防萬一,我保守。

可視化的顏色隨着時間的抖動,而且大都相當小。這表明原子沒有發生。有人可以檢查這個程序嗎?我錯過了什麼?

編輯:從this page,我發現使用discard可以使圖片加載/存儲未定義的片段。我刪除了丟棄物,但問題仍然存在。我還發現layout(early_fragment_tests) in;,這迫使早期片段測試(它也沒有幫助)。

回答

0

另一個相關鏈接:
https://www.opengl.org/discussion_boards/showthread.php/182715-Image-load-store-mutex-problem?p=1255935#post1255935

一些工作,我測試了它最後一次自旋鎖碼(授予幾年前):
http://blog.icare3d.org/2010/07/opengl-40-abuffer-v20-linked-lists-of.html

同一應用程序的另一種實現:
https://github.com/OpenGLInsights/OpenGLInsightsCode/blob/master/Chapter%2020%20Efficient%20Layered%20Fragment%20Buffer%20Techniques/lfbPages.glsl

在上面的鏈接中,使用了一種絕對重要且可能仍然是的金絲雀。 coherent是重要的,但你有。幾年前memoryBarrier()根本沒有實施,什麼也沒做。我希望情況並非如此,但是它可能是自旋鎖工作得很好,並且寫入img0不會按照以下順序發生。

GLSL編譯器有時可能有點bug。這裏有幾個例子來說明GLSL編碼可以得到多麼奇怪。要點是,嘗試編寫相同代碼的許多不同方式都可以提供幫助。我看到functions as conditionals inside while loops simply failing的問題。 對於我所知道的一切,雖然編譯與一般的時代截然不同。 將多個條件組合成循環條件有時也可以提供幫助。 有時else break並不如預期的行爲或允許編譯器展開一定的循環,你必須使用以下方法:

for (...) 
{ 
    if (...) 
    { 
     ... 
     continue; 
    } 
    break; 
} 
+0

的緩衝代碼不起作用(第一個版本渲染任何東西之前給出了GL錯誤,我報告,並鏈接的一個崩潰)。在查找其他示例代碼的同時,我還發現http://soconne.blogspot.com/p/demos.html,其中各種由於內部編譯器錯誤而崩潰。我也嘗試了for循環。必須有更好的方法,比試圖將製造商的代碼用於廣告宣傳。 – imallett