3

So, I'm using a multiple render target framebuffer, on which, the first color attachment is a color texture (RGBA8), while the second draw buffer (color attachment 1) is an index texture (R32UI).

gl::BindTexture(gl::TEXTURE_2D_MULTISAMPLE, m_Textures[eTEXTURE_COLORBUFFER]);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_BASE_LEVEL, 0);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_MAX_LEVEL, 0);
gl::TexImage2DMultisample(gl::TEXTURE_2D_MULTISAMPLE, m_Multisample,gl::RGBA8,width,height,gl::FALSE_);

gl::BindTexture(gl::TEXTURE_2D_MULTISAMPLE, m_Textures[eTEXTURE_CLASSBUFFER]);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_BASE_LEVEL, 0);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_MAX_LEVEL, 0);
gl::TexImage2DMultisample(gl::TEXTURE_2D_MULTISAMPLE, m_Multisample,gl::R32UI,width,height,gl::FALSE_);

Both textures are multisampled, and I would like to download them on CPU once the render has been completed. Although, when I blit the multisample FBO into a singlesample FBO, the index texture data returned is made of all zeros, while the color texture is correctly resolved.

// Resolve multisampling
if ( m_Multisample > 0 )
{
    gl::BindFramebuffer(gl::READ_FRAMEBUFFER, m_Framebuffers[eFBO_RENDERBUFFER]);
    gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, m_Framebuffers[eFBO_RESOLVEBUFFER]);
    gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims, m_FrameDims, 
        gl::COLOR_BUFFER_BIT, gl::NEAREST);

    gl::enum_t blit_error = gl::NO_ERROR_;
    blit_error = gl::GetError();
    if ( blit_error != gl::NO_ERROR_ )
    {
        throw framebuffer_error(string::format<128>(
            "BlitFramebuffer failed with error: %d",blit_error));
    }

    gl::BindFramebuffer(gl::READ_FRAMEBUFFER, m_Framebuffers[eFBO_RESOLVEBUFFER]);
}

I use the NEARST flag because, it actually seems that integer textures don't work with LINEAR interpolation.

The code I use to download the image is listed down here.

uint32_t* tex_data = new uint32_t[query.m_FrameDims*query.m_FrameDims];
memset(tex_data,0,sizeof(uint32_t)*query.m_FrameDims*query.m_FrameDims);
gl::BindTexture(gl::TEXTURE_2D,query.m_DestColorTexture);
{
    // Copy color texture
    gl::ReadBuffer(gl::COLOR_ATTACHMENT0);
    gl::ReadPixels(0,0,query.m_FrameDims,query.m_FrameDims,
        gl::RGBA,gl::UNSIGNED_BYTE,tex_data);
    gl::TexSubImage2D(gl::TEXTURE_2D,0,0,0,query.m_FrameDims,query.m_FrameDims,
        gl::RGBA,gl::UNSIGNED_BYTE,tex_data);
}

gl::BindTexture(gl::TEXTURE_2D,query.m_DestClassTexture);
{
    // Copy class texture
    gl::ReadBuffer(gl::COLOR_ATTACHMENT1);                      
    gl::ReadPixels(0,0,query.m_FrameDims,query.m_FrameDims,
            gl::RED_INTEGER,gl::UNSIGNED_INT,tex_data);
    gl::TexSubImage2D(gl::TEXTURE_2D,0,0,0,query.m_FrameDims,query.m_FrameDims,
            gl::RED_INTEGER,gl::UNSIGNED_INT,tex_data);
}

delete[] tex_data;

If I disable the multisample FBO, therefore avoiding to call the gl::BlitFramebuffer() function, everything works fine.

I don't see any docs that says that integer texture can note be multisampled, but even though, I'm not sure they make sense at all.

Any clue where I'm may mistaking?

3
  • Integer + multisampled? Doesn't sounds so reasonable, let's see if that is supported in the first place...Ok, seems supported, but what does GL_MAX_INTEGER_SAMPLES say (since it could be different from GL_MAX_SAMPLES)? Is it >1? Commented Sep 16, 2013 at 13:56
  • Uhm, good try, but my GTX 660 seems to be capable of 32 max integer samples :(. Thanks anyway. Commented Sep 16, 2013 at 14:19
  • 1
    Are you aware that in the code you pasted, you only blit from one of your two color buffer attachments? See my updated answer, it should solve your problem. Commented Sep 18, 2013 at 2:26

1 Answer 1

1

You can only read from a single color buffer at a time when you do a framebuffer blit; you can write to many draw buffers (technically up to GL_MAX_DRAW_BUFFERS at once). The problem here is that you want to read from two different color buffers, and you are trying to do it in a single blit.

OpenGL 4.4 Core Specification - 18.3. Copying Pixels - (pp. 483)

When the color buffer is transferred, values are taken from the read buffer of the read framebuffer and written to each of the draw buffers of the draw framebuffer.


Your code indicates to me that you forgot to actually do a second blit for the second color attachment, and that is why it comes up empty.

To correct this, I would expect to see something like:

// Resolve multisampling
if ( m_Multisample > 0 )
{
  //
  // Do the first resolve (COLOR_ATTACHMENT0)
  //
  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RENDERBUFFER]);
  gl::ReadBuffer     (gl::COLOR_ATTACHMENT0); // Read:  Attachment 0 (MSAA)

  gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
  gl::DrawBuffer     (gl::COLOR_ATTACHMENT0); // Write: Attachment 0 (Resolve)

  gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims,
      m_FrameDims, gl::COLOR_BUFFER_BIT, gl::NEAREST);

  gl::enum_t blit_error = gl::NO_ERROR_;
  blit_error = gl::GetError();
  if ( blit_error != gl::NO_ERROR_ )
  {
      throw framebuffer_error(string::format<128>(
          "BlitFramebuffer failed with error: %d",blit_error));
  }

  //
  // Do the second resolve (COLOR_ATTACHMENT1)
  //
  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RENDERBUFFER]);
  gl::ReadBuffer     (gl::COLOR_ATTACHMENT1); // Read:  Attachment 1 (MSAA)

  gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
  gl::DrawBuffer     (gl::COLOR_ATTACHMENT1); // Write: Attachment 1 (Resolve)

  gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims,
      m_FrameDims, gl::COLOR_BUFFER_BIT, gl::NEAREST);

  gl::enum_t blit_error = gl::NO_ERROR_;
  blit_error = gl::GetError();
  if ( blit_error != gl::NO_ERROR_ )
  {
      throw framebuffer_error(string::format<128>(
          "BlitFramebuffer failed with error: %d",blit_error));
  }

  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
}

This assumes that the textures / renderbuffers you want to blit from/to have the same attachment point. If not, you can adjust gl::ReadBuffer (...) and gl::DrawBuffer (...) accordingly.

Sign up to request clarification or add additional context in comments.

2 Comments

@AndomM.Coleman It makes perfectly sense, although, not so intuitive. I'm going to try this out and let you know. Thank you!
@AndomM.Coleman Indeed it was the problem. Thank you very much! This probably a bit less efficient than resolving everything with one call, but as you highlighted this way gives you more flexiblility.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.