mesa: Remove unnecessary headers from fbobject.c.
[mesa.git] / src / mesa / main / depthstencil.c
index 90e434118e1c1e57aa8526f470884bb9306c1a23..193c7f8255fe9e4d246a7105b98b12ec8d8f26f4 100644 (file)
@@ -2,7 +2,7 @@
  * Mesa 3-D graphics library
  * Version:  6.5
  *
- * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
+ * 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"),
@@ -26,6 +26,7 @@
 #include "imports.h"
 #include "context.h"
 #include "fbobject.h"
+#include "formats.h"
 #include "mtypes.h"
 #include "depthstencil.h"
 #include "renderbuffer.h"
  * 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.
+ * We solve this by wrapping the Z24_S8 or S8_Z24 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 renderbuffer.
+ * Delete a depth or stencil wrapper renderbuffer.
  */
 static void
 delete_wrapper(struct gl_renderbuffer *rb)
 {
+   ASSERT(rb->Format == MESA_FORMAT_Z24_S8 ||
+          rb->Format == MESA_FORMAT_S8_Z24);
+   _mesa_reference_renderbuffer(&rb->Wrapped, NULL);
+   _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;
-   assert(dsrb);
-   assert(rb->InternalFormat == GL_DEPTH_COMPONENT24 ||
-          rb->InternalFormat == GL_STENCIL_INDEX8_EXT);
-   /* decrement refcount on the wrapped buffer and delete it if necessary */
-   dsrb->RefCount--;
-   if (dsrb->RefCount <= 0) {
-      dsrb->Delete(dsrb);
+   GLboolean retVal;
+
+   (void) internalFormat;
+
+   ASSERT(dsrb->Format == MESA_FORMAT_Z24_S8 ||
+          dsrb->Format == MESA_FORMAT_S8_Z24);
+
+   retVal = dsrb->AllocStorage(ctx, dsrb, dsrb->InternalFormat, width, height);
+   if (retVal) {
+      rb->Width = width;
+      rb->Height = height;
    }
-   _mesa_free(rb);
+   return retVal;
 }
 
 
+
+
 /*======================================================================
  * Depth wrapper around depth/stencil renderbuffer
  */
@@ -89,8 +115,16 @@ get_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
       src = temp;
    }
-   for (i = 0; i < count; i++) {
-      dst[i] = src[i] >> 8;
+   if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+      for (i = 0; i < count; i++) {
+         dst[i] = src[i] >> 8;
+      }
+   }
+   else {
+      assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+      for (i = 0; i < count; i++) {
+         dst[i] = src[i] & 0xffffff;
+      }
    }
 }
 
@@ -106,8 +140,16 @@ get_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
    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;
+   if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+      for (i = 0; i < count; i++) {
+         dst[i] = temp[i] >> 8;
+      }
+   }
+   else {
+      assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+      for (i = 0; i < count; i++) {
+         dst[i] = temp[i] & 0xffffff;
+      }
    }
 }
 
@@ -123,9 +165,19 @@ put_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
    if (dst) {
       /* direct access */
       GLuint i;
-      for (i = 0; i < count; i++) {
-         if (!mask || mask[i]) {
-            dst[i] = (src[i] << 8) | (dst[i] & 0xff);
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = (src[i] << 8) | (dst[i] & 0xff);
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = (src[i] & 0xffffff) | (dst[i] & 0xff000000);
+            }
          }
       }
    }
@@ -133,9 +185,19 @@ put_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
       /* 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);
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (src[i] << 8) | (temp[i] & 0xff);
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (src[i] & 0xffffff) | (temp[i] & 0xff000000);
+            }
          }
       }
       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
@@ -147,16 +209,27 @@ 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->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);
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         const GLuint shiftedVal = *((GLuint *) value) << 8;
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = shiftedVal | (dst[i] & 0xff);
+            }
+         }
+      }
+      else {
+         const GLuint shiftedVal = *((GLuint *) value);
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = shiftedVal | (dst[i] & 0xff000000);
+            }
          }
       }
    }
@@ -164,9 +237,21 @@ put_mono_row_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
       /* 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);
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         const GLuint shiftedVal = *((GLuint *) value) << 8;
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = shiftedVal | (temp[i] & 0xff);
+            }
+         }
+      }
+      else {
+         const GLuint shiftedVal = *((GLuint *) value);
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = shiftedVal | (temp[i] & 0xff000000);
+            }
          }
       }
       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
@@ -179,16 +264,27 @@ put_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
                const void *values, const GLubyte *mask)
 {
    struct gl_renderbuffer *dsrb = z24rb->Wrapped;
-   const GLubyte *src = (const GLubyte *) values;
+   const GLuint *src = (const GLuint *) values;
    ASSERT(z24rb->DataType == GL_UNSIGNED_INT);
    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);
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         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 {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
+               *dst = (src[i] & 0xffffff) | (*dst & 0xff000000);
+            }
          }
       }
    }
@@ -196,9 +292,19 @@ put_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb, GLuint count,
       /* 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);
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (src[i] << 8) | (temp[i] & 0xff);
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (src[i] & 0xffffff) | (temp[i] & 0xff000000);
+            }
          }
       }
       dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
@@ -212,12 +318,23 @@ put_mono_values_z24(GLcontext *ctx, struct gl_renderbuffer *z24rb,
 {
    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);
+   if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+      const GLuint shiftedVal = *((GLuint *) value) << 8;
+      for (i = 0; i < count; i++) {
+         if (!mask || mask[i]) {
+            temp[i] = shiftedVal | (temp[i] & 0xff);
+         }
+      }
+   }
+   else {
+      const GLuint shiftedVal = *((GLuint *) value);
+      assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+      for (i = 0; i < count; i++) {
+         if (!mask || mask[i]) {
+            temp[i] = shiftedVal | (temp[i] & 0xff000000);
+         }
       }
    }
    dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
@@ -235,7 +352,8 @@ _mesa_new_z24_renderbuffer_wrapper(GLcontext *ctx,
 {
    struct gl_renderbuffer *z24rb;
 
-   ASSERT(dsrb->_BaseFormat == GL_DEPTH_STENCIL_EXT);
+   ASSERT(dsrb->Format == MESA_FORMAT_Z24_S8 ||
+          dsrb->Format == MESA_FORMAT_S8_Z24);
    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
 
    z24rb = _mesa_new_renderbuffer(ctx, 0);
@@ -247,12 +365,13 @@ _mesa_new_z24_renderbuffer_wrapper(GLcontext *ctx,
    z24rb->RefCount = 1;
    z24rb->Width = dsrb->Width;
    z24rb->Height = dsrb->Height;
-   z24rb->InternalFormat = GL_DEPTH_COMPONENT24_ARB;
+   z24rb->InternalFormat = GL_DEPTH_COMPONENT24;
+   z24rb->Format = MESA_FORMAT_X8_Z24;
    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;
@@ -284,8 +403,16 @@ get_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
       dsrb->GetRow(ctx, dsrb, count, x, y, temp);
       src = temp;
    }
-   for (i = 0; i < count; i++) {
-      dst[i] = src[i] & 0xff;
+   if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+      for (i = 0; i < count; i++) {
+         dst[i] = src[i] & 0xff;
+      }
+   }
+   else {
+      assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+      for (i = 0; i < count; i++) {
+         dst[i] = src[i] >> 24;
+      }
    }
 }
 
@@ -301,8 +428,16 @@ get_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
    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;
+   if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+      for (i = 0; i < count; i++) {
+         dst[i] = temp[i] & 0xff;
+      }
+   }
+   else {
+      assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+      for (i = 0; i < count; i++) {
+         dst[i] = temp[i] >> 24;
+      }
    }
 }
 
@@ -318,9 +453,19 @@ put_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
    if (dst) {
       /* direct access */
       GLuint i;
-      for (i = 0; i < count; i++) {
-         if (!mask || mask[i]) {
-            dst[i] = (dst[i] & 0xffffff00) | src[i];
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = (dst[i] & 0xffffff00) | src[i];
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = (dst[i] & 0xffffff) | (src[i] << 24);
+            }
          }
       }
    }
@@ -328,9 +473,19 @@ put_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
       /* 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];
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (temp[i] & 0xffffff00) | src[i];
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (temp[i] & 0xffffff) | (src[i] << 24);
+            }
          }
       }
       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
@@ -349,9 +504,19 @@ put_mono_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
    if (dst) {
       /* direct access */
       GLuint i;
-      for (i = 0; i < count; i++) {
-         if (!mask || mask[i]) {
-            dst[i] = (dst[i] & 0xffffff00) | val;
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = (dst[i] & 0xffffff00) | val;
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               dst[i] = (dst[i] & 0xffffff) | (val << 24);
+            }
          }
       }
    }
@@ -359,9 +524,19 @@ put_mono_row_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
       /* 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;
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (temp[i] & 0xffffff00) | val;
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (temp[i] & 0xffffff) | (val << 24);
+            }
          }
       }
       dsrb->PutRow(ctx, dsrb, count, x, y, temp, mask);
@@ -380,10 +555,21 @@ put_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
    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];
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         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 {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               GLuint *dst = (GLuint *) dsrb->GetPointer(ctx, dsrb, x[i], y[i]);
+               *dst = (*dst & 0xffffff) | (src[i] << 24);
+            }
          }
       }
    }
@@ -391,9 +577,19 @@ put_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
       /* 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];
+      if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (temp[i] & 0xffffff00) | src[i];
+            }
+         }
+      }
+      else {
+         assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+         for (i = 0; i < count; i++) {
+            if (!mask || mask[i]) {
+               temp[i] = (temp[i] & 0xffffff) | (src[i] << 24);
+            }
          }
       }
       dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
@@ -410,9 +606,19 @@ put_mono_values_s8(GLcontext *ctx, struct gl_renderbuffer *s8rb, GLuint count,
    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;
+   if (dsrb->Format == MESA_FORMAT_Z24_S8) {
+      for (i = 0; i < count; i++) {
+         if (!mask || mask[i]) {
+            temp[i] = (temp[i] & 0xffffff00) | val;
+         }
+      }
+   }
+   else {
+      assert(dsrb->Format == MESA_FORMAT_S8_Z24);
+      for (i = 0; i < count; i++) {
+         if (!mask || mask[i]) {
+            temp[i] = (temp[i] & 0xffffff) | (val << 24);
+         }
       }
    }
    dsrb->PutValues(ctx, dsrb, count, x, y, temp, mask);
@@ -429,7 +635,8 @@ _mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, struct gl_renderbuffer *dsrb)
 {
    struct gl_renderbuffer *s8rb;
 
-   ASSERT(dsrb->_BaseFormat == GL_DEPTH_STENCIL_EXT);
+   ASSERT(dsrb->Format == MESA_FORMAT_Z24_S8 ||
+          dsrb->Format == MESA_FORMAT_S8_Z24);
    ASSERT(dsrb->DataType == GL_UNSIGNED_INT_24_8_EXT);
 
    s8rb = _mesa_new_renderbuffer(ctx, 0);
@@ -442,11 +649,12 @@ _mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, struct gl_renderbuffer *dsrb)
    s8rb->Width = dsrb->Width;
    s8rb->Height = dsrb->Height;
    s8rb->InternalFormat = GL_STENCIL_INDEX8_EXT;
+   s8rb->Format = MESA_FORMAT_S8;
    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;
@@ -460,90 +668,156 @@ _mesa_new_s8_renderbuffer_wrapper(GLcontext *ctx, struct gl_renderbuffer *dsrb)
 }
 
 
+
 /**
- * Merge data from a depth renderbuffer and a stencil renderbuffer into a
- * combined depth/stencil renderbuffer.
+ ** 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_merge_depth_stencil_buffers(GLcontext *ctx,
-                                  struct gl_renderbuffer *dest,
-                                  struct gl_renderbuffer *depth,
-                                  struct gl_renderbuffer *stencil)
+_mesa_extract_stencil(GLcontext *ctx,
+                      struct gl_renderbuffer *dsRb,
+                      struct gl_renderbuffer *stencilRb)
 {
-   GLuint depthVals[MAX_WIDTH];
-   GLubyte stencilVals[MAX_WIDTH];
-   GLuint combined[MAX_WIDTH];
-   GLuint row, width;
-
-   ASSERT(dest);
-   ASSERT(depth);
-   ASSERT(stencil);
-
-   ASSERT(dest->InternalFormat == GL_DEPTH24_STENCIL8_EXT);
-   ASSERT(dest->DataType == GL_UNSIGNED_INT_24_8_EXT);
-   ASSERT(depth->InternalFormat == GL_DEPTH_COMPONENT24);
-   ASSERT(depth->DataType == GL_UNSIGNED_INT);
-   ASSERT(stencil->InternalFormat == GL_STENCIL_INDEX8_EXT);
-   ASSERT(stencil->DataType == GL_UNSIGNED_BYTE);
-
-   ASSERT(dest->Width == depth->Width);
-   ASSERT(dest->Height == depth->Height);
-   ASSERT(dest->Width == stencil->Width);
-   ASSERT(dest->Height == stencil->Height);
-
-   width = dest->Width;
-   for (row = 0; row < dest->Height; row++) {
-      GLuint i;
-      depth->GetRow(ctx, depth, width, 0, row, depthVals);
-      stencil->GetRow(ctx, stencil, width, 0, row, stencilVals);
-      for (i = 0; i < width; i++) {
-         combined[i] = (depthVals[i] << 8) | stencilVals[i];
+   GLuint row, width, height;
+
+   ASSERT(dsRb);
+   ASSERT(stencilRb);
+
+   ASSERT(dsRb->Format == MESA_FORMAT_Z24_S8);
+   ASSERT(dsRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+   ASSERT(stencilRb->Format == MESA_FORMAT_Z24_S8 ||
+          stencilRb->Format == MESA_FORMAT_S8);
+   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->Format == MESA_FORMAT_S8) {
+         /* 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->Format == MESA_FORMAT_Z24_S8);
+         ASSERT(stencilRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+         stencilRb->PutRow(ctx, stencilRb, width, 0, row, depthStencil, NULL);
       }
-      dest->PutRow(ctx, dest, width, 0, row, combined, NULL);
    }
 }
 
 
 /**
- * Split combined depth/stencil renderbuffer data into separate depth/stencil
- * buffers.
+ * 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_split_depth_stencil_buffer(GLcontext *ctx,
-                                 struct gl_renderbuffer *source,
-                                 struct gl_renderbuffer *depth,
-                                 struct gl_renderbuffer *stencil)
+_mesa_insert_stencil(GLcontext *ctx,
+                     struct gl_renderbuffer *dsRb,
+                     struct gl_renderbuffer *stencilRb)
 {
-   GLuint depthVals[MAX_WIDTH];
-   GLubyte stencilVals[MAX_WIDTH];
-   GLuint combined[MAX_WIDTH];
-   GLuint row, width;
-
-   ASSERT(source);
-   ASSERT(depth);
-   ASSERT(stencil);
-
-   ASSERT(source->InternalFormat == GL_DEPTH24_STENCIL8_EXT);
-   ASSERT(source->DataType == GL_UNSIGNED_INT_24_8_EXT);
-   ASSERT(depth->InternalFormat == GL_DEPTH_COMPONENT24);
-   ASSERT(depth->DataType == GL_UNSIGNED_INT);
-   ASSERT(stencil->InternalFormat == GL_STENCIL_INDEX8_EXT);
-   ASSERT(stencil->DataType == GL_UNSIGNED_BYTE);
-
-   ASSERT(source->Width == depth->Width);
-   ASSERT(source->Height == depth->Height);
-   ASSERT(source->Width == stencil->Width);
-   ASSERT(source->Height == stencil->Height);
-
-   width = source->Width;
-   for (row = 0; row < source->Height; row++) {
-      GLuint i;
-      source->GetRow(ctx, source, width, 0, row, combined);
-      for (i = 0; i < width; i++) {
-         depthVals[i] = combined[i] >> 8;
-         stencilVals[i] = combined[i] & 0xff;
+   GLuint row, width, height;
+
+   ASSERT(dsRb);
+   ASSERT(stencilRb);
+
+   ASSERT(dsRb->Format == MESA_FORMAT_Z24_S8);
+   ASSERT(dsRb->DataType == GL_UNSIGNED_INT_24_8_EXT);
+   ASSERT(stencilRb->Format == MESA_FORMAT_Z24_S8 ||
+          stencilRb->Format == MESA_FORMAT_S8);
+
+   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->Format == MESA_FORMAT_S8) {
+         /* 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->Format == MESA_FORMAT_Z24_S8);
+         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->Format == MESA_FORMAT_S8);
+   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++];
       }
-      depth->PutRow(ctx, depth, width, 0, row, depthVals, NULL);
-      stencil->PutRow(ctx, stencil, width, 0, row, stencilVals, NULL);
+      stencilRb->PutRow(ctx, stencilRb, width, 0, i, depthStencil, NULL);
    }
+   _mesa_free(data);
 }