howto disable multisampling for stencil buffer?

Hello,

I have 4x multisampling enabled in my application
(WGL_SAMPLE_BUFFERS_ARB == true and WGL_SAMPLES_ARB == 4).

Unfortunately this also affects render operations
to the stencil buffer and slows them down.

I tried to disable multisampling temporary for the
stencil operations using…

glDisable(GL_MULTISAMPLE_EXT);

…but it does not seem to work.

How can I get rid of multisampling for stencil operations?

Thanks!

Use an FBO to render to a single-sample texture or renderbuffer (with depth+stencil support). Blit the result wherever you need it.

Also keep in mind: when you render with multisampling on the system framebuffer, you:

  1. allocate a multisample draw surface (happens when window created),
  2. perform multisample rasterization, and
  3. the GPU performs GPU multisample downsample filtering on the result at the end of drawing.

Once you have #1 set up on the system framebuffer, calling glDisable( GL_MULTISAMPLE ) only disables #2. You’re stuck with #1 and #3. If you want something else, flip over to rendering on a single-sample FBO.

#1 implies you have a framebuffer allocated with multisample depth, stencil, and color. That’s just the way it is.

Here are the DEPTH+STENCIL formats out in the wild now that you can target your FBO depth/stencil attachments to: GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8.

Thanks for your reply.

Currently I render my scene to the normal window (double) buffer.

Then I render stuff to the stencil buffer part of this window
with depth test enabled (so the depth values of the scene
are required for my stencil stuff).

If I render my stencil stuff to the FBO I also need to
render the whole scene to this FBO to get the same
depth values required for my stencil stuff, right?

But since the scene should be rendered with multisampling
how can I manage this? I somehow must have a framebuffer
first to render the scene with multisampling and then
a second framebuffer without multisampling for the stencil
stuff which makes use of the first framebuffer’s depth buffer?

Or is it possible to tell the FBO that it should use
the depth buffer from my normal window?

Thanks again :slight_smile:

glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0 );

Will copy just the system depth buffer (possibly multisampled) to a single-sample texture, downsampling if needed, and converting formats as required. You can then bind this texture as an FBO’s depth buffer attachment.

If you can specify GL_DEPTH_COMPONENT to copy just the depth buffer, I’ll bet you can specify GL_DEPTH_STENCIL to copy both the depth and stencil buffers to a depth+stencil combined texture format such as GL_DEPTH24_STENCIL8 or GL_DEPTH32F_STENCIL8. Then bind this resulting texture as both the depth and stencil attachments of the FBO.

Failing that, use the first technique to copy the stencil buffer into a texture and bind that as the FBO depth attachment, and then create a DEPTH24_STENCIL8 texture or renderbuffer and bind to the FBOs stencil attachment. There may be other formats the hardware will allow you to use as stencil only, but I’ve never read anything about that.

I’m not sure I fully understood the question, but sounds like glBlitFramebufferEXT() could be of use:

http://www.opengl.org/registry/specs/EXT/framebuffer_blit.txt

@Dark Photon:
I think that goes in the direction of what I try to do.
Thanks for the hints.

@TomFlynn:

I’ll try to summarize what I want to do:

  1. I don’t want to draw the scene two times.
  2. The scene should be rendered with multisampling.
  3. I want to render stuff into a stencil buffer, but the stencil buffer needs to be combined with the depth buffer
    values that where generated during the scene rendering.
    And the stencil buffer should not be multisampled.

So maybe it somehow works by attaching/detaching
different renderbuffers to/from FBOs. But I guess
I cannot just render the scene to a multisampled
FBO and then attach the depth renderbuffer of
this FBO to another non-multisampled FBO used
as target for my stencil operations. I somewhere
read that it is not possible to mix multisampled
and non-multisampled renderbuffers in one FBO.

But I guess I should just follow Dark Photon’s description :slight_smile:

I found an interesting blog post.

I think this should work:

// multi sampled color buffer
glGenRenderbuffersEXT(1, &colorBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorBuffer);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_RGBA8, width, height);

// multi sampled depth buffer
glGenRenderbuffersEXT(1, &depthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_DEPTH_COMPONENT, width, height);

// create fbo for multi sampled content and attach depth and color buffers to it
glGenFramebuffersEXT(1, &mfbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mfbo);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, colorBuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBuffer);

// create texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
// set your texture parameters here if required ...

// create final fbo and attach texture to it
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0);

...

// rendering procedure
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mfbo);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, width, height);
// ... draw ...
glPopAttrib();

// copy multisampled color buffer to non-multisampled buffer
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mfbo);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo);
glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

// you have to unbind all fbos before you can render to the main window
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

So basically I create two FBOs, one multisampled and
the other not. And when I have rendered my scene to
the multisampled one I copy only the depth part to
the non-multisampled one.

Then I can do my stencil operations in this non-multisampled
one that now has the depth values from the previous one.

This should work, right? :slight_smile:
What do you think about this solution?

I made some progress, I created two FBO with packed depth stencil.
The first is multisampled, the second not.

I render the scene to the multisampled one and then blit
the depth-stencil buffer to the singlesampled one.
Then I can do my stencil stuff without multisampling
(it is much faster now).

The only problem is that I cannot just blit the singlesampled
depth-stencil buffer back to the multisampled FBO =/