簡體   English   中英

GLSL原子圖像訪問

[英]GLSL Atomic Image Access

我的另一篇文章打算收集有關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. 啟用着色器3

  8. 渲染全屏四邊形

請注意,在第3步和第6步中,我[認為我]本可以使用GL_SHADER_IMAGE_ACCESS_BARRIER_BIT。 以防萬一,我很保守。

可視化的顏色會隨着時間而抖動,並且通常很小。 這表明原子性沒有發生。 有人可以檢查這個程序嗎? 我有什么想念的嗎?

編輯:從此頁面 ,我發現使用discard可以使圖像加載/存儲在片段中未定義。 我刪除了丟棄物,但問題仍然存在。 我還發現了layout(early_fragment_tests) in; ,這會強制進行早期片段測試(也沒有幫助)。

另一個相關鏈接:
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編碼如何獲得。 重點是,嘗試使用多種不同的方式編寫相同的代碼會有所幫助。 我已經看到了while循環失敗時函數作為條件的問題。 就我所知,.. while與典型的while編譯有很大不同。 將盡可能多的條件組合到循環條件中有時也會有所幫助。 有時, else break無法達到預期效果,或者使編譯器無法展開某些循環,因此您必須使用以下命令:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM