PDA

View Full Version : Accessing GL_DEPTH24_STENCIL8 framebuffer depth



Schnulla
11-06-2011, 08:09 AM
Hello!

I have rendered my scene into a FBO that contains a
GL_DEPTH24_STENCIL8 framebuffer. In a post processing
step I want to bind this depth framebuffer to a pixel
shader and read the depth values. How can I read the
24 bit depth part from this "packed" framebuffer?
Can I just attach a texture instead like I do for the
color framebuffer? But I guess this does not work with
the packed format, right?

Help is really appreciated!

Thanks!

Dark Photon
11-06-2011, 10:19 AM
I have rendered my scene into a FBO that contains a GL_DEPTH24_STENCIL8 framebuffer. In a post processing step I want to bind this depth framebuffer to a pixel shader and read the depth values. How can I read the
24 bit depth part from this "packed" framebuffer?

1) Ensure that the GL_DEPTH24_STENCIL8 depth/stencil render target you create is a texture.

2) On the 2nd pass, just bind it to a texture unit so the shader can access it. You have two options for accessing this depth texture: a) reading the 0..1 depth values directly out of the texture, or b) having the hardware do a depth comparison as part of the texture lookup and return to you a 0..1 "occlusion" result (if this is a shadow map).

It sounds like you want a) (read the 0..1 depth values directly). So just use a sampler2D type in the shader:

uniform sampler2D Depth_map;

and don't enable hardware depth comparisons on that texture (GL_TEXTURE_COMPARE_MODE). No depth comparisons is the default.

You can of course use a sampler2DArray instead if you need an array of 2D depth maps, or samplerCube if you need a cube map depth map, or samplerCubeArray if you need an array of cube map depth maps.


Can I just attach a texture instead like I do for the color framebuffer? But I guess this does not work with the packed format, right?
It should work just the same (as would DEPTH_COMPONENT24 and friends). Just attach it like any other texture and forget the fact that it's special packed format. It just works. OpenGL hides this from you.

Note that if the depth map you're managing is a shadow map AND if you want the hardware to do the depth comparisons for you (possibly with PCF filtering), then instead of using the above sampler types, use one of: sampler2DShadow, sampler2DArrayShadow, samplerCubeShadow, or samplerCubeArrayShadow, respectively in the shader, and enable GL_TEXTURE_COMPARE_MODE on the texture. With this, setting a NEAREST MIN/MAG filter on the texture means point-sampled shadow map comparisons, whereas LINEAR MIN/MAG filter means PCF-filtered shadow map comparisons.

Schnulla
11-06-2011, 11:29 AM
Thanks a bunch for the detailed answer! I always appreciate your commitment on this board :)

So I guess I can just call...

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, MyTextureHandle, 0);
...when setting up the FBO.

Just two final questions:

1. Can I just use ".x" to access the depth value in the shader? For the sake of completeness: is it also possible to access the 8 bit stencil value in the same manner (I guess not)?

2. For MultiSampling (MS) can I (as usual) create a MS FBO and a non-MS FBO and then blit the MS FBO to the other FBO when I need to access the depth texture? So I would have a MultiSampled depth renderbuffer which is downsampled into a depth texture. I think I have to do that in order to access the depth values although I am not sure if the downsampling could produce strange depth values.

Thanks!

Dark Photon
11-06-2011, 12:56 PM
So I guess I can just call...

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, MyTextureHandle, 0);
...when setting up the FBO.
Yep.


1. Can I just use ".x" to access the depth value in the shader? For the sake of completeness: is it also possible to access the 8 bit stencil value in the same manner (I guess not)?
Re .x, yes, I think so. In early OpenGL, there was a DEPTH_TEXTURE_MODE (for example:)

glTexParameteri( GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE , GL_INTENSITY );

which you could use to tell OpenGL how you wanted the texture sampling to populate a vec4 with the retrieved value:

GL_INTENSITY = dddd
GL_LUMINANCE = ddd1
GL_ALPHA = 000d
GL_RED = d001

but in GLSL 1.3 or so, I believe they nuked that and the default for this became GL_LUMINANCE. So if you specify LUMINANCE for this or just use GLSL 1.3+, then I think you can grab the value from .r, .g, or .b (.x, .y, or .z).


2. For MultiSampling (MS) can I (as usual) create a MS FBO and a non-MS FBO and then blit the MS FBO to the other FBO when I need to access the depth texture?
First, a subtlety. An FBO itself isn't inherently multisampled or not. It's a function the render targets that you attach to the FBO.

But yes, it's actually even better than what you suggest above. You can either: create MSAA depth texture or renderbuffer to render to, bind to your draw FBO, draw to it, create 1xAA depth texture, bind to another FBO, blit between FBOs to downsample, and then bind the downsampled depth texture to a texture unit to read in a shaders in a subsequent pass (though why even render MSAA if you only need 1xAA output?), OR create MSAA depth texture to render to, bind to your draw FBO, draw to it, and bind the MSAA depth texture to a texture unit to read in shaders in a subsequent pass.Re the first option, I don't know that it's specified how a downsample of the depth buffer actually works, or whether it is always supported, so you might check the spec.

And re the second option, just use sampler2DMS as the sampler type in the shader, and use:

texelFetch( Depth_map, texcoord, sample )

to fetch the depth texture value for the MSAA sample number "sample".


...although I am not sure if the downsampling could produce strange depth values.
Yeah, I'm wondering about that too. I'll check the spec here in a minute.

Dark Photon
11-06-2011, 01:06 PM
...although I am not sure if the downsampling could produce strange depth values.
Yeah, I'm wondering about that too. I'll check the spec here in a minute.
Re downsampling depth, the 4.2 spec has this to say:


...if mask includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, and filter is not NEAREST, no copy is
performed and an INVALID_OPERATION error is generated. ... Calling BlitFramebuffer will result in an INVALID_OPERATION error if mask includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, and the source and destination depth and stencil buffer formats do not match.
So it seems to suggest that as long as your depth buffer format matches AND you specify NEAREST filtering, then the Blit is not explicitly invalid. Though I don't see where it actually specifies the algorithm to be used for a depth downsample (e.g. min(all_samples)).

Schnulla
11-06-2011, 02:29 PM
or just use GLSL 1.3+, then I think you can grab the value from .r, .g, or .b (.x, .y, or .z).
Alright, thanks!


create MSAA depth texture
Ahh you know what, till today I always used this downsampling approach cause glTexImage2DMultisample was not available in the past. Now that you mentioned "MSAA texture" I found this glTexImage2DMultisample which is available since GL version 3.2.


(though why even render MSAA if you only need 1xAA output?)

I need MSAA for the normal scene rendering and I think all renderbuffers attached to a FBO must be MultiSampled. So IMHO I cannot mix MS renderbuffers with non-MS renderbuffers.


And re the second option, just use sampler2DMS as the sampler type in the shader, and use
Now that I know glTexImage2DMultisample exists that saves of course the downsampling step. I guess sampler2DMS also works when the sampler is actually not MultiSampled (otherwise I would need to write two shader versions)?


Man you already helped my a lot! Thanks a bunch!

Dark Photon
11-06-2011, 07:45 PM
I guess sampler2DMS also works when the sampler is actually not MultiSampled (otherwise I would need to write two shader versions)?
Really? That would be surprising to me. Operative question is I think can you call glTexImage2DMultisample with a samples count of "1". I wouldn't think you could provide a glTexImage2D created texture to a sampler2DMS though...

Oh, and it's not really writing too different shader versions. You can just #ifdef one shader (I've done this). Something like this:

#if NUM_SAMPLES == 1
# define SAMPLER_TYPE sampler2D
#else
# define SAMPLER_TYPE sampler2DMS
#endif

uniform SAMPLER_TYPE Depth_tex;


Then where you actually access them, use:

texelFetch( Depth_tex, texcoord, sample )

In the multisample case, sample will be 0..n-1. In the single-sample depth case, sample will always be 0. In this case, the 3rd arg is actually the MIP level, but you wanted to access MIP level 0 anyway, so it just works.

All you have to do is prepend a "#define NUM_SAMPLES 4" or whatever to the front of the shader, and it just works.

Schnulla
11-07-2011, 12:32 PM
That is an interesting trick using the LOD part :)
I guess I'll try something like this on the weekend.

So when I lookup the depth value from the MS depth texture,
I guess it does not matter which sample I take? I need the
depth value to clear some pixels in the color buffer which
belong to a certain depth range.

Schnulla
11-07-2011, 03:40 PM
Ah and another question, I just removed my legacy code to
downsample a MSAA FBO and noticed that I maybe still need it
for MSAA cubemaps. glTexImage2DMultisample does not work
for GL_TEXTURE_CUBE_MAP_*_*.

So what I did in the past is render to a MSAA FBO and then
downsample to a FBO which uses a cube map texture as color
attachment. This way I was able to create MSAA cube map
textures/sides.

Dark Photon
11-07-2011, 03:49 PM
So when I lookup the depth value from the MS depth texture, I guess it does not matter which sample I take?
Depends on your needs. You may just want to grab them all and do your own reduction in the shader.

Schnulla
11-08-2011, 01:49 PM
Hmm I just want to know if the current fragment is in some special
depth range. Actually I am not sure how this should be done when
dealing with multiple samples :p

For the MSAA cube map, I guess I still need the downsampling
approach?