Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 2 of 2

Thread: can't get imageStore to work.

Hybrid View

  1. #1
    Newbie Newbie
    Join Date
    Jan 2014
    Posts
    2

    can't get imageStore to work.

    Hi,

    I was hopping someone can help me out here.
    I am trying to get imageStore to work from a simple fragment shader but I had no success until now. I am wondering if I am doing something fundamentally wrong.
    In the code bellow I am sending 200,000 points to render and I am trying to use their index ( gl_VertexID ) to fill in the image2D (1024x1024) like this:
    imageStore(image_out, ivec2(vertexIndex % imageWidth, vertexIndex / imageHeight ) , vec4(1.,1.,1.,1.));

    When I read the pixels from the texture using "glGetTexImage" I get what seems to be random results, while I was expecting to see white color for at least the first 190 lines of the image.
    Some time the image will show parts of the underlying windows, or different pass renders, so I am sure I am doing something very wrong here.
    This is a very simplified version of my real shader. I only tried it for debug and I still could not get it to work . There are no compile or link errors.

    Here is the code:

    1) create the texture that will binded to the image:

    int imageWidth = 1024;
    int imageHeight =1024;
    glGenTextures(1, &glBakeTexture);
    glBindTexture(GL_TEXTURE_2D, glBakeTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageWidth , imageHeight , 0 , GL_RGBA, GL_FLOAT , NULL);
    glBindTexture(GL_TEXTURE_2D, 0);


    2) The following is how I render to image:

    shader->bind();


    shader->setUniformValue( "mvp", mvp );
    // the width of the image2D

    shader->setUniformValue("imageWidth", imageWidth);
    // the height of the image2D
    shader->setUniformValue("imageHeight", imageHeight);

    //glActiveTexture( GL_TEXTURE0 + 2 ); // tried using glActiveTexture that didn't help much
    glBindImageTexture(2, glBakeTexture, 0, false, 0, GL_WRITE_ONLY, GL_RGBA8);

    glBindVertexArray( m_vao );


    // draw points
    glDrawArrays(GL_POINTS, 0, (GLsizei)numberOfPoints); // about 200,000 points


    glBindVertexArray(0);


    shader->release();

    // release textures etc...





    3) read the image using "glGetTexImage"

    // tried both of the following barriers and also "ALL_BIT"
    //glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
    glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);


    glBindTexture(GL_TEXTURE_2D, glBakeTexture);
    int numBytes = imageWidth * imageHeight * 4 * sizeof(float);
    unsigned char *pixels = (unsigned char*)malloc(numBytes); // allocate image data into RAM
    glGetTexImage(GL_TEXTURE_2D , 0 , GL_RGBA , GL_FLOAT , pixels); // after this call the pixels seems wrong !

    free(pixels);


    4) The vertex shader:
    #version 430


    layout (location = 0) in vec3 in_Position;


    uniform mat4 mvp;


    flat out int vertexIndex;


    void main( void )
    {
    vec4 worldPos = vec4(in_Position, 1.0);
    gl_Position = mvp * worldPos;


    vertexIndex = gl_VertexID;
    }


    5) Fragment shader :
    #version 430

    uniform int imageWidth;
    uniform int imageHeight;

    in vec4 worldPos;

    //
    (I made sure vertexIndex variable has correct value by doing some color testing...)

    flat in int vertexIndex;


    // Output image
    layout (binding = 2, rgba8) writeonly uniform image2D image_out;


    void main( void )
    {
    imageStore(image_out, ivec2(vertexIndex % imageWidth, vertexIndex / imageHeight ) , vec4(1.,1.,1.,1.));
    }



    Am I forgetting something or making an obvious mistake here ?

    Thanks in advance !

  2. #2
    Newbie Newbie
    Join Date
    Jan 2014
    Posts
    2

    my current solution

    After a lot of hair pulling I got some working version. I am going to post the changes I made in case someone will find it helpful in the future. I ended up using FBOs, glReadPixels and memoryBarier() (in the shader), seems that made a big difference.

    1) create the FBO that will hold the texture that will be referenced by the image2D:

    int imageWidth = 1024;
    int imageHeight =1024;
    glGenFramebuffers(1, &glBakeFbo);
    glBindFramebuffer(GL_FRAMEBUFFER, glBakeFbo);


    glGenTextures(1, &glBakeTexture);
    glBindTexture(GL_TEXTURE_2D, glBakeTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageWidth , imageHeight , 0 , GL_RGBA, GL_UNSIGNED_BYTE , NULL);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, imageWidth, imageHeight);


    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glBakeTexture, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glBakeTexture, 0);


    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);


    2) The following is how I render to image:



    static const GLfloat white[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    static const GLenum attachments[] = { GL_COLOR_ATTACHMENT0 };

    // bind the FBO

    glBindFramebuffer(GL_FRAMEBUFFER, glBakeFbo);
    glDrawBuffers(1, attachments);
    glClearBufferfv(GL_COLOR, 0, white);
    glViewport(0, 0, imageWidth, imageHeight);

    glDisable(GL_DEPTH_TEST);
    glDepthMask( GL_FALSE );
    glDisable(GL_BLEND);


    shader->bind();
    shader->setUniformValue( "mvp", mvp );
    // the width of the image2D

    shader->setUniformValue("imageWidth", imageWidth);
    // the height of the image2D
    shader->setUniformValue("imageHeight", imageHeight);

    int id = shader->uniformLocation("image_out");
    // bind the 2D image.
    glBindImageTexture(id, glBakeTexture, 0, false, 0, GL_WRITE_ONLY, GL_RGBA8);

    // This was also important to add otherwise I got artifacts.
    glDrawBuffer(GL_NONE);

    glBindVertexArray( m_vao );


    // draw points
    glDrawArrays(GL_POINTS, 0, (GLsizei)numberOfPoints); // about 200,000 points


    glBindVertexArray(0);


    shader->release();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // release textures etc...





    3) read the image from FBO using "glReadPixels"


    glBindFramebuffer(GL_FRAMEBUFFER, glBakeFbo);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, glBakeFbo);


    glMemoryBarrier(GL_ALL_BARRIER_BITS);

    int numBytes = imageWidth * imageHeight * 4;
    unsigned char *pixels = (unsigned char*)malloc(numBytes); // allocate image data into RAM


    glReadPixels( 0, 0, imageWidth, imageHeight, GL_RGBA , GL_UNSIGNED_BYTE , pixels);
    free(pixels);



    4) The vertex shader:

    #version 430

    layout (location = 0) in vec3 in_Position;

    uniform mat4 mvp;

    flat out int vertexIndex;

    void main( void )
    {
    vec4 worldPos = vec4(in_Position, 1.0);
    gl_Position = mvp * worldPos;

    vertexIndex = gl_VertexID;
    }


    5) Fragment shader few changes here:

    #version 430

    uniform int imageWidth;
    uniform int imageHeight;

    in vec4 worldPos;

    flat in int vertexIndex;

    // Output image
    layout (binding = 2 , rgba8) writeonly uniform image2D image_out;

    void main( void )
    {
    memoryBarrier();
    imageStore(image_out, ivec2(vertexIndex % imageWidth, vertexIndex / imageHeight ) , vec4(1.,0.,0.,1.0));
    memoryBarrier();
    }



    Hope this helps anyone....
    I was expecting it to work in other ways but this is the only way I got it to work...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •