Вопрос

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?

Это было полезно?

Решение

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top