How to resolve integer multisampled texture attached to a framebuffer?

Hi,

I’m having some troubles in resolving integer multisampled textures.
I have a simple questions which although, don’t seem to get strong answers so far.

I already know that I can define integer multisample textures, I can attach them to a FBO and I can draw on them from a fragment shader. The question is, can they be resolved coherently? The problem occurs when I try to resolve the integer draw buffer onto a singlesample FBO, because the texture data I get is filled with zeroes.

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.
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;

With no multisampling everything works fine, and the integer texture is filled with correct data, but as soon as I call the glBlitFramebuffer() function the second color attachment (the integer texture) is zeroed.

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.

Hope someone can shed some light on it.

Current spec says that LINEAR blit of integer formats results in INVALID_OPERATION (because filtering of integer pixels is undefined.) This was not specified in earlier spec versions (and several implementations report MAX_INTEGER_SAMPLES as zero.)

So, if you’re attempting to do a LINEAR resolve, no, it shouldn’t work. If you do a NEAREST resolve it should work, but it will simply throw away all of the samples but one (in which case, why did you bother multisampling in the first place?)

[QUOTE=arekkusu;1254880]Current spec says that LINEAR blit of integer formats results in INVALID_OPERATION (because filtering of integer pixels is undefined.) This was not specified in earlier spec versions (and several implementations report MAX_INTEGER_SAMPLES as zero.)

So, if you’re attempting to do a LINEAR resolve, no, it shouldn’t work. If you do a NEAREST resolve it should work, but it will simply throw away all of the samples but one (in which case, why did you bother multisampling in the first place?)[/QUOTE]

That is not what the latest spec says on multisample resolve. When doing multisample resolve, filter is ignored. For integer attachments, a single sample is selected when multisample resolve is performed.

Hm, you are correct. Prior to GL4.4 the spec indicated integer formats would simply error with LINEAR. In 4.4 the new language clarifies multisample cases.

Too bad these issues weren’t more carefully specified back in 2006, when EXT_texture_integer, EXT_framebuffer_multisample, EXT_framebuffer_blit were contemporaneously authored.

I’m checking with glGetError() and/or the KHR_debug and I don’t get any error.

It doesn’t work for me on both cases. Although, it would make sense to me getting the nearest values on integer multisample textures, I can always blit the color with the LINEAR option and the indexes with the NEAREST. It would be anyway faster than repaint the entire scene again.

This is the code I use to blit the framebuffer before downloading textures on CPU.


// 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]);
}

My context version is 4.3 with nVidia drivers 326.80 and a GeForce660GTX on Windows 7.

So, I have resolved the mistery.

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 I want to read from two different color buffers, and writing with 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.

The correct way to blit my multisample MRT FBO is:


// 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);

  //
  // 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::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
}