1

Currently I am trying to write to an image using imageStore in OpenGL. However, using renderdock as my debugger, I find only a black texture after running my program.

I create and bind the image to write to as follows:

glGenTextures(1, &textureID);
glBindTexture(target, textureID);
glObjectLabel(GL_TEXTURE, textureID, -1, "\"3D Texture\"");
glTexStorage3D(target, 1, GL_RGBA8, width, height, depth);

glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

Then I load the texture to a program by doing:

glBindImageTexture(0, textureID, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA8);
GLuint location = glGetUniformLocation(programID, uniform);
glUniform1i(location,0);

And finally I render by calling glDrawArrays().

My fragment shader looks like:

#version 440

out vec3 f_pos;
out vec3 f_norm;
out vec2 f_uv;

layout(RGBA8) uniform image3D volumeMap;

void main()
{
    imageStore(volumeMap, ivec3(0,0,0),
        vec4(0,1,1,0));
}

So my expectation is to find a cyan pixel on the upper left corner of the first layer. However that pixel is black.

I have successfully loaded and read from samplers using the texture() call.

I am not sure if I am missing steps or if the way I am doing stuff is wrong.

EDIT:

I modified my code to not rely on RenderDoc to check for the color.

So I render things as follows

Final Fragment Shader:

#version 440

out vec4 fragment_color;

layout(binding=3, RGBA8) uniform image3D vMap;

void main()
{
    fragment_color = imageLoad(vMap, ivec3(0,0,0));
}

C++

glUseProgram(Program1);
/*load texture as above*/
draw();
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

glUseProgram(Program2);
/*load texture as above*/
draw();

draw simply sets up the geometry buffers and then calls glDrawArrays().

The result is a black mesh where I expect a cyan mesh

Makogan
  • 8,208
  • 7
  • 44
  • 112
  • 2
    "*So my expectation is to find a cyan pixel on the upper left corner of the first layer. However that pixel is black.*" Where is the code that reads this pixel? I'm being serious; that's really important. – Nicol Bolas May 14 '18 at 00:19
  • I am checking the texture directly in renderdoc (I said that on the question). i.e I am launching my program with renderdoc, looking at the uniform with the texture viewer and inspecting the first layer. – Makogan May 14 '18 at 01:22
  • 1
    So, you might be debugging a problem in Renderdoc. I don't know about Renderdoc; I don't know if it has some special functions/tools/etc to synchronize its operations with OpenGL incoherent memory accesses. I don't even know if it needs to. But I do know that it's best to reduce the number of variables as much as possible. Really, this is something that ought to be simple enough to verify through OpenGL. – Nicol Bolas May 14 '18 at 01:31
  • I modified the question to not rely on renderdoc for debugging – Makogan May 14 '18 at 01:55
  • Could it be a problem with your vertex shader? The function `imageLoad()` will store a texel, but doesn't it need to be invoked as part of shading a triangle? That is, you might not be getting any calls to your fragment shader because there's no geometry being rendered. – MichaelsonBritt May 14 '18 at 02:32
  • @MichaelsonBritt I am definetely rendering geometry. The vertex shader is getting called around 10 000 times. – Makogan May 14 '18 at 02:54
  • 1
    @Makogan, Can you measure how many times the fragment shader is being called? I ask because, even if the progam processes 10000 vertices, you still might not have any fragment shader calls if none of the geometry is within the frustum of the camera or otherwise non-renderable. Some detail about how you generate fragment shader calls seems relevant to the issue here. – MichaelsonBritt May 14 '18 at 04:23
  • I am not sure how to measure the calls of only a single shader, however I played around with the code to test your hypothesis. I can guarantee the geometry is being rendered. in other words, there is at least one valid fragment being executed. – Makogan May 14 '18 at 04:32

1 Answers1

2

Image load/store operations operate under the rules of incoherent memory access. This means that writes to them are not visible to later reads unless you explicitly do something to make them visible. Usually, this is a call to glMemoryBarrier.

Always remember that glMemoryBarrier specifies how you intend to access the written value, not how you wrote to it. In this case, the mechanism is the same either way: GL_SHADER_IMAGE_ACCESS_BARRIER_BIT. This command must be placed after the command that writes the data, and before the one that reads it.

Also, I cannot say whether this shader has undefined behavior or not. You have multiple invocations that are all writing to the same memory location. But in your case, they are writing the same value. It is not clear from the description in the specification whether this is genuine UB or whether it is fine. It would certainly be UB if the invocations were writing different data, but I don't know if some exception exists for them writing the same data.

I would be very hesitant about doing this, however.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • There was an error in my edit, I am explicetly calling the memory barrier check, edited my answer. – Makogan May 14 '18 at 12:11