c++openglfbodepth-buffermsaa

OpenGL how can I attach a depth buffer to a framebuffer using a multisampled 2d texture


How can I attach a depth-buffer to my framebufferobject when I use GL_TEXTURE_2D_MULTISAMPLE. glCheckFramebufferStatus(msaa_fbo) from the code below returns 0. From the documentation this seems to mean that msaa_fba is not a framebuffer, but it is created from glGenFramebuffers(1, &msaa_fbo);.

Additionally, if an error occurs, zero is returned. GL_INVALID_ENUM is generated if target is not GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER or GL_FRAMEBUFFER.

The error is 1280, which I think means GL_INVALID_ENUM.

If i remove the depth buffer attachment the program runs and renders (although without depth testing). The error is still present when it runs then. With the depth attachment included there is an error (1286) after every frame, which is INVALID_FRAMEBUFFER. I don't know how to continue from here. Some examples I've looked at do somewhat the same but seem to work.

glGenTextures(1, &render_target_texture);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, render_target_texture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, NUM_SAMPLES, GL_RGBA8, width, height, false);

glGenFramebuffers(1, &msaa_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, msaa_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, render_target_texture, 0);

glGenRenderbuffers(1, &depth_render_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, depth_render_buffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, NUM_SAMPLES, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_render_buffer);

GLenum status = glCheckFramebufferStatus(msaa_fbo);

Most of the code is from this.

EDIT

The status check was wrong, it should've been GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);. Now there is no error when I don't include the depth. When I include depth I get this error now: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE.

EDIT 2

Documentation claims that this happens when GL_TEXTURE_SAMPLES and GL_RENDERBUFFER:SAMPLES don't match.

GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE is returned if the value of GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers; if the value of GL_TEXTURE_SAMPLES is the not same for all attached textures; or, if the attached images are a mix of renderbuffers and textures, the value of GL_RENDERBUFFER_SAMPLES does not match the value of GL_TEXTURE_SAMPLES.

But they do!

I've tested them like this:

std::cout << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE" << std::endl;
GLsizei gts, grs;
glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &gts);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &grs);
std::cout << "GL_TEXTURE_SAMPLES: " << gts << std::endl;
std::cout << "GL_RENDERBUFFER_SAMPLES: " << grs << std::endl;

Output is:

GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
GL_TEXTURE_SAMPLES: 8
GL_RENDERBUFFER_SAMPLES: 8

EDIT 3

Worked around this by using two textures instead of a texture and a renderbuffer like this:

glGenFramebuffers(1, &msaa_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, msaa_fbo);

glGenTextures(1, &render_texture);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, render_texture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, NUM_SAMPLES, GL_RGBA8, width, height, false);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, render_texture, 0);

glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, depth_texture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, NUM_SAMPLES, GL_DEPTH_COMPONENT, width, height, false);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depth_texture, 0);

I'm am still interested in what was wrong with the original implementation, so question is still standing.


Solution

  • You need to used fixed sample locations for the texture if you mix it with renderbuffers. From the spec, in section "Framebuffer Completeness":

    The value of TEXTURE_FIXED_SAMPLE_LOCATIONS is the same for all attached textures; and, if the attached images are a mix of renderbuffers and textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.

    {FRAMEBUFFER_INCOMPLETE_MULTISAMPLE}

    To avoid this error condition, you the call for setting up the texture storage needs to be changed to:

    glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
        NUM_SAMPLES, GL_RGBA8, width, height, GL_TRUE);