From 7f31255eb2676aa88c10eb5e92a708642b9a6808 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Wed, 22 Mar 2006 18:46:18 +0000 Subject: [PATCH] Support for separate depth and stencil renderbuffers. If the user creates several stencil renderbuffers and several depth renderbuffers, any combination can get bound to a framebuffer object. Since the hardware only supports combined depth+stencil buffers we need to do some shuffling of buffer data to make things work. This code deals with that. Now fbotexture.c runs in hardware without the -ds flag. Probably quite a few loose ends, clean-ups remain... --- src/mesa/drivers/dri/i915/Makefile | 1 + src/mesa/drivers/dri/i915/intel_buffers.c | 24 +- .../drivers/dri/i915/intel_depthstencil.c | 269 ++++++++++++++++++ .../drivers/dri/i915/intel_depthstencil.h | 14 + src/mesa/drivers/dri/i915/intel_fbo.c | 26 +- src/mesa/drivers/dri/i915/intel_fbo.h | 3 + 6 files changed, 319 insertions(+), 18 deletions(-) create mode 100644 src/mesa/drivers/dri/i915/intel_depthstencil.c create mode 100644 src/mesa/drivers/dri/i915/intel_depthstencil.h diff --git a/src/mesa/drivers/dri/i915/Makefile b/src/mesa/drivers/dri/i915/Makefile index 714c7885616..ac4aeb21ad9 100644 --- a/src/mesa/drivers/dri/i915/Makefile +++ b/src/mesa/drivers/dri/i915/Makefile @@ -47,6 +47,7 @@ DRIVER_SOURCES = \ intel_state.c \ intel_tris.c \ intel_fbo.c \ + intel_depthstencil.c \ intel_bufmgr.c diff --git a/src/mesa/drivers/dri/i915/intel_buffers.c b/src/mesa/drivers/dri/i915/intel_buffers.c index 6300d2cacb6..f9fce9977b6 100644 --- a/src/mesa/drivers/dri/i915/intel_buffers.c +++ b/src/mesa/drivers/dri/i915/intel_buffers.c @@ -29,6 +29,7 @@ #include "intel_context.h" #include "intel_blit.h" #include "intel_buffers.h" +#include "intel_depthstencil.h" #include "intel_fbo.h" #include "intel_tris.h" #include "intel_regions.h" @@ -516,8 +517,8 @@ void intel_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb) { struct intel_context *intel = intel_context(ctx); - struct intel_region *colorRegion, *depthRegion; - struct intel_renderbuffer *irbDepth, *irbStencil; + struct intel_region *colorRegion, *depthRegion = NULL; + struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL; int front = 0; /* drawing to front color buffer? */ if (!fb) { @@ -533,6 +534,8 @@ intel_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb) _mesa_update_framebuffer(ctx); /* this updates the DrawBuffer's Width/Height if it's a FBO */ _mesa_update_draw_buffer_bounds(ctx); + + intel_validate_depth_stencil(ctx, fb); } if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -607,8 +610,13 @@ intel_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb) *** Get depth buffer region and check if we need a software fallback. *** Note the BUFFER_DEPTH attachment is usually a DEPTH_STENCIL buffer. ***/ +#if 0 irbDepth = intel_get_renderbuffer(fb, BUFFER_DEPTH); if (irbDepth) { +#else + if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) { + irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped); +#endif if (irbDepth->region) { FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); depthRegion = irbDepth->region; @@ -638,9 +646,15 @@ intel_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb) *** This can only be hardware accelerated if we're using a *** combined DEPTH_STENCIL buffer (for now anyway). ***/ +#if 0 irbStencil = intel_get_renderbuffer(fb, BUFFER_STENCIL); if (irbStencil) { - if (irbStencil == irbDepth && irbStencil->region) { +#else + if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) { + irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped); +#endif + if ((irbStencil == irbDepth && irbStencil->region) /***|| + (irbStencil->PairedDepth == irbDepth->Base.Name)**/) { ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); /* need to re-compute stencil hw state */ @@ -651,10 +665,14 @@ intel_draw_buffer(GLcontext *ctx, struct gl_framebuffer *fb) } } else { + /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */ FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); /* need to re-compute stencil hw state */ ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled); } + /* + _mesa_debug(ctx, "STENCIL FALLBACK: 0x%x\n", intel->Fallback ); + */ intel->vtbl.set_draw_region( intel, colorRegion, depthRegion ); diff --git a/src/mesa/drivers/dri/i915/intel_depthstencil.c b/src/mesa/drivers/dri/i915/intel_depthstencil.c new file mode 100644 index 00000000000..92dbb4e0279 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_depthstencil.c @@ -0,0 +1,269 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "depthstencil.h" +#include "fbobject.h" +#include "framebuffer.h" +#include "hash.h" +#include "mtypes.h" +#include "renderbuffer.h" + +#include "intel_context.h" +#include "intel_fbo.h" +#include "intel_depthstencil.h" +#include "intel_regions.h" + + +/** + * The GL_EXT_framebuffer_object allows the user to create their own + * framebuffer objects consisting of color renderbuffers (0 or more), + * depth renderbuffers (0 or 1) and stencil renderbuffers (0 or 1). + * + * The spec considers depth and stencil renderbuffers to be totally independent + * buffers. In reality, most graphics hardware today uses a combined + * depth+stencil buffer (one 32-bit pixel = 24 bits of Z + 8 bits of stencil). + * + * This causes difficulty because the user may create some number of depth + * renderbuffers and some number of stencil renderbuffers and bind them + * together in framebuffers in any combination. + * + * This code manages all that. + * + * 1. Depth renderbuffers are always allocated in hardware as 32bpp + * GL_DEPTH24_STENCIL8 buffers. + * + * 2. Stencil renderbuffers are initially allocated in software as 8bpp + * GL_STENCIL_INDEX8 buffers. + * + * 3. Depth and Stencil renderbuffers use the PairedStencil and PairedDepth + * fields (respectively) to indicate if the buffer's currently paired + * with another stencil or depth buffer (respectively). + * + * 4. When a depth and stencil buffer are initially both attached to the + * current framebuffer, we merge the stencil buffer values into the + * depth buffer (really a depth+stencil buffer). The then hardware uses + * the combined buffer. + * + * 5. Whenever a depth or stencil buffer is reallocated (with + * glRenderbufferStorage) we undo the pairing and copy the stencil values + * from the combined depth/stencil buffer back to the stencil-only buffer. + * + * 6. We also undo the pairing when we find a change in buffer bindings. + * + * 7. If a framebuffer is only using a depth renderbuffer (no stencil), we + * just use the combined depth/stencil buffer and ignore the stencil values. + * + * 8. If a framebuffer is only using a stencil renderbuffer (no depth) we have + * to promote the 8bpp software stencil buffer to a 32bpp hardware + * depth+stencil buffer. + * + */ + + + +static void +map_regions(GLcontext *ctx, + struct intel_renderbuffer *depthRb, + struct intel_renderbuffer *stencilRb) +{ + struct intel_context *intel = intel_context(ctx); + if (depthRb && depthRb->region) { + intel_region_map(intel, depthRb->region); + depthRb->pfMap = depthRb->region->map; + depthRb->pfPitch = depthRb->region->pitch; + } + if (stencilRb && stencilRb->region) { + intel_region_map(intel, stencilRb->region); + stencilRb->pfMap = stencilRb->region->map; + stencilRb->pfPitch = stencilRb->region->pitch; + } +} + +static void +unmap_regions(GLcontext *ctx, + struct intel_renderbuffer *depthRb, + struct intel_renderbuffer *stencilRb) +{ + struct intel_context *intel = intel_context(ctx); + if (depthRb && depthRb->region) { + intel_region_unmap(intel, depthRb->region); + depthRb->pfMap = NULL; + depthRb->pfPitch = 0; + } + if (stencilRb && stencilRb->region) { + intel_region_unmap(intel, stencilRb->region); + stencilRb->pfMap = NULL; + stencilRb->pfPitch = 0; + } +} + + + +/** + * Undo the pairing/interleaving between depth and stencil buffers. + * driRb should be a depth/stencil or stencil renderbuffer. + */ +void +intel_undo_depth_stencil_pairing(GLcontext *ctx, + struct intel_renderbuffer *irb) +{ + if (irb->PairedStencil) { + /* irb is a depth/stencil buffer */ + struct gl_renderbuffer *stencilRb; + struct intel_renderbuffer *stencilIrb; + + ASSERT(irb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + + stencilRb = _mesa_lookup_renderbuffer(ctx, irb->PairedStencil); + stencilIrb = intel_renderbuffer(stencilRb); + if (stencilIrb) { + /* need to extract stencil values from the depth buffer */ + ASSERT(stencilIrb->PairedDepth == irb->Base.Name); + map_regions(ctx, irb, NULL); + _mesa_extract_stencil(ctx, &irb->Base, &stencilIrb->Base); + unmap_regions(ctx, irb, NULL); + stencilIrb->PairedDepth = 0; + } + irb->PairedStencil = 0; + } + else if (irb->PairedDepth) { + /* irb is a stencil buffer */ + struct gl_renderbuffer *depthRb; + struct intel_renderbuffer *depthIrb; + + ASSERT(irb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT || + irb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + + depthRb = _mesa_lookup_renderbuffer(ctx, irb->PairedDepth); + depthIrb = intel_renderbuffer(depthRb); + if (depthIrb) { + /* need to extract stencil values from the depth buffer */ + ASSERT(depthIrb->PairedStencil == irb->Base.Name); + map_regions(ctx, irb, NULL); + _mesa_extract_stencil(ctx, &depthIrb->Base, &irb->Base); + unmap_regions(ctx, irb, NULL); + depthIrb->PairedStencil = 0; + } + irb->PairedDepth = 0; + } + else { + _mesa_problem(ctx, "Problem in undo_depth_stencil_pairing"); + } + + ASSERT(irb->PairedStencil == 0); + ASSERT(irb->PairedDepth == 0); +} + + +/** + * Must be called if NewState & _NEW_BUFFER + */ +void +intel_validate_depth_stencil(GLcontext *ctx, struct gl_framebuffer *fb) +{ + struct intel_renderbuffer *depthRb, *stencilRb; + + depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); + stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); + + if (depthRb && stencilRb) { + if (depthRb == stencilRb) { + /* Using a user-created combined depth/stencil buffer. + * Nothing to do. + */ + ASSERT(depthRb->Base._BaseFormat == GL_DEPTH_STENCIL_EXT); + ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + } + else { + /* Separate depth/stencil buffers, need to interleave now */ + ASSERT(depthRb->Base._BaseFormat == GL_DEPTH_COMPONENT); + ASSERT(stencilRb->Base._BaseFormat == GL_STENCIL_INDEX); + /* may need to interleave depth/stencil now */ + if (depthRb->PairedStencil == stencilRb->Base.Name) { + /* OK, the depth and stencil buffers are already interleaved */ + ASSERT(stencilRb->PairedDepth == depthRb->Base.Name); + } + else { + /* need to setup pairing/interleaving */ + if (depthRb->PairedStencil) { + intel_undo_depth_stencil_pairing(ctx, depthRb); + } + if (stencilRb->PairedDepth) { + intel_undo_depth_stencil_pairing(ctx, stencilRb); + } + + ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + ASSERT(stencilRb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT || + stencilRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + + /* establish new pairing: interleave stencil into depth buffer */ + map_regions(ctx, depthRb, stencilRb); + _mesa_insert_stencil(ctx, &depthRb->Base, &stencilRb->Base); + unmap_regions(ctx, depthRb, stencilRb); + depthRb->PairedStencil = stencilRb->Base.Name; + stencilRb->PairedDepth = depthRb->Base.Name; + } + + } + } + else if (depthRb) { + /* Depth buffer but no stencil buffer. + * We'll use a GL_DEPTH24_STENCIL8 buffer and ignore the stencil bits. + */ + ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + /* intel_undo any previous pairing */ + if (depthRb->PairedStencil) { + intel_undo_depth_stencil_pairing(ctx, depthRb); + } + } + else if (stencilRb) { + /* Stencil buffer but no depth buffer. + * Since h/w doesn't typically support just 8bpp stencil w/out Z, + * we'll use a GL_DEPTH24_STENCIL8 buffer and ignore the depth bits. + */ + /* undo any previous pairing */ + if (stencilRb->PairedDepth) { + intel_undo_depth_stencil_pairing(ctx, stencilRb); + } + if (stencilRb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT) { + /* promote buffer to GL_DEPTH24_STENCIL8 */ + _mesa_promote_stencil(ctx, &stencilRb->Base); + } + ASSERT(stencilRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + } + + _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH); + _mesa_update_stencil_buffer(ctx, fb, BUFFER_DEPTH); /* Yes, not STENCIL */ + + /* The hardware should use fb->Attachment[BUFFER_DEPTH].Renderbuffer + * first, if present, then fb->Attachment[BUFFER_STENCIL].Renderbuffer + * if present. + */ +} diff --git a/src/mesa/drivers/dri/i915/intel_depthstencil.h b/src/mesa/drivers/dri/i915/intel_depthstencil.h new file mode 100644 index 00000000000..f64af2aef37 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_depthstencil.h @@ -0,0 +1,14 @@ + +#ifndef INTEL_DEPTH_STENCIL_H +#define INTEL_DEPTH_STENCIL_H + + +extern void +intel_undo_depth_stencil_pairing(GLcontext *ctx, + struct intel_renderbuffer *driRb); + +extern void +intel_validate_depth_stencil(GLcontext *ctx, struct gl_framebuffer *fb); + + +#endif /* INTEL_DEPTH_STENCIL_H */ diff --git a/src/mesa/drivers/dri/i915/intel_fbo.c b/src/mesa/drivers/dri/i915/intel_fbo.c index 76b79a70f5d..97d4cecf062 100644 --- a/src/mesa/drivers/dri/i915/intel_fbo.c +++ b/src/mesa/drivers/dri/i915/intel_fbo.c @@ -37,12 +37,12 @@ #include "intel_context.h" #include "intel_buffers.h" #include "intel_bufmgr.h" +#include "intel_depthstencil.h" #include "intel_fbo.h" #include "intel_mipmap_tree.h" #include "intel_regions.h" #include "intel_span.h" - #define INTEL_RB_CLASS 0x12345678 @@ -102,6 +102,12 @@ intel_delete_renderbuffer(struct gl_renderbuffer *rb) struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); + ASSERT(irb); + + if (irb->PairedStencil || irb->PairedDepth) { + intel_undo_depth_stencil_pairing(ctx, irb); + } + if (intel && irb->region) { intel_region_release(intel, &irb->region); } @@ -156,15 +162,6 @@ intel_alloc_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb, ASSERT(rb->Name != 0); - /* defaults */ - rb->RedBits = - rb->GreenBits = - rb->BlueBits = - rb->AlphaBits = - rb->IndexBits = - rb->DepthBits = - rb->StencilBits = 0; - switch (internalFormat) { case GL_R3_G3_B2: case GL_RGB4: @@ -202,12 +199,11 @@ intel_alloc_renderbuffer_storage(GLcontext *ctx, struct gl_renderbuffer *rb, case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: - rb->_ActualFormat = GL_STENCIL_INDEX8_EXT; - rb->DataType = GL_UNSIGNED_BYTE; + /* alloc a depth+stencil buffer */ + rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; + rb->DataType = GL_UNSIGNED_INT_24_8_EXT; rb->StencilBits = 8; - cpp = 1; - softwareBuffer = GL_TRUE; - /* XXX software buffer? */ + cpp = 4; break; case GL_DEPTH_COMPONENT16: rb->_ActualFormat = GL_DEPTH_COMPONENT16; diff --git a/src/mesa/drivers/dri/i915/intel_fbo.h b/src/mesa/drivers/dri/i915/intel_fbo.h index 34d095228f4..906df4a6bc4 100644 --- a/src/mesa/drivers/dri/i915/intel_fbo.h +++ b/src/mesa/drivers/dri/i915/intel_fbo.h @@ -42,6 +42,9 @@ struct intel_renderbuffer { void *pfMap; /* possibly paged flipped map pointer */ GLuint pfPitch; /* possibly paged flipped pitch */ GLboolean RenderToTexture; /* RTT? */ + + GLuint PairedDepth; /**< only used if this is a depth renderbuffer */ + GLuint PairedStencil; /**< only used if this is a stencil renderbuffer */ };