swrast: do depth/stencil clearing with Map/UnmapRenderbuffer()
authorBrian Paul <brianp@vmware.com>
Sat, 24 Dec 2011 15:54:25 +0000 (08:54 -0700)
committerBrian Paul <brianp@vmware.com>
Sat, 24 Dec 2011 15:54:25 +0000 (08:54 -0700)
Another step toward getting rid of the renderbuffer PutRow/etc functions.

v2: fix assorted depth/stencil clear bugs found by Eric

Reviewed-by: José Fonseca <jfonseca@vmware.com>
src/mesa/swrast/s_clear.c
src/mesa/swrast/s_depth.c
src/mesa/swrast/s_depth.h
src/mesa/swrast/s_stencil.c
src/mesa/swrast/s_stencil.h

index 851f6d165677d40a932e590a7ae108a96dbf3ddb..3566370053593d6c8f6f14f19a564973bbc629a8 100644 (file)
@@ -195,6 +195,8 @@ clear_color_buffers(struct gl_context *ctx)
 void
 _swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
 {
+   const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
+
 #ifdef DEBUG_FOO
    {
       const GLbitfield legalBits =
@@ -216,24 +218,39 @@ _swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
    if (SWRAST_CONTEXT(ctx)->NewState)
       _swrast_validate_derived(ctx);
 
-   swrast_render_start(ctx);
+   if ((buffers & BUFFER_BITS_COLOR)
+       && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
+      /* XXX remove the swrast_render_start/finish() calls after
+       * clear_color_buffers() is converted to use Map/UnmapRenderbuffer()
+       * The other clearing functions don't need these calls.
+       */
+      swrast_render_start(ctx);
+      clear_color_buffers(ctx);
+      swrast_render_finish(ctx);
+   }
 
-   /* do software clearing here */
-   if (buffers) {
-      if ((buffers & BUFFER_BITS_COLOR)
-          && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
-         clear_color_buffers(ctx);
-      }
-      if (buffers & BUFFER_BIT_DEPTH) {
-         _swrast_clear_depth_buffer(ctx, ctx->DrawBuffer->_DepthBuffer);
-      }
-      if (buffers & BUFFER_BIT_ACCUM) {
-         _mesa_clear_accum_buffer(ctx);
+   if (buffers & BUFFER_BIT_ACCUM) {
+      _mesa_clear_accum_buffer(ctx);
+   }
+
+   if (buffers & BUFFER_DS) {
+      struct gl_renderbuffer *depthRb =
+         ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+      struct gl_renderbuffer *stencilRb =
+         ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
+
+      if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) {
+         /* clear depth and stencil together */
+         _swrast_clear_depth_stencil_buffer(ctx);
       }
-      if (buffers & BUFFER_BIT_STENCIL) {
-         _swrast_clear_stencil_buffer(ctx, ctx->DrawBuffer->_StencilBuffer);
+      else {
+         /* clear depth, stencil separately */
+         if (buffers & BUFFER_BIT_DEPTH) {
+            _swrast_clear_depth_buffer(ctx);
+         }
+         if (buffers & BUFFER_BIT_STENCIL) {
+            _swrast_clear_stencil_buffer(ctx);
+         }
       }
    }
-
-   swrast_render_finish(ctx);
 }
index 8d3ad105bce81f7816f5864fc0314e2e441b7719..09c0be68f07b2962a1c969f942a8a9478527727c 100644 (file)
@@ -26,6 +26,7 @@
 #include "main/glheader.h"
 #include "main/context.h"
 #include "main/formats.h"
+#include "main/format_pack.h"
 #include "main/macros.h"
 #include "main/imports.h"
 
@@ -1312,14 +1313,21 @@ _swrast_read_depth_span_float( struct gl_context *ctx, struct gl_renderbuffer *r
    }
 }
 
+
 /**
- * Clear the given z/depth renderbuffer.
+ * Clear the given z/depth renderbuffer.  If the buffer is a combined
+ * depth+stencil buffer, only the Z bits will be touched.
  */
 void
-_swrast_clear_depth_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb )
+_swrast_clear_depth_buffer(struct gl_context *ctx)
 {
+   struct gl_renderbuffer *rb =
+      ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
    GLuint clearValue;
    GLint x, y, width, height;
+   GLubyte *map;
+   GLint rowStride, i, j;
+   GLbitfield mapMode;
 
    if (!rb || !ctx->Depth.Mask) {
       /* no depth buffer, or writing to it is disabled */
@@ -1334,67 +1342,218 @@ _swrast_clear_depth_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb )
       clearValue = (GLuint) (ctx->Depth.Clear * ctx->DrawBuffer->_DepthMaxF);
    }
 
-   assert(rb->_BaseFormat == GL_DEPTH_COMPONENT);
-
    /* compute region to clear */
    x = ctx->DrawBuffer->_Xmin;
    y = ctx->DrawBuffer->_Ymin;
    width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
    height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
 
-   if (rb->GetPointer(ctx, rb, 0, 0)) {
-      /* Direct buffer access is possible.  Either this is just malloc'd
-       * memory, or perhaps the driver mmap'd the zbuffer memory.
-       */
-      if (rb->DataType == GL_UNSIGNED_SHORT) {
-         if ((clearValue & 0xff) == ((clearValue >> 8) & 0xff) &&
-             ((GLushort *) rb->GetPointer(ctx, rb, 0, 0) + width ==
-              (GLushort *) rb->GetPointer(ctx, rb, 0, 1))) {
-            /* optimized case */
-            GLushort *dst = (GLushort *) rb->GetPointer(ctx, rb, x, y);
-            GLuint len = width * height * sizeof(GLushort);
-            memset(dst, (clearValue & 0xff), len);
+   mapMode = GL_MAP_WRITE_BIT;
+   if (rb->Format == MESA_FORMAT_S8_Z24 ||
+       rb->Format == MESA_FORMAT_X8_Z24 ||
+       rb->Format == MESA_FORMAT_Z24_S8 ||
+       rb->Format == MESA_FORMAT_Z24_X8) {
+      mapMode |= GL_MAP_READ_BIT;
+   }
+
+   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
+                               mapMode, &map, &rowStride);
+   if (!map) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth)");
+      return;
+   }
+
+   switch (rb->Format) {
+   case MESA_FORMAT_Z16:
+      {
+         GLfloat clear = (GLfloat) ctx->Depth.Clear;
+         GLushort clearVal = 0;
+         _mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal);
+         if (clearVal == 0xffff && width * 2 == rowStride) {
+            /* common case */
+            memset(map, 0xff, width * height * 2);
          }
          else {
-            /* general case */
-            GLint i, j;
             for (i = 0; i < height; i++) {
-               GLushort *dst = (GLushort *) rb->GetPointer(ctx, rb, x, y + i);
+               GLushort *row = (GLushort *) map;
                for (j = 0; j < width; j++) {
-                  dst[j] = clearValue;
+                  row[j] = clearVal;
                }
+               map += rowStride;
             }
          }
       }
-      else {
-         GLint i, j;
-         ASSERT(rb->DataType == GL_UNSIGNED_INT);
+      break;
+   case MESA_FORMAT_Z32:
+   case MESA_FORMAT_Z32_FLOAT:
+      {
+         GLfloat clear = (GLfloat) ctx->Depth.Clear;
+         GLuint clearVal = 0;
+         _mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal);
          for (i = 0; i < height; i++) {
-            GLuint *dst = (GLuint *) rb->GetPointer(ctx, rb, x, y + i);
+            GLuint *row = (GLuint *) map;
             for (j = 0; j < width; j++) {
-               dst[j] = clearValue;
+               row[j] = clearVal;
             }
+            map += rowStride;
          }
       }
-   }
-   else {
-      /* Direct access not possible.  Use PutRow to write new values. */
-      if (rb->DataType == GL_UNSIGNED_SHORT) {
-         GLushort clearVal16 = (GLushort) (clearValue & 0xffff);
-         GLint i;
+      break;
+   case MESA_FORMAT_S8_Z24:
+   case MESA_FORMAT_X8_Z24:
+   case MESA_FORMAT_Z24_S8:
+   case MESA_FORMAT_Z24_X8:
+      {
+         GLfloat clear = (GLfloat) ctx->Depth.Clear;
+         GLuint clearVal = 0;
+         GLuint mask;
+
+         if (rb->Format == MESA_FORMAT_S8_Z24 ||
+             rb->Format == MESA_FORMAT_X8_Z24)
+            mask = 0xff000000;
+         else
+            mask = 0xff;
+
+         _mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal);
          for (i = 0; i < height; i++) {
-            rb->PutMonoRow(ctx, rb, width, x, y + i, &clearVal16, NULL);
+            GLuint *row = (GLuint *) map;
+            for (j = 0; j < width; j++) {
+               row[j] = (row[j] & mask) | clearVal;
+            }
+            map += rowStride;
          }
+
       }
-      else if (rb->DataType == GL_UNSIGNED_INT) {
-         GLint i;
-         ASSERT(sizeof(clearValue) == sizeof(GLuint));
+      break;
+   case MESA_FORMAT_Z32_FLOAT_X24S8:
+      /* XXX untested */
+      {
+         GLfloat clearVal = (GLfloat) ctx->Depth.Clear;
          for (i = 0; i < height; i++) {
-            rb->PutMonoRow(ctx, rb, width, x, y + i, &clearValue, NULL);
+            GLfloat *row = (GLfloat *) map;
+            for (j = 0; j < width; j++) {
+               row[j * 2] = clearVal;
+            }
+            map += rowStride;
          }
       }
-      else {
-         _mesa_problem(ctx, "bad depth renderbuffer DataType");
+      break;
+   default:
+      _mesa_problem(ctx, "Unexpected depth buffer format %s"
+                    " in _swrast_clear_depth_buffer()",
+                    _mesa_get_format_name(rb->Format));
+   }
+
+   ctx->Driver.UnmapRenderbuffer(ctx, rb);
+}
+
+
+
+
+/**
+ * Clear both depth and stencil values in a combined depth+stencil buffer.
+ */
+void
+_swrast_clear_depth_stencil_buffer(struct gl_context *ctx)
+{
+   const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits;
+   const GLuint writeMask = ctx->Stencil.WriteMask[0];
+   const GLuint stencilMax = (1 << stencilBits) - 1;
+   struct gl_renderbuffer *rb =
+      ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+   GLint x, y, width, height;
+   GLbitfield mapMode;
+   GLubyte *map;
+   GLint rowStride, i, j;
+
+   /* check that we really have a combined depth+stencil buffer */
+   assert(rb == ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer);
+
+   /* compute region to clear */
+   x = ctx->DrawBuffer->_Xmin;
+   y = ctx->DrawBuffer->_Ymin;
+   width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
+   height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
+
+   mapMode = GL_MAP_WRITE_BIT;
+   if ((writeMask & stencilMax) != stencilMax) {
+      /* need to mask stencil values */
+      mapMode |= GL_MAP_READ_BIT;
+   }
+
+   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
+                               mapMode, &map, &rowStride);
+   if (!map) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth+stencil)");
+      return;
+   }
+
+   switch (rb->Format) {
+   case MESA_FORMAT_S8_Z24:
+   case MESA_FORMAT_Z24_S8:
+      {
+         GLfloat zClear = (GLfloat) ctx->Depth.Clear;
+         GLuint clear = 0, mask;
+
+         _mesa_pack_float_z_row(rb->Format, 1, &zClear, &clear);
+
+         if (rb->Format == MESA_FORMAT_S8_Z24) {
+            mask = ((~writeMask) & 0xff) << 24;
+            clear |= (ctx->Stencil.Clear & writeMask & 0xff) << 24;
+         }
+         else {
+            mask = ((~writeMask) & 0xff);
+            clear |= (ctx->Stencil.Clear & writeMask & 0xff);
+         }
+
+         for (i = 0; i < height; i++) {
+            GLuint *row = (GLuint *) map;
+            if (mask != 0x0) {
+               for (j = 0; j < width; j++) {
+                  row[j] = (row[j] & mask) | clear;
+               }
+            }
+            else {
+               for (j = 0; j < width; j++) {
+                  row[j] = clear;
+               }
+            }
+            map += rowStride;
+         }
+      }
+      break;
+   case MESA_FORMAT_Z32_FLOAT_X24S8:
+      /* XXX untested */
+      {
+         const GLfloat zClear = (GLfloat) ctx->Depth.Clear;
+         const GLuint sClear = ctx->Stencil.Clear & writeMask;
+         const GLuint sMask = (~writeMask) & 0xff;
+         for (i = 0; i < height; i++) {
+            GLfloat *zRow = (GLfloat *) map;
+            GLuint *sRow = (GLuint *) map;
+            for (j = 0; j < width; j++) {
+               zRow[j * 2 + 0] = zClear;
+            }
+            if (sMask != 0) {
+               for (j = 0; j < width; j++) {
+                  sRow[j * 2 + 1] = (sRow[j * 2 + 1] & sMask) | sClear;
+               }
+            }
+            else {
+               for (j = 0; j < width; j++) {
+                  sRow[j * 2 + 1] = sClear;
+               }
+            }
+            map += rowStride;
+         }
       }
+      break;
+   default:
+      _mesa_problem(ctx, "Unexpected depth buffer format %s"
+                    " in _swrast_clear_depth_buffer()",
+                    _mesa_get_format_name(rb->Format));
    }
+
+   ctx->Driver.UnmapRenderbuffer(ctx, rb);
+
 }
index 2caea82e081d868607af2c1f5e083c528e167c8e..25a7a0bbf83cdc5cf0941b080a15d201cf32d497 100644 (file)
@@ -49,7 +49,10 @@ _swrast_read_depth_span_float( struct gl_context *ctx, struct gl_renderbuffer *r
                                GLint n, GLint x, GLint y, GLfloat depth[] );
 
 extern void
-_swrast_clear_depth_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb );
+_swrast_clear_depth_buffer(struct gl_context *ctx);
+
+extern void
+_swrast_clear_depth_stencil_buffer(struct gl_context *ctx);
 
 
 #endif
index 101ee50567170857fa1f1dab901cd79bc48edf36..5f81fe8ec73381f6cce91fcd3865320259cdb785 100644 (file)
@@ -1124,121 +1124,107 @@ _swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y,
 
 
 /**
- * Clear the stencil buffer.
+ * Clear the stencil buffer.  If the buffer is a combined
+ * depth+stencil buffer, only the stencil bits will be touched.
  */
 void
-_swrast_clear_stencil_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb )
+_swrast_clear_stencil_buffer(struct gl_context *ctx)
 {
+   struct gl_renderbuffer *rb =
+      ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
    const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits;
-   const GLuint mask = ctx->Stencil.WriteMask[0];
-   const GLuint invMask = ~mask;
-   const GLuint clearVal = (ctx->Stencil.Clear & mask);
+   const GLuint writeMask = ctx->Stencil.WriteMask[0];
    const GLuint stencilMax = (1 << stencilBits) - 1;
    GLint x, y, width, height;
+   GLubyte *map;
+   GLint rowStride, i, j;
+   GLbitfield mapMode;
 
-   if (!rb || mask == 0)
+   if (!rb || writeMask == 0)
       return;
 
-   ASSERT(rb->DataType == GL_UNSIGNED_BYTE ||
-          rb->DataType == GL_UNSIGNED_SHORT);
-
-   ASSERT(rb->_BaseFormat == GL_STENCIL_INDEX);
-
    /* compute region to clear */
    x = ctx->DrawBuffer->_Xmin;
    y = ctx->DrawBuffer->_Ymin;
    width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
    height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
 
-   if (rb->GetPointer(ctx, rb, 0, 0)) {
-      /* Direct buffer access */
-      if ((mask & stencilMax) != stencilMax) {
-         /* need to mask the clear */
-         if (rb->DataType == GL_UNSIGNED_BYTE) {
-            GLint i, j;
-            for (i = 0; i < height; i++) {
-               GLubyte *stencil = (GLubyte*) rb->GetPointer(ctx, rb, x, y + i);
-               for (j = 0; j < width; j++) {
-                  stencil[j] = (stencil[j] & invMask) | clearVal;
-               }
-            }
-         }
-         else {
-            GLint i, j;
+   mapMode = GL_MAP_WRITE_BIT;
+   if ((writeMask & stencilMax) != stencilMax) {
+      /* need to mask stencil values */
+      mapMode |= GL_MAP_READ_BIT;
+   }
+   else if (_mesa_get_format_bits(rb->Format, GL_DEPTH_BITS) > 0) {
+      /* combined depth+stencil, need to mask Z values */
+      mapMode |= GL_MAP_READ_BIT;
+   }
+
+   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
+                               mapMode, &map, &rowStride);
+   if (!map) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(stencil)");
+      return;
+   }
+
+   switch (rb->Format) {
+   case MESA_FORMAT_S8:
+      {
+         GLubyte clear = ctx->Stencil.Clear & writeMask & 0xff;
+         GLubyte mask = (~writeMask) & 0xff;
+         if (mask != 0) {
+            /* masked clear */
             for (i = 0; i < height; i++) {
-               GLushort *stencil = (GLushort*) rb->GetPointer(ctx, rb, x, y + i);
+               GLubyte *row = map;
                for (j = 0; j < width; j++) {
-                  stencil[j] = (stencil[j] & invMask) | clearVal;
+                  row[j] = (row[j] & mask) | clear;
                }
+               map += rowStride;
             }
          }
-      }
-      else {
-         /* no bit masking */
-         if (width == (GLint) rb->Width && rb->DataType == GL_UNSIGNED_BYTE) {
-            /* optimized case */
-            /* Note: bottom-to-top raster assumed! */
-            GLubyte *stencil = (GLubyte *) rb->GetPointer(ctx, rb, x, y);
-            GLuint len = width * height * sizeof(GLubyte);
-            memset(stencil, clearVal, len);
+         else if (rowStride == width) {
+            /* clear whole buffer */
+            memset(map, clear, width * height);
          }
          else {
-            /* general case */
-            GLint i;
+            /* clear scissored */
             for (i = 0; i < height; i++) {
-               GLvoid *stencil = rb->GetPointer(ctx, rb, x, y + i);
-               if (rb->DataType == GL_UNSIGNED_BYTE) {
-                  memset(stencil, clearVal, width);
-               }
-               else {
-                  _mesa_memset16((short unsigned int*) stencil, clearVal, width);
-               }
+               memset(map, clear, width);
+               map += rowStride;
             }
          }
       }
-   }
-   else {
-      /* no direct access */
-      if ((mask & stencilMax) != stencilMax) {
-         /* need to mask the clear */
-         if (rb->DataType == GL_UNSIGNED_BYTE) {
-            GLint i, j;
-            for (i = 0; i < height; i++) {
-               GLubyte stencil[MAX_WIDTH];
-               rb->GetRow(ctx, rb, width, x, y + i, stencil);
-               for (j = 0; j < width; j++) {
-                  stencil[j] = (stencil[j] & invMask) | clearVal;
-               }
-               rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL);
-            }
-         }
-         else {
-            GLint i, j;
-            for (i = 0; i < height; i++) {
-               GLushort stencil[MAX_WIDTH];
-               rb->GetRow(ctx, rb, width, x, y + i, stencil);
-               for (j = 0; j < width; j++) {
-                  stencil[j] = (stencil[j] & invMask) | clearVal;
-               }
-               rb->PutRow(ctx, rb, width, x, y + i, stencil, NULL);
+      break;
+   case MESA_FORMAT_S8_Z24:
+      {
+         GLuint clear = (ctx->Stencil.Clear & writeMask & 0xff) << 24;
+         GLuint mask = (((~writeMask) & 0xff) << 24) | 0xffffff;
+         for (i = 0; i < height; i++) {
+            GLuint *row = (GLuint *) map;
+            for (j = 0; j < width; j++) {
+               row[j] = (row[j] & mask) | clear;
             }
+            map += rowStride;
          }
       }
-      else {
-         /* no bit masking */
-         const GLubyte clear8 = (GLubyte) clearVal;
-         const GLushort clear16 = (GLushort) clearVal;
-         const void *clear;
-         GLint i;
-         if (rb->DataType == GL_UNSIGNED_BYTE) {
-            clear = &clear8;
-         }
-         else {
-            clear = &clear16;
-         }
+      break;
+   case MESA_FORMAT_Z24_S8:
+      {
+         GLuint clear = ctx->Stencil.Clear & writeMask & 0xff;
+         GLuint mask = 0xffffff00 | ((~writeMask) & 0xff);
          for (i = 0; i < height; i++) {
-            rb->PutMonoRow(ctx, rb, width, x, y + i, clear, NULL);
+            GLuint *row = (GLuint *) map;
+            for (j = 0; j < width; j++) {
+               row[j] = (row[j] & mask) | clear;
+            }
+            map += rowStride;
          }
       }
+      break;
+   default:
+      _mesa_problem(ctx, "Unexpected stencil buffer format %s"
+                    " in _swrast_clear_stencil_buffer()",
+                    _mesa_get_format_name(rb->Format));
    }
+
+   ctx->Driver.UnmapRenderbuffer(ctx, rb);
 }
index 37f3c8da14777d0480ad5445ed1c6fdf09f5fa99..113649a375ce1793061ac6e406de47db1912e065 100644 (file)
@@ -47,7 +47,7 @@ _swrast_write_stencil_span( struct gl_context *ctx, GLint n, GLint x, GLint y,
 
 
 extern void
-_swrast_clear_stencil_buffer( struct gl_context *ctx, struct gl_renderbuffer *rb );
+_swrast_clear_stencil_buffer(struct gl_context *ctx);
 
 
 #endif