Search code examples
c#opengltexturescompute-shader

Why isn't my compute shader doing anything?


I'm in OpenGL 4.5 (OpenGL.net in c#, but the code is very similar to normal OpenGL code), and am trying to use a compute shader. Here's what I have so far:

// (Compile and link stuff, this part I know works)

// Use the compute shader
Gl.UseProgram(program);

// Create the texture the compute shader will output to
int textureWidth = 512, textureHeight = 512;
uint[] texturesMaking = new uint[1];
Gl.GenTextures(texturesMaking);
uint texture = texturesMaking[0];
Gl.ActiveTexture(Gl.TEXTURE0);
Gl.BindTexture(TextureTarget.Texture2d, texture);
Gl.TextureParameter(Gl.TEXTURE_2D, Gl.TEXTURE_MAG_FILTER, Gl.NEAREST);
Gl.TextureParameter(Gl.TEXTURE_2D, Gl.TEXTURE_MIN_FILTER, Gl.NEAREST);
Gl.TexImage2D(TextureTarget.Texture2d, 0, Gl.RGBA32F, textureWidth, textureHeight, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero);

// Get the shader output variable and set it
int location = Gl.GetUniformLocation(program, "destTex");
Gl.Uniform1(location, texture); 
Gl.BindImageTexture(0, texture, 0, false, 0, Gl.READ_WRITE, Gl.RGBA32F);

// Send off the compute shader to do work, with one group per pixel
//  (I know this is far less than optimal, it was just a debugging thing)
Gl.DispatchCompute((uint)textureWidth, (uint)textureHeight, 1);

// Wait for compute shader to finish
Gl.MemoryBarrier(Gl.SHADER_IMAGE_ACCESS_BARRIER_BIT);

// Looking at the texture, it is black

And here is my compute shader:

#version 450
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f) uniform image2D destTex;

void main () {
  imageStore (destTex, ivec2(gl_GlobalInvocationID.xy), vec4(1.0, 0.0, 1.0, 1.0));
}

If I understand this correctly, my texture should be a purple/pink color after the shader runs, but instead it is just black, and printing out a few of the pixels' colors shows that all the values are zero as well. What am I doing wrong?


Solution

  • The problem lies in how you tell the shader which texture to use. The value set by

    int location = Gl.GetUniformLocation(program, "destTex");
    Gl.Uniform1(location, texture); 
    

    has to be the image texture unit (the first parameter of the Gl.BindImageTexture command), not the texture itself. Since you are using the image texture unit 0, you also have to pass 0 to the uniform:

    GLuint unit = 0;
    int location = Gl.GetUniformLocation(program, "destTex");
    Gl.Uniform1(location, unit); 
    Gl.BindImageTexture(unit, texture, 0, false, 0, Gl.READ_WRITE, Gl.RGBA32F);