glReadPixels fails to read the content of the color buffer

here is what my following code does:

  1. create an FBO
  2. create a 2x2 RGBA texture and attach it as the color buffer of the FBO
  3. set clear color to 0.0, 1.0, 0.0, 1.0 and clear the color buffer(the texture in this case)
  4. read the color buffer of the FBO using glReadPixels

I expect the content of each pixel would be: 0, 255, 0,255,
but it’s not, instead, they look like some random numbers,
what am I doing wrong?

P.S. I use opengl es 2.0


        GLuint tex;
        glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_2D, tex);
        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_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        
        GLuint fboID;
        glGenFramebuffers(1, &fboID);
        glBindFramebuffer(GL_FRAMEBUFFER, fboID);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
                
        glClearColor(0.0, 1.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
        GLubyte* pixels = (GLubyte*) malloc(2 * 2 * 4 * sizeof(GLubyte));
        glReadPixels(0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

First, check for GL errors via glGetError(). I suspect you might be throwing some.

(Edit: This is wrong – ignore–> ) [strikeout]PACK is for moving data “to” the GPU. UNPACK is for moving data “from” the GPU. You need to use UNPACK:[/strikeout]

Also you should be checking for framebuffer completeness after configuring it before you start using it.

Would call:

glReadBuffer( GL_COLOR_ATTACHMENT0 );

before glReadPixels so it knows which attachment to read from the active read framebuffer (which you’ve set via glBindFramebuffer with the GL_FRAMEBUFFER target).

Also check the glClear() man page. It honors the pixel ownership test, the scissor test, dithering, and the buffer writemasks. So make sure you have those set properly. In particular, pass 4 GL_TRUEs to glColorMask for the color buffer writemask.

Also, I would be explicit about what internal format your texture should have. GL_RGBA8 instead of GL_RGBA for the 3rd arg to glTexImage2D() would be preferable.

No, UNPACK is for moving data to the GPU. You unpack data to OpenGL.
If you are going to get something from OpenGL, then GL packs it for you.

I have checked it multiple times, I delete them just to keep my code clean,
there are no errors.

PACK is for moving data “to” the GPU. UNPACK is for moving data “from” the GPU. You need to use UNPACK:

No offense, sir, but I think it’s the other way around.(unpack: cpu -> gpu, pack: gpu->cpu)

Also you should be checking for framebuffer completeness after configuring it before you start using it.

I have done that too, still, the framebuffer is complete.

Would call:

glReadBuffer( GL_COLOR_ATTACHMENT0 );

before glReadPixels so it knows which attachment to read from the active read framebuffer (which you’ve set via glBindFramebuffer with the GL_FRAMEBUFFER target).

glReadBuffer doesn’t exist in opengl es, glReadPixels automatically read the currently
active framebuffer.

Also check the glClear() man page. It honors the pixel ownership test, the scissor test, dithering, and the buffer writemasks. So make sure you have those set properly. In particular, pass 4 GL_TRUEs to glColorMask for the color buffer writemask.

Tried and no luck.

Also, I would be explicit about what internal format your texture should have. GL_RGBA8 instead of GL_RGBA for the 3rd arg to glTexImage2D() would be preferable.

GL_RGBA8 is not declared in opengl es.

Thank you so much for replying,
hope someone could shed some light on this.

I would initialize the texture to some known values (different than the clear values) at creation time.

I would also initialize the pixels array to some other distinct known value.

After the read pixels is done you may inspect the contents of the pixels array and maybe get a better indication of what is going wrong.

http://www.khronos.org/message_boards/viewforum.php?f=19

OpenGL ES forum

[QUOTE=V-man;1238819]No, UNPACK is for moving data to the GPU. You unpack data to OpenGL.
If you are going to get something from OpenGL, then GL packs it for you.[/QUOTE]
Thanks for the correction! Man, not sure where I got turned around with that one.

So conceptually client memory is “packed” and GPU/driver memory is “unpacked”. Sorry about that.

Unless you use pack/unpack buffers, in which case its all gpu side.
I just gave up on remembering which is which, just check every time i need it …

I still hasn’t found any solution to this problem,
it makes me wonder,
is it possible that this operation is not supported on my implementation?

If GLES2 has GLUT support, try the attached. Produces the value you’d expect on GL. If not, try a short test program with nothing else besides the above code and minimal context init. Failing that, I’d post your question in a GLES2 forum.


#include <stdio.h>
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <GL/glut.h>

/*****************************************************************************/

void checkGLError( const char hdr[] )
{
  int err = glGetError();
  if( err )
  {
    fprintf(stderr, "ERROR %s: %s
", hdr, gluErrorString(err));
    exit(1);
  }
}

void doit()
{
  GLuint tex;
  glGenTextures(1, &tex);
  glBindTexture(GL_TEXTURE_2D, tex);
  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_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

  GLuint fboID;
  glGenFramebuffers(1, &fboID);
  glBindFramebuffer(GL_FRAMEBUFFER, fboID);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);

  glClearColor(0.0, 1.0, 0.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT);

  glPixelStorei(GL_PACK_ALIGNMENT, 1);
  GLubyte* pixels = (GLubyte*) malloc(2 * 2 * 4 * sizeof(GLubyte));
  glReadPixels(0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

  GLubyte *p = pixels;
  for ( int i = 0; i < 4; i++ )
  {
    printf( "%d %d %d %d
", p[0], p[1], p[2], p[3] );
    p += 4;
  }
}

int main( int argc, char *argv[] )
{
  glutInit( &argc, argv );
  glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH );
  glutCreateWindow( "window title" );

  checkGLError( "Before doit()" );
  doit();
  checkGLError( "After doit()" );
  return 0;
}