glReadPixels() sets GL_INVALID_OPERATION error

c++, fbo, opengl

Solution

Your problem is the format parameter. For a texture that has a one-channel integer internal format the correct parameter isn't `GL_RED`, but `GL_RED_INTEGER`:

glReadPixels(pos.x(), resolution.y() - pos.y(), 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &result);

Look at the OpenGL documentation wiki (emphasis mine):

...

format

Specifies the format of the pixel data. For transfers of depth, stencil, or depth/stencil data, you must use GL_DEPTH_COMPONENT, GL_STENCIL_INDEX, or GL_DEPTH_STENCIL, where appropriate. For transfers of normalized integer or floating-point color image data, you must use one of the following: GL_RED, GL_GREEN, GL_BLUE, GL_RG, GL_RGB, GL_BGR, GL_RGBA, and GL_BGRA. For transfers of non-normalized integer data, you must use one of the following: GL_RED_INTEGER, GL_GREEN_INTEGER, GL_BLUE_INTEGER, GL_RG_INTEGER, GL_RGB_INTEGER, GL_BGR_INTEGER, GL_RGBA_INTEGER, and GL_BGRA_INTEGER. Even if no actual pixel transfer is made (data​ is NULL and no buffer is bound to GL_PIXEL_UNPACK_BUFFER), you must set this parameter correctly for the internal format of the destination image.

...

Note: the official reference page is incomplete/wrong.

Problem

I'm trying to implement color picking with FBO. I have multisampled FBO (fbo[0]) which I use to render the scene and I have non multisampled FBO (fbo[1]) which I use for color picking. The problem is: when I try to read pixel data from fbo[1] everything goes well until glReadPixels call which sets GL_INVALID_OPERATION flag. I've checked the manual and can't find the reason why. The code to create FBO: ``` glBindRenderbuffer(GL_RENDERBUFFER, rbo[0]); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, resolution[0], resolution[1]); glBindRenderbuffer(GL_RENDERBUFFER, rbo[1]); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_DEPTH24_STENCIL8, resolution[0], resolution[1]); glBindRenderbuffer(GL_RENDERBUFFER, rbo[2]); glRenderbufferStorage(GL_RENDERBUFFER, GL_R32UI, resolution[0], resolution[1]); glBindRenderbuffer(GL_RENDERBUFFER, rbo[3]); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, resolution[0], resolution[1]); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo[3]); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[2]); OGLChecker::checkFBO(GL_DRAW_FRAMEBUFFER); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[0]); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo[1]); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[0]); OGLChecker::checkFBO(GL_DRAW_FRAMEBUFFER); ``` My checker stays silent so the FBOs are complete. Next the picking code ``` glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // bla, bla, bla // do the rendering unsigned int result; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]); int sb; glReadBuffer(GL_COLOR_ATTACHMENT0); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glGetIntegerv(GL_SAMPLE_BUFFERS, &sb); // glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); OGLChecker::getGlError(); std::cerr << "Sample buffers " << sb << std::endl; glReadPixels(pos.x(), resolution.y() - pos.y(), 1, 1, GL_RED, GL_UNSIGNED_INT, &result); OGLChecker::getGlError(); return result; ``` the output: ``` Sample buffers 0 OpenGL Error : Invalid Operation ``` The interesting fact that if I uncomment glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); then no error happens and pixels are read from screen (but I don't need this). What may be wrong here?

Original source