Search code examples
c++glslopengl-4compute-shader

imageLoad glsl always return 0 in compute shader OpenGL 4.3


I know that there is another question with exactly the same title here however the solution provided over there does not work for my case.

I am trying to access pixel value from my compute shader. But the imageLoad function always returns 0.

Here is how I load the image:

void setTexture(GLuint texture_input, const char *fname)
{
    // set texture related

    int width, height, nbChannels;
    unsigned char *data = stbi_load(fname, &width, &height, &nbChannels, 0);
    if (data)
    {
        GLenum format;
        if (nbChannels == 1)
        {
            format = GL_RED;
        }
        else if (nbChannels == 3)
        {
            format = GL_RGB;
        }
        else if (nbChannels == 4)
        {
            format = GL_RGBA;
        }
        glActiveTexture(GL_TEXTURE0 + 1);
        gerr();
        glBindTexture(GL_TEXTURE_2D, texture_input);
        gerr();
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        gerr();
        glTexImage2D(GL_TEXTURE_2D, // target
                     0,             // level, 0 means base level
                     format,        // internal format of image specifies color  components
                     width, height, // what it says
                     0,             // border, should be 0 at all times
                     format, GL_UNSIGNED_BYTE, // data type of pixel data
                     data);
        gerr();
        glBindImageTexture(1,             // unit
                           texture_input, // texture id
                           0,             // level
                           GL_FALSE,      // is layered
                           0,             // layer no
                           GL_READ_ONLY,  // access type
                           GL_RGBA32F);

        // end texture handling
        gerr();
        glBindTexture(GL_TEXTURE_2D, 0); // unbind
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
}

And here is the relevant declaration and calling code in the shader:


layout(rgba32f, location = 1, binding = 1) readonly uniform image2D in_image;

struct ImageTexture
{
    int width;
    int height;
};

vec3 imageValue(ImageTexture im, float u, float v, in vec3 p)
{
    u = clamp(u, 0.0, 1.0);
    v = 1 - clamp(v, 0.0, 1.0);
    int i = int(u * im.width);
    int j = int(v * im.height);

    if (i >= im.width)
        i = im.width - 1;

    if (j >= im.height)
        j = im.height - 1;

    vec3 color = imageLoad(in_image, ivec2(i, j)).xyz;

    if (color == vec3(0))
        color = vec3(0, u, v); // debug 

    return color;
}

I am seeing a green gradient instead of the contents of the image, which means my debugging code is in effect.


Solution

  • Either the internal format of the texture does not match the format which is specified at glBindImageTexture or the format argument is not a valid enumerator constant, when the two-dimensional texture image is specified, because format is used twice, for the internal format and the format (see glTexImage2D):

    glTexImage2D(GL_TEXTURE_2D, // target
                    0,             // level, 0 means base level
                    format,        // internal format of image specifies color
                    // components
                    width, height, // what it says
                    0,             // border, should be 0 at all times
                    format, GL_UNSIGNED_BYTE, // data type of pixel data
                    data);
    

    The format argument to glBindImageTexture is GL_RGBA32F:

    glBindImageTexture(1,             // unit
                        texture_input, // texture id
                        0,             // level
                        GL_FALSE,      // is layered
                        0,             // layer no
                        GL_READ_ONLY,  // access type
                        GL_RGBA32F);
    

    Hence, internal format has to be GL_RGBA32F. A possible fomrat is GL_RGBA:

    glTexImage2D(GL_TEXTURE_2D, // target
                    0,             // level, 0 means base level
                    GL_RGBA32F,        // internal format of image specifies color
                    // components
                    width, height, // what it says
                    0,             // border, should be 0 at all times
                    GL_RGBA, GL_UNSIGNED_BYTE, // data type of pixel data
                    data);