我的另一篇文章打算收集有关 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
- 渲染全屏四边形
glMemoryBarrier(GL_ALL_BARRIER_BITS);
启用着色器 2
- 渲染两个小三角形
glMemoryBarrier(GL_ALL_BARRIER_BITS);
启用着色器 3
- 渲染全屏四边形
请注意,在第 3 步和第 6 步中,我 [认为我] 可以使用 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT。以防万一,我是保守的。
可视化的颜色随时间抖动,并且大多相当小。这表明原子性没有发生。有人可以理智地检查这个程序吗?我错过了什么吗?
编辑:从这个页面,我发现使用discard
可以使图像加载/存储在片段中未定义。我删除了丢弃物,但问题仍然存在。我还发现layout(early_fragment_tests) in;
,它强制进行早期片段测试(它也没有帮助)。