正在读取imageStore()之后的texel

Reading texels after imageStore()

本文关键字:之后 texel 读取 imageStore      更新时间:2023-10-16

我正在用imageStore()修改纹理的texel,之后我用texture()将其他着色器中的这些texel读取为sampler2D,但我得到了在imageStore(()之前存储在纹理中的值。使用imageLoad()可以很好地工作,但我需要使用过滤,texture()的性能更好,所以有没有办法用texture(()获得修改后的数据?

编辑:

第一个片段着色器(用于写入):

#version 450 core
layout (binding = 0, rgba32f) uniform image2D img;
in vec2 vs_uv_out;
void main()
{
    imageStore(img, ivec2(vs_uv_out), vec4(0.0f, 0.0f, 1.0f, 1.0f));
}

第二个片段着色器(用于读取):

#version 450 core
layout (binding = 0) uniform sampler2D tex;
in vec2 vs_uv_out;
out vec4 out_color;
void main()
{
    out_color = texture(tex, vs_uv_out);
}

这就是我运行着色器的方式:

glUseProgram(shader_programs[0]);
glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, 
                   GL_RGBA32F);
glDrawArrays(GL_TRIANGLES, 0, 6);
glUseProgram(shader_programs[1]);
glBindTextureUnit(0, texture);
glDrawArrays(GL_TRIANGLES, 0, 6);

我制作了这个简单的应用程序来测试这一点,因为真实的应用程序非常复杂,我首先用红色清除纹理,但纹素不会显示为蓝色(除了在第二个frag.shader中使用imageLoad)。

哦,那很容易。Image Load/Store的写入使用了非相干内存模型,而不是OpenGL其他大部分使用的同步模型。因此,仅仅因为你用图像加载/存储写了一些东西,并不意味着它对其他人可见。你必须明确地使其可见以供阅读。

在写入数据的渲染操作和读取数据的操作之间需要一个glMemoryBarrier调用。由于读取操作是纹理提取,因此要使用的正确屏障是GL_TEXTURE_FETCH_BARRIER_BIT

仅供参考:您的imageLoad之所以能够读取写入的数据,是因为纯粹的运气。没有任何东西可以保证它能够读取写入的数据。为了确保这样的读取,您还需要一个内存屏障。虽然明显不同:GL_SHADER_IMAGE_ACCESS_BARRIER_BIT


此外,texture采用归一化纹理坐标。imageStore取整数像素坐标。除非该纹理是矩形纹理(由于使用了sampler2D,所以它不是矩形纹理),否则不可能将完全相同的坐标传递给imageStoretexture

因此,要么像素被写入错误的位置,要么纹理被从错误的位置采样。无论哪种方式,都存在明显的沟通错误。假设vs_uv_out真的是非标准化的,那么你应该使用texelFetch或者标准化它。幸运的是,你使用的是OpenGL 4.5,所以这应该很简单:

ivec2 size = textureSize(tex);
vec2 texCoord = vs_uv_out / size;
out_color = texture(tex, texCoord);