summaryrefslogtreecommitdiff
path: root/src/mesa/main/depthstencil.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main/depthstencil.c')
-rw-r--r--src/mesa/main/depthstencil.c661
1 files changed, 661 insertions, 0 deletions
diff --git a/src/mesa/main/depthstencil.c b/src/mesa/main/depthstencil.c
new file mode 100644
index 0000000..d4990bb
--- /dev/null
+++ b/src/mesa/main/depthstencil.c
@@ -0,0 +1,661 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2006 Brian Paul 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, sublicense,
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL 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 "fbobject.h"
+#include "mtypes.h"
+#include "depthstencil.h"
+#include "renderbuffer.h"
+
+
+/**
+ * Adaptor/wrappers for GL_DEPTH_STENCIL renderbuffers.
+ *
+ * The problem with a GL_DEPTH_STENCIL renderbuffer is that sometimes we
+ * want to treat it as a stencil buffer, other times we want to treat it
+ * as a depth/z buffer and still other times when we want to treat it as
+ * a combined Z+stencil buffer! That implies we need three different sets
+ * of Get/Put functions.
+ *
+ * We solve this by wrapping the Z24_S8 renderbuffer with depth and stencil
+ * adaptors, each with the right kind of depth/stencil Get/Put functions.
+ */
+
+
+static void *
+nop_get_pointer(GLcontext *ctx, struct gl_renderbuffer *rb, GLint x, GLint y)
+{
+ (void) ctx;
+ (void) rb;
+ (void) x;
+ (void) y;
+ return NULL;
+}
+
+
+/**
+ * Delete a depth or stencil wrapper renderbuffer.
+ */
+static void
+delete_wrapper(struct gl_renderbuffer *rb)
+{
+ struct gl_renderbuffer *dsrb = rb->Wrapped;
+ ASSERT(dsrb);
+ ASSERT(rb->_ActualFormat == GL_DEPTH_COMPONENT24 ||
+ rb->_ActualFormat == GL_STENCIL_INDEX8_EXT);
+ /* decrement refcount on the wrapped buffer and delete it if necessary */
+ dsrb->RefCount--;
+ if (dsrb->RefCount <= 0) {
+ dsrb->Delete(dsrb);
+ }
+ _mesa_free(rb);
+}
+
+
+/**
+ * Realloc storage for wrapper.
+ */
+static GLboolean
+alloc_wrapper_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLuint width, GLuint height)
+{
+ /* just pass this on to the wrapped renderbuffer */
+ struct gl_renderbuffer *dsrb = rb->Wrapped;
+ GLboolean retVal;
+
+ (void) internalFormat;
+
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+
+ retVal = dsrb->AllocStorage(ctx, dsrb, dsrb->InternalFormat, width, height);
+ if (retVal) {
+ rb->Width = width;
+ rb->Height = height;
+ }
+ return retVal;
+}
+
+
+
+
+/*======================================================================
+ * Depth wrapper around depth/stencil renderbuffer
+ */
+
+static void
+get_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
+ GLint x, GLint y, void *values)
+{
+ struct gl_renderbuffer *dsrb = z24rb->Wrapped;
+ GLuint temp[MAX_WIDTH], i;
+ GLuint *dst = (GLuint *) values;
+ const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
+ ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (!src) {
+ dsrb->GetRow(ctx, dsrb, count, x, y, temp);
+ src = temp;
+ }
+ for (i = 0; i < count; i++) {
+ dst[i] = src[i] >> 8;
+ }
+}
+
+static void
+get_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
+ const GLint x[], const GLint y[], void *values)
+{
+ struct gl_renderbuffer *dsrb = z24rb->Wrapped;
+ GLuint temp[MAX_WIDTH], i;
+ GLuint *dst = (GLuint *) values;
+ ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ ASSERT(count <= MAX_WIDTH);
+ /* don't bother trying direct access */
+ dsrb->GetValues(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ dst[i] = temp[i] >> 8;
+ }
+}
+
+static void
+put_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
+ GLint x, GLint y, const void *values, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = z24rb->Wrapped;
+ const GLuint *src = (const GLuint *) values;
+ GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
+ ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (dst) {
+ /* direct access */
+ GLuint i;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ dst[i] = (src[i] << 8) | (dst[i] & 0xff);
+ }
+ }
+ }
+ else {
+ /* get, modify, put */
+ GLuint temp[MAX_WIDTH], i;
+ dsrb->GetRow(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = (src[i] << 8) | (temp[i] & 0xff);
+ }
+ }
+ dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
+ }
+}
+
+static void
+put_mono_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
+ GLint x, GLint y, const void *value, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = z24rb->Wrapped;
+ const GLuint shiftedVal = *((GLuint *) value) << 8;
+ GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
+ ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (dst) {
+ /* direct access */
+ GLuint i;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ dst[i] = shiftedVal | (dst[i] & 0xff);
+ }
+ }
+ }
+ else {
+ /* get, modify, put */
+ GLuint temp[MAX_WIDTH], i;
+ dsrb->GetRow(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = shiftedVal | (temp[i] & 0xff);
+ }
+ }
+ dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
+ }
+}
+
+static void
+put_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
+ const GLint x[], const GLint y[],
+ const void *values, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = z24rb->Wrapped;
+ const GLubyte *src = (const GLubyte *) values;
+ ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (dsrb->GetPointer(ctx, dsrb, 0, 0)) {
+ /* direct access */
+ GLuint i;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
+ *dst = (src[i] << 8) | (*dst & 0xff);
+ }
+ }
+ }
+ else {
+ /* get, modify, put */
+ GLuint temp[MAX_WIDTH], i;
+ dsrb->GetValues(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = (src[i] << 8) | (temp[i] & 0xff);
+ }
+ }
+ dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
+ }
+}
+
+static void
+put_mono_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb,
+ GLuint count, const GLint x[], const GLint y[],
+ const void *value, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = z24rb->Wrapped;
+ GLuint temp[MAX_WIDTH], i;
+ const GLuint shiftedVal = *((GLuint *) value) << 8;
+ /* get, modify, put */
+ dsrb->GetValues(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = shiftedVal | (temp[i] & 0xff);
+ }
+ }
+ dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
+}
+
+
+/**
+ * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like
+ * a depth renderbuffer.
+ * \return new depth renderbuffer
+ */
+struct gl_renderbuffer *
+_mesa_new_z24_renderbuffer_wrapper(GLcontext *ctx,
+ struct gl_renderbuffer *dsrb)
+{
+ struct gl_renderbuffer *z24rb;
+
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+
+ z24rb = _mesa_new_renderbuffer(ctx, 0);
+ if (!z24rb)
+ return NULL;
+
+ z24rb->Wrapped = dsrb;
+ z24rb->Name = dsrb->Name;
+ z24rb->RefCount = 1;
+ z24rb->Width = dsrb->Width;
+ z24rb->Height = dsrb->Height;
+ z24rb->InternalFormat = GL_DEPTH_COMPONENT24_ARB;
+ z24rb->_ActualFormat = GL_DEPTH_COMPONENT24_ARB;
+ z24rb->_BaseFormat = GL_DEPTH_COMPONENT;
+ z24rb->DataType = GL_UNSIGNED_INT;
+ z24rb->DepthBits = 24;
+ z24rb->Data = NULL;
+ z24rb->Delete = delete_wrapper;
+ z24rb->AllocStorage = alloc_wrapper_storage;
+ z24rb->GetPointer = nop_get_pointer;
+ z24rb->GetRow = get_row_z24;
+ z24rb->GetValues = get_values_z24;
+ z24rb->PutRow = put_row_z24;
+ z24rb->PutRowRGB = NULL;
+ z24rb->PutMonoRow = put_mono_row_z24;
+ z24rb->PutValues = put_values_z24;
+ z24rb->PutMonoValues = put_mono_values_z24;
+
+ return z24rb;
+}
+
+
+/*======================================================================
+ * Stencil wrapper around depth/stencil renderbuffer
+ */
+
+static void
+get_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
+ GLint x, GLint y, void *values)
+{
+ struct gl_renderbuffer *dsrb = s8rb->Wrapped;
+ GLuint temp[MAX_WIDTH], i;
+ GLubyte *dst = (GLubyte *) values;
+ const GLuint *src = (const GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
+ ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (!src) {
+ dsrb->GetRow(ctx, dsrb, count, x, y, temp);
+ src = temp;
+ }
+ for (i = 0; i < count; i++) {
+ dst[i] = src[i] & 0xff;
+ }
+}
+
+static void
+get_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
+ const GLint x[], const GLint y[], void *values)
+{
+ struct gl_renderbuffer *dsrb = s8rb->Wrapped;
+ GLuint temp[MAX_WIDTH], i;
+ GLubyte *dst = (GLubyte *) values;
+ ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ ASSERT(count <= MAX_WIDTH);
+ /* don't bother trying direct access */
+ dsrb->GetValues(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ dst[i] = temp[i] & 0xff;
+ }
+}
+
+static void
+put_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
+ GLint x, GLint y, const void *values, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = s8rb->Wrapped;
+ const GLubyte *src = (const GLubyte *) values;
+ GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
+ ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (dst) {
+ /* direct access */
+ GLuint i;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ dst[i] = (dst[i] & 0xffffff00) | src[i];
+ }
+ }
+ }
+ else {
+ /* get, modify, put */
+ GLuint temp[MAX_WIDTH], i;
+ dsrb->GetRow(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = (temp[i] & 0xffffff00) | src[i];
+ }
+ }
+ dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
+ }
+}
+
+static void
+put_mono_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
+ GLint x, GLint y, const void *value, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = s8rb->Wrapped;
+ const GLubyte val = *((GLubyte *) value);
+ GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x, y);
+ ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (dst) {
+ /* direct access */
+ GLuint i;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ dst[i] = (dst[i] & 0xffffff00) | val;
+ }
+ }
+ }
+ else {
+ /* get, modify, put */
+ GLuint temp[MAX_WIDTH], i;
+ dsrb->GetRow(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = (temp[i] & 0xffffff00) | val;
+ }
+ }
+ dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
+ }
+}
+
+static void
+put_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
+ const GLint x[], const GLint y[],
+ const void *values, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = s8rb->Wrapped;
+ const GLubyte *src = (const GLubyte *) values;
+ ASSERT(s8rb->DataType == GL_UNSIGNED_BYTE);
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ if (dsrb->GetPointer(ctx, dsrb, 0, 0)) {
+ /* direct access */
+ GLuint i;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
+ *dst = (*dst & 0xffffff00) | src[i];
+ }
+ }
+ }
+ else {
+ /* get, modify, put */
+ GLuint temp[MAX_WIDTH], i;
+ dsrb->GetValues(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = (temp[i] & 0xffffff00) | src[i];
+ }
+ }
+ dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
+ }
+}
+
+static void
+put_mono_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
+ const GLint x[], const GLint y[],
+ const void *value, const GLubyte *mask)
+{
+ struct gl_renderbuffer *dsrb = s8rb->Wrapped;
+ GLuint temp[MAX_WIDTH], i;
+ const GLubyte val = *((GLubyte *) value);
+ /* get, modify, put */
+ dsrb->GetValues(ctx, dsrb, count, x, y, temp);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ temp[i] = (temp[i] & 0xffffff) | val;
+ }
+ }
+ dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
+}
+
+
+/**
+ * Wrap the given GL_DEPTH_STENCIL renderbuffer so that it acts like
+ * a stencil renderbuffer.
+ * \return new stencil renderbuffer
+ */
+struct gl_renderbuffer *
+_mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, struct gl_renderbuffer *dsrb)
+{
+ struct gl_renderbuffer *s8rb;
+
+ ASSERT(dsrb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+
+ s8rb = _mesa_new_renderbuffer(ctx, 0);
+ if (!s8rb)
+ return NULL;
+
+ s8rb->Wrapped = dsrb;
+ s8rb->Name = dsrb->Name;
+ s8rb->RefCount = 1;
+ s8rb->Width = dsrb->Width;
+ s8rb->Height = dsrb->Height;
+ s8rb->InternalFormat = GL_STENCIL_INDEX8_EXT;
+ s8rb->_ActualFormat = GL_STENCIL_INDEX8_EXT;
+ s8rb->_BaseFormat = GL_STENCIL_INDEX;
+ s8rb->DataType = GL_UNSIGNED_BYTE;
+ s8rb->StencilBits = 8;
+ s8rb->Data = NULL;
+ s8rb->Delete = delete_wrapper;
+ s8rb->AllocStorage = alloc_wrapper_storage;
+ s8rb->GetPointer = nop_get_pointer;
+ s8rb->GetRow = get_row_s8;
+ s8rb->GetValues = get_values_s8;
+ s8rb->PutRow = put_row_s8;
+ s8rb->PutRowRGB = NULL;
+ s8rb->PutMonoRow = put_mono_row_s8;
+ s8rb->PutValues = put_values_s8;
+ s8rb->PutMonoValues = put_mono_values_s8;
+
+ return s8rb;
+}
+
+
+
+/**
+ ** The following functions are useful for hardware drivers that only
+ ** implement combined depth/stencil buffers.
+ ** The GL_EXT_framebuffer_object extension allows indepedent depth and
+ ** stencil buffers to be used in any combination.
+ ** Therefore, we sometimes have to merge separate depth and stencil
+ ** renderbuffers into a single depth+stencil renderbuffer. And sometimes
+ ** we have to split combined depth+stencil renderbuffers into separate
+ ** renderbuffers.
+ **/
+
+
+/**
+ * Extract stencil values from the combined depth/stencil renderbuffer, storing
+ * the values into a separate stencil renderbuffer.
+ * \param dsRb the source depth/stencil renderbuffer
+ * \param stencilRb the destination stencil renderbuffer
+ * (either 8-bit or 32-bit)
+ */
+void
+_mesa_extract_stencil(GLcontext *ctx,
+ struct gl_renderbuffer *dsRb,
+ struct gl_renderbuffer *stencilRb)
+{
+ GLuint row, width, height;
+
+ ASSERT(dsRb);
+ ASSERT(stencilRb);
+
+ ASSERT(dsRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ ASSERT(stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT ||
+ stencilRb->_ActualFormat == GL_STENCIL_INDEX8_EXT);
+ ASSERT(dsRb->Width == stencilRb->Width);
+ ASSERT(dsRb->Height == stencilRb->Height);
+
+ width = dsRb->Width;
+ height = dsRb->Height;
+
+ for (row = 0; row < height; row++) {
+ GLuint depthStencil[MAX_WIDTH];
+ dsRb->GetRow(ctx, dsRb, width, 0, row, depthStencil);
+ if (stencilRb->_ActualFormat == GL_STENCIL_INDEX8_EXT) {
+ /* 8bpp stencil */
+ GLubyte stencil[MAX_WIDTH];
+ GLuint i;
+ for (i = 0; i < width; i++) {
+ stencil[i] = depthStencil[i] & 0xff;
+ }
+ stencilRb->PutRow(ctx, stencilRb, width, 0, row, stencil, NULL);
+ }
+ else {
+ /* 32bpp stencil */
+ /* the 24 depth bits will be ignored */
+ ASSERT(stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(stencilRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ stencilRb->PutRow(ctx, stencilRb, width, 0, row, depthStencil, NULL);
+ }
+ }
+}
+
+
+/**
+ * Copy stencil values from a stencil renderbuffer into a combined
+ * depth/stencil renderbuffer.
+ * \param dsRb the destination depth/stencil renderbuffer
+ * \param stencilRb the source stencil buffer (either 8-bit or 32-bit)
+ */
+void
+_mesa_insert_stencil(GLcontext *ctx,
+ struct gl_renderbuffer *dsRb,
+ struct gl_renderbuffer *stencilRb)
+{
+ GLuint row, width, height;
+
+ ASSERT(dsRb);
+ ASSERT(stencilRb);
+
+ ASSERT(dsRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(dsRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ ASSERT(stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT ||
+ stencilRb->_ActualFormat == GL_STENCIL_INDEX8_EXT);
+
+ ASSERT(dsRb->Width == stencilRb->Width);
+ ASSERT(dsRb->Height == stencilRb->Height);
+
+ width = dsRb->Width;
+ height = dsRb->Height;
+
+ for (row = 0; row < height; row++) {
+ GLuint depthStencil[MAX_WIDTH];
+
+ dsRb->GetRow(ctx, dsRb, width, 0, row, depthStencil);
+
+ if (stencilRb->_ActualFormat == GL_STENCIL_INDEX8_EXT) {
+ /* 8bpp stencil */
+ GLubyte stencil[MAX_WIDTH];
+ GLuint i;
+ stencilRb->GetRow(ctx, stencilRb, width, 0, row, stencil);
+ for (i = 0; i < width; i++) {
+ depthStencil[i] = (depthStencil[i] & 0xffffff00) | stencil[i];
+ }
+ }
+ else {
+ /* 32bpp stencil buffer */
+ GLuint stencil[MAX_WIDTH], i;
+ ASSERT(stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(stencilRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+ stencilRb->GetRow(ctx, stencilRb, width, 0, row, stencil);
+ for (i = 0; i < width; i++) {
+ depthStencil[i]
+ = (depthStencil[i] & 0xffffff00) | (stencil[i] & 0xff);
+ }
+ }
+
+ dsRb->PutRow(ctx, dsRb, width, 0, row, depthStencil, NULL);
+ }
+}
+
+
+/**
+ * Convert the stencil buffer from 8bpp to 32bpp depth/stencil.
+ * \param stencilRb the stencil renderbuffer to promote
+ */
+void
+_mesa_promote_stencil(GLcontext *ctx, struct gl_renderbuffer *stencilRb)
+{
+ const GLsizei width = stencilRb->Width;
+ const GLsizei height = stencilRb->Height;
+ GLubyte *data;
+ GLint i, j, k;
+
+ ASSERT(stencilRb->_ActualFormat == GL_STENCIL_INDEX8_EXT);
+ ASSERT(stencilRb->Data);
+
+ data = (GLubyte *) stencilRb->Data;
+ stencilRb->Data = NULL;
+ stencilRb->AllocStorage(ctx, stencilRb, GL_DEPTH24_STENCIL8_EXT,
+ width, height);
+
+ ASSERT(stencilRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+
+ k = 0;
+ for (i = 0; i < height; i++) {
+ GLuint depthStencil[MAX_WIDTH];
+ for (j = 0; j < width; j++) {
+ depthStencil[j] = data[k++];
+ }
+ stencilRb->PutRow(ctx, stencilRb, width, 0, i, depthStencil, NULL);
+ }
+ _mesa_free(data);
+
+ stencilRb->_BaseFormat = GL_DEPTH_STENCIL_EXT;
+}