5

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
  }
}
Community
  • 1
  • 1
Trevor Powell
  • 1,154
  • 9
  • 20

1 Answers1

6

...and after banging my head against this for almost a week, I figured it out just five minutes after finally posting the question on StackOverflow. Posting my solution since it seems to be a header problem that's likely to affect other OSX folks.

For whatever reason, on my 64-bit OSX build, GLenum is defined as an 8-byte integer type, while the OpenGL drivers actually want 32-bit values in the array being passed to glDrawBuffers. If I rewrite the code as:

uint32_t buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers(2,(GLenum*)buffers);  

Then everything works as expected. (The placement of the GL_ZERO entries was the hint that eventually led me to this answer)

Trevor Powell
  • 1,154
  • 9
  • 20
  • This indicates that either your opengl library and header files do not match, or, most likely, that the opengl library you use was compiled for a 32-bit platform. Either of these could pose extra problems so you should take a look into that. `GLEnum` is a typedef, usually for `unsigned int` – KillianDS Jul 29 '12 at 12:40
  • Yeah. I'm getting GLenum from GLEW, where it's defined as an unsigned int (and which will, in fact, be a 64-bit integer in a 64-bit build). It appears to be defined the same way in the regular OpenGL.framework which ships with OS X, so presumably same problem there? – Trevor Powell Jul 29 '12 at 12:45
  • ...And upgrading to the latest version of GLEW eliminated the problem entirely. – Trevor Powell Jul 29 '12 at 13:54
  • Please stop mixing the EXT_FBO and ARB_FBO extensions and enumerators. – Nicol Bolas Jul 29 '12 at 21:03
  • Whoops, typo in my original code snippet. The "ARB" versions were only showing up in Apple's driver-side debugging tool, not in the code I had written; I'm assuming that their OpenGL.framework is doing some conversions behind the scenes. – Trevor Powell Jul 30 '12 at 04:45