views:

1988

answers:

3

I have an FBO object with a color and depth attachment which I render to and then read from using glReadPixels() and I'm trying to add to it multisampling support.
Instead of glRenderbufferStorage() I'm calling glRenderbufferStorageMultisampleEXT() for both the color attachment and the depth attachment. The frame buffer object seem to have been created successfully and is reported as complete.
After rendering I'm trying to read from it with glReadPixels(). When the number of samples is 0 i.e. multisampling disables it works perfectly and I get the image I want. when I set the number of samples to something else, say 4, the frame buffer is still constructed OK but glReadPixels() fails with an INVALID_OPERATION

Anyone have an idea what could be wrong here?

EDIT: The code of glReadPixels:

glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, ptr);

where ptr points to an array of width*height uints.

+5  A: 

I don't think you can read from a multisampled FBO with glReadPixels(). You need to blit from the multisampled FBO to a normal FBO, bind the normal FBO, and then read the pixels from the normal FBO.

Something like this:

// Bind the multisampled FBO for reading
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, my_multisample_fbo);
// Bind the normal FBO for drawing
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, my_fbo);
// Blit the multisampled FBO to the normal FBO
glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
//Bind the normal FBO for reading
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, my_fbo);
// Read the pixels!
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Steven Richards
"I don't think you can read from a multisampled" - Got any references for that?
shoosh
Here you go (scroll to the bottom): http://www.opengl.org/wiki/GL_EXT_framebuffer_multisample
Steven Richards
A: 

0..width * 0..height is effectively (width+1)*(height+1)

which is larger than width *height ?

In short shouldn't it be:

glReadPixels(0, 0, width-1, height-1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

Marco van de Voort
No. As mentioned in the question, this works perfectly without multisampling.
shoosh
A: 

You can't read the multisample buffer directly with glReadPixels since it would raise an GL_INVALID_OPERATION error. You need to blit to another surface so that the GPU can do a downsample. You could blit to the backbuffer, but there is the problem of the "pixel owner ship test". It is best to make another FBO. Let's assume you made another FBO and now you want blit. This requires GL_EXT_framebuffer_blit. Typically, when your driver supports GL_EXT_framebuffer_multisample, it also supports GL_EXT_framebuffer_blit, for example the nVidia Geforce 8 series.

 //Bind the MS FBO
 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, multisample_fboID);
 //Bind the standard FBO
 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fboID);
 //Let's say I want to copy the entire surface
 //Let's say I only want to copy the color buffer only
 //Let's say I don't need the GPU to do filtering since both surfaces have the same dimension
 glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
 //--------------------
 //Bind the standard FBO for reading
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
 glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, pixels);

Source: GL EXT framebuffer multisample

M. Jahedbozorgan