| /************************************************************************** |
| * |
| * 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. |
| * irb should be a depth/stencil or stencil renderbuffer. |
| */ |
| void |
| intel_unpair_depth_stencil(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, stencilIrb); |
| _mesa_extract_stencil(ctx, &irb->Base, &stencilIrb->Base); |
| unmap_regions(ctx, irb, stencilIrb); |
| 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, depthIrb, irb); |
| _mesa_extract_stencil(ctx, &depthIrb->Base, &irb->Base); |
| unmap_regions(ctx, depthIrb, irb); |
| depthIrb->PairedStencil = 0; |
| } |
| irb->PairedDepth = 0; |
| } |
| else { |
| _mesa_problem(ctx, "Problem in undo_depth_stencil_pairing"); |
| } |
| |
| ASSERT(irb->PairedStencil == 0); |
| ASSERT(irb->PairedDepth == 0); |
| } |
| |
| |
| /** |
| * Examine the depth and stencil renderbuffers which are attached to the |
| * framebuffer. If both depth and stencil are attached, make sure that the |
| * renderbuffers are 'paired' (combined). If only depth or only stencil is |
| * attached, undo any previous pairing. |
| * |
| * Must be called if NewState & _NEW_BUFFER (when renderbuffer attachments |
| * change, for example). |
| */ |
| void |
| intel_validate_paired_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 new pairing/interleaving */ |
| if (depthRb->PairedStencil) { |
| intel_unpair_depth_stencil(ctx, depthRb); |
| } |
| if (stencilRb->PairedDepth) { |
| intel_unpair_depth_stencil(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. |
| */ |
| /* can't assert this until storage is allocated: |
| ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); |
| */ |
| /* intel_undo any previous pairing */ |
| if (depthRb->PairedStencil) { |
| intel_unpair_depth_stencil(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_unpair_depth_stencil(ctx, stencilRb); |
| } |
| if (stencilRb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT) { |
| /* promote buffer to GL_DEPTH24_STENCIL8 for hw rendering */ |
| _mesa_promote_stencil(ctx, &stencilRb->Base); |
| ASSERT(stencilRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); |
| } |
| } |
| |
| /* Finally, update the fb->_DepthBuffer and fb->_StencilBuffer fields */ |
| _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH); |
| if (depthRb && depthRb->PairedStencil) |
| _mesa_update_stencil_buffer(ctx, fb, BUFFER_DEPTH); |
| else |
| _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL); |
| |
| |
| /* The hardware should use fb->Attachment[BUFFER_DEPTH].Renderbuffer |
| * first, if present, then fb->Attachment[BUFFER_STENCIL].Renderbuffer |
| * if present. |
| */ |
| } |