blob: 90baecd8c218ce03e8d246be396aaa2eb875b22e [file] [log] [blame]
/**************************************************************************
*
* 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.
*/
}