I'm having some very strange behaviour from my multiple-render-target code, and have started to wonder whether I'm catastrophically misunderstanding the way that this is supposed to work.
I'm running in a version 2.1 context. Here's the core bit of render setup code I'm executing:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers(2,buffers);
My shader then writes out color data to gl_FragColor[0]
and glFragColor[1]
.
This is essentially the same situation as was discussed in this question. However, when I run this on OS X, my shader only outputs to the first render target. OpenGL throws no errors, either during the construction of the FBO with two color attachments, or at any point during the rendering process.
When I examine what's going on via the OSX 'OpenGL Profiler' "trace" view, it shows the driver's side of this code execution as being:
2.86 µs glBindFramebufferEXT(GL_FRAMEBUFFER, 1);
3.48 µs glDrawBuffersARB(2, {GL_COLOR_ATTACHMENT0, GL_ZERO});
Which perhaps explains why nothing was being written to GL_COLOR_ATTACHMENT1
; it seems to be being replaced by GL_ZERO
in the call to glDrawBuffers
!
If I switch the order of the buffers in the buffers[]
array to be GL_COLOR_ATTACHMENT1_EXT
first and then GL_COLOR_ATTACHMENT0_EXT
, then my shader only writes into GL_COLOR_ATTACHMENT1_EXT
, and GL_COLOR_ATTACHMENT0_EXT
appears to be replaced with GL_ZERO
.
Here's where it gets weird. If I use the code:
GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers(3, buffers);
Then the statistics view shows this:
0.46 µs glDrawBuffersARB(3, {GL_COLOR_ATTACHMENT0, GL_ZERO, GL_COLOR_ATTACHMENT1});
OpenGL still throws no errors, and my shader successfully writes out data to both color attachments, even though it's writing to gl_FragColor[0]
and gl_FragColor[1]
.
So even though my program is now working, it seems to me like this shouldn't work. And I was curious to see how far I could push this, hoping that pushing OpenGL to an eventual failure would be educational. So I tried compiling with this code:
GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers(4, buffers);
When running that, the OpenGL Profiler "trace" view shows this as being executed:
4.26 µs glDrawBuffersARB(4, {GL_COLOR_ATTACHMENT0, GL_ZERO, GL_COLOR_ATTACHMENT1, GL_ZERO});
And now OpenGL is throwing "invalid framebuffer operations" all over the place, but my shader is still successfully writing color data to both color attachment points.
Does all this make sense to anyone? Have I catastrophically misunderstood the way that glDrawBuffers
is supposed to be called?
According to the OpenGL Profiler's "Resources" view, my framebuffer (number 1) looks fine; it does have two color attachments attached, as expected.
Attached Objects:
{
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT0
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_TEXTURE
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 1
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 0
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 0
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 0
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT1
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_TEXTURE
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 2
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 0
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 0
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 0
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT2
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_NONE
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT3
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_NONE
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT4
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_NONE
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT5
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_NONE
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT6
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_NONE
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_COLOR_ATTACHMENT7
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_NONE
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_DEPTH_ATTACHMENT
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_TEXTURE
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 3
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 0
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 0
GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 0
}
{
GL_FRAMEBUFFER_ATTACHMENT: GL_STENCIL_ATTACHMENT
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: GL_NONE
}
}