Move compiler.h and imports.h/c from src/mesa/main into src/util
[mesa.git] / src / mesa / swrast / s_clear.c
index 7b0a63391fa26fb81fc26e2b67f9194b4c67c8dd..158e5dace16fa28a6c3dde502837ce0ba3e3790f 100644 (file)
@@ -1,6 +1,5 @@
 /*
  * Mesa 3-D graphics library
- * Version:  7.1
  *
  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  *
  * 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.
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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 "main/glheader.h"
-#include "main/colormac.h"
+#include "main/accum.h"
 #include "main/condrender.h"
-#include "main/formats.h"
+#include "main/format_pack.h"
 #include "main/macros.h"
-#include "main/imports.h"
+#include "util/imports.h"
 #include "main/mtypes.h"
 
-#include "s_accum.h"
 #include "s_context.h"
 #include "s_depth.h"
-#include "s_masking.h"
 #include "s_stencil.h"
 
 
 /**
- * Clear the color buffer when glColorMask is in effect.
+ * Convert a boolean color mask to a packed color where each channel of
+ * the packed value at dst will be 0 or ~0 depending on the colorMask.
  */
 static void
-clear_rgba_buffer_with_masking(GLcontext *ctx, struct gl_renderbuffer *rb,
-                               GLuint buf)
+_pack_colormask(mesa_format format, const uint8_t colorMask[4], void *dst)
 {
-   const GLint x = ctx->DrawBuffer->_Xmin;
-   const GLint y = ctx->DrawBuffer->_Ymin;
-   const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
-   const GLint width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
-   SWspan span;
-   GLint i;
-
-   ASSERT(rb->PutRow);
-
-   /* Initialize color span with clear color */
-   /* XXX optimize for clearcolor == black/zero (bzero) */
-   INIT_SPAN(span, GL_BITMAP);
-   span.end = width;
-   span.arrayMask = SPAN_RGBA;
-   span.array->ChanType = rb->DataType;
-   if (span.array->ChanType == GL_UNSIGNED_BYTE) {
-      GLubyte clearColor[4];
-      UNCLAMPED_FLOAT_TO_UBYTE(clearColor[RCOMP], ctx->Color.ClearColor[0]);
-      UNCLAMPED_FLOAT_TO_UBYTE(clearColor[GCOMP], ctx->Color.ClearColor[1]);
-      UNCLAMPED_FLOAT_TO_UBYTE(clearColor[BCOMP], ctx->Color.ClearColor[2]);
-      UNCLAMPED_FLOAT_TO_UBYTE(clearColor[ACOMP], ctx->Color.ClearColor[3]);
-      for (i = 0; i < width; i++) {
-         COPY_4UBV(span.array->rgba[i], clearColor);
-      }
-   }
-   else if (span.array->ChanType == GL_UNSIGNED_SHORT) {
-      GLushort clearColor[4];
-      UNCLAMPED_FLOAT_TO_USHORT(clearColor[RCOMP], ctx->Color.ClearColor[0]);
-      UNCLAMPED_FLOAT_TO_USHORT(clearColor[GCOMP], ctx->Color.ClearColor[1]);
-      UNCLAMPED_FLOAT_TO_USHORT(clearColor[BCOMP], ctx->Color.ClearColor[2]);
-      UNCLAMPED_FLOAT_TO_USHORT(clearColor[ACOMP], ctx->Color.ClearColor[3]);
-      for (i = 0; i < width; i++) {
-         COPY_4V_CAST(span.array->rgba[i], clearColor, GLchan);
-      }
-   }
-   else {
-      ASSERT(span.array->ChanType == GL_FLOAT);
-      for (i = 0; i < width; i++) {
-         CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][0], ctx->Color.ClearColor[0]);
-         CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][1], ctx->Color.ClearColor[1]);
-         CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][2], ctx->Color.ClearColor[2]);
-         CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][3], ctx->Color.ClearColor[3]);
-      }
-   }
+   float maskColor[4];
+
+   switch (_mesa_get_format_datatype(format)) {
+   case GL_UNSIGNED_NORMALIZED:
+      /* simple: 1.0 will convert to ~0 in the right bit positions */
+      maskColor[0] = colorMask[0] ? 1.0f : 0.0f;
+      maskColor[1] = colorMask[1] ? 1.0f : 0.0f;
+      maskColor[2] = colorMask[2] ? 1.0f : 0.0f;
+      maskColor[3] = colorMask[3] ? 1.0f : 0.0f;
+      _mesa_pack_float_rgba_row(format, 1,
+                                (const float (*)[4]) maskColor, dst);
+      break;
+   case GL_SIGNED_NORMALIZED:
+   case GL_FLOAT:
+      /* These formats are harder because it's hard to know the floating
+       * point values that will convert to ~0 for each color channel's bits.
+       * This solution just generates a non-zero value for each color channel
+       * then fixes up the non-zero values to be ~0.
+       * Note: we'll need to add special case code if we ever have to deal
+       * with formats with unequal color channel sizes, like R11_G11_B10.
+       * We issue a warning below for channel sizes other than 8,16,32.
+       */
+      {
+         uint32_t bits = _mesa_get_format_max_bits(format); /* bits per chan */
+         uint32_t bytes = _mesa_get_format_bytes(format);
+         uint32_t i;
+
+         /* this should put non-zero values into the channels of dst */
+         maskColor[0] = colorMask[0] ? -1.0f : 0.0f;
+         maskColor[1] = colorMask[1] ? -1.0f : 0.0f;
+         maskColor[2] = colorMask[2] ? -1.0f : 0.0f;
+         maskColor[3] = colorMask[3] ? -1.0f : 0.0f;
+         _mesa_pack_float_rgba_row(format, 1,
+                                   (const float (*)[4]) maskColor, dst);
 
-   /* Note that masking will change the color values, but only the
-    * channels for which the write mask is GL_FALSE.  The channels
-    * which which are write-enabled won't get modified.
-    */
-   for (i = 0; i < height; i++) {
-      span.x = x;
-      span.y = y + i;
-      _swrast_mask_rgba_span(ctx, rb, &span, buf);
-      /* write masked row */
-      rb->PutRow(ctx, rb, width, x, y + i, span.array->rgba, NULL);
+         /* fix-up the dst channels by converting non-zero values to ~0 */
+         if (bits == 8) {
+            uint8_t *d = (uint8_t *) dst;
+            for (i = 0; i < bytes; i++) {
+               d[i] = d[i] ? 0xff : 0x0;
+            }
+         }
+         else if (bits == 16) {
+            uint16_t *d = (uint16_t *) dst;
+            for (i = 0; i < bytes / 2; i++) {
+               d[i] = d[i] ? 0xffff : 0x0;
+            }
+         }
+         else if (bits == 32) {
+            uint32_t *d = (uint32_t *) dst;
+            for (i = 0; i < bytes / 4; i++) {
+               d[i] = d[i] ? 0xffffffffU : 0x0;
+            }
+         }
+         else {
+            unreachable("unexpected size in _mesa_pack_colormask()");
+         }
+      }
+      break;
+   default:
+      unreachable("unexpected format data type in gen_color_mask()");
    }
 }
 
-
 /**
- * Clear an rgba color buffer without channel masking.
+ * Clear an rgba color buffer with masking if needed.
  */
 static void
-clear_rgba_buffer(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint buf)
+clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb,
+                  const GLubyte colorMask[4])
 {
    const GLint x = ctx->DrawBuffer->_Xmin;
    const GLint y = ctx->DrawBuffer->_Ymin;
    const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
    const GLint width  = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
-   GLubyte clear8[4];
-   GLushort clear16[4];
-   GLvoid *clearVal;
-   GLint i;
-
-   ASSERT(ctx->Color.ColorMask[buf][0] &&
-          ctx->Color.ColorMask[buf][1] &&
-          ctx->Color.ColorMask[buf][2] &&
-          ctx->Color.ColorMask[buf][3]);             
-
-   ASSERT(rb->PutMonoRow);
-
-   switch (rb->DataType) {
-      case GL_UNSIGNED_BYTE:
-         UNCLAMPED_FLOAT_TO_UBYTE(clear8[0], ctx->Color.ClearColor[0]);
-         UNCLAMPED_FLOAT_TO_UBYTE(clear8[1], ctx->Color.ClearColor[1]);
-         UNCLAMPED_FLOAT_TO_UBYTE(clear8[2], ctx->Color.ClearColor[2]);
-         UNCLAMPED_FLOAT_TO_UBYTE(clear8[3], ctx->Color.ClearColor[3]);
-         clearVal = clear8;
-         break;
-      case GL_UNSIGNED_SHORT:
-         UNCLAMPED_FLOAT_TO_USHORT(clear16[0], ctx->Color.ClearColor[0]);
-         UNCLAMPED_FLOAT_TO_USHORT(clear16[1], ctx->Color.ClearColor[1]);
-         UNCLAMPED_FLOAT_TO_USHORT(clear16[2], ctx->Color.ClearColor[2]);
-         UNCLAMPED_FLOAT_TO_USHORT(clear16[3], ctx->Color.ClearColor[3]);
-         clearVal = clear16;
-         break;
-      case GL_FLOAT:
-         clearVal = ctx->Color.ClearColor;
-         break;
-      default:
-         _mesa_problem(ctx, "Bad rb DataType in clear_color_buffer");
-         return;
+   const GLuint pixelSize = _mesa_get_format_bytes(rb->Format);
+   const GLboolean doMasking = (colorMask[0] == 0 ||
+                                colorMask[1] == 0 ||
+                                colorMask[2] == 0 ||
+                                colorMask[3] == 0);
+   const GLfloat (*clearColor)[4] =
+      (const GLfloat (*)[4]) ctx->Color.ClearColor.f;
+   GLbitfield mapMode = GL_MAP_WRITE_BIT;
+   GLubyte *map;
+   GLint rowStride;
+   GLint i, j;
+
+   if (doMasking) {
+      /* we'll need to read buffer values too */
+      mapMode |= GL_MAP_READ_BIT;
+   }
+
+   /* map dest buffer */
+   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
+                               mapMode, &map, &rowStride,
+                               ctx->DrawBuffer->FlipY);
+   if (!map) {
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(color)");
+      return;
    }
 
-   for (i = 0; i < height; i++) {
-      rb->PutMonoRow(ctx, rb, width, x, y + i, clearVal, NULL);
+   /* for 1, 2, 4-byte clearing */
+#define SIMPLE_TYPE_CLEAR(TYPE)                                         \
+   do {                                                                 \
+      TYPE pixel, pixelMask;                                            \
+      _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, &pixel);     \
+      if (doMasking) {                                                  \
+         _pack_colormask(rb->Format, colorMask, &pixelMask);            \
+         pixel &= pixelMask;                                            \
+         pixelMask = ~pixelMask;                                        \
+      }                                                                 \
+      for (i = 0; i < height; i++) {                                    \
+         TYPE *row = (TYPE *) map;                                      \
+         if (doMasking) {                                               \
+            for (j = 0; j < width; j++) {                               \
+               row[j] = (row[j] & pixelMask) | pixel;                   \
+            }                                                           \
+         }                                                              \
+         else {                                                         \
+            for (j = 0; j < width; j++) {                               \
+               row[j] = pixel;                                          \
+            }                                                           \
+         }                                                              \
+         map += rowStride;                                              \
+      }                                                                 \
+   } while (0)
+
+
+   /* for 3, 6, 8, 12, 16-byte clearing */
+#define MULTI_WORD_CLEAR(TYPE, N)                                       \
+   do {                                                                 \
+      TYPE pixel[N], pixelMask[N];                                      \
+      GLuint k;                                                         \
+      _mesa_pack_float_rgba_row(rb->Format, 1, clearColor, pixel);      \
+      if (doMasking) {                                                  \
+         _pack_colormask(rb->Format, colorMask, pixelMask);             \
+         for (k = 0; k < N; k++) {                                      \
+            pixel[k] &= pixelMask[k];                                   \
+            pixelMask[k] = ~pixelMask[k];                               \
+         }                                                              \
+      }                                                                 \
+      for (i = 0; i < height; i++) {                                    \
+         TYPE *row = (TYPE *) map;                                      \
+         if (doMasking) {                                               \
+            for (j = 0; j < width; j++) {                               \
+               for (k = 0; k < N; k++) {                                \
+                  row[j * N + k] =                                      \
+                     (row[j * N + k] & pixelMask[k]) | pixel[k];        \
+               }                                                        \
+            }                                                           \
+         }                                                              \
+         else {                                                         \
+            for (j = 0; j < width; j++) {                               \
+               for (k = 0; k < N; k++) {                                \
+                  row[j * N + k] = pixel[k];                            \
+               }                                                        \
+            }                                                           \
+         }                                                              \
+         map += rowStride;                                              \
+      }                                                                 \
+   } while(0)
+
+   switch (pixelSize) {
+   case 1:
+      SIMPLE_TYPE_CLEAR(GLubyte);
+      break;
+   case 2:
+      SIMPLE_TYPE_CLEAR(GLushort);
+      break;
+   case 3:
+      MULTI_WORD_CLEAR(GLubyte, 3);
+      break;
+   case 4:
+      SIMPLE_TYPE_CLEAR(GLuint);
+      break;
+   case 6:
+      MULTI_WORD_CLEAR(GLushort, 3);
+      break;
+   case 8:
+      MULTI_WORD_CLEAR(GLuint, 2);
+      break;
+   case 12:
+      MULTI_WORD_CLEAR(GLuint, 3);
+      break;
+   case 16:
+      MULTI_WORD_CLEAR(GLuint, 4);
+      break;
+   default:
+      _mesa_problem(ctx, "bad pixel size in clear_rgba_buffer()");
    }
+
+   /* unmap buffer */
+   ctx->Driver.UnmapRenderbuffer(ctx, rb);
 }
 
 
@@ -160,21 +244,27 @@ clear_rgba_buffer(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint buf)
  * clear its own color buffers for some reason (such as with masking).
  */
 static void
-clear_color_buffers(GLcontext *ctx)
+clear_color_buffers(struct gl_context *ctx)
 {
    GLuint buf;
 
    for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
       struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf];
-      if (ctx->Color.ColorMask[buf][0] == 0 ||
-          ctx->Color.ColorMask[buf][1] == 0 ||
-          ctx->Color.ColorMask[buf][2] == 0 ||
-          ctx->Color.ColorMask[buf][3] == 0) {
-         clear_rgba_buffer_with_masking(ctx, rb, buf);
-      }
-      else {
-         clear_rgba_buffer(ctx, rb, buf);
-      }
+
+      /* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
+       * the framebuffer can be complete with some attachments be missing.  In
+       * this case the _ColorDrawBuffers pointer will be NULL.
+       */
+      if (rb == NULL)
+        continue;
+
+      const GLubyte colormask[4] = {
+         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 0) ? 0xff : 0,
+         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 1) ? 0xff : 0,
+         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 2) ? 0xff : 0,
+         GET_COLORMASK_BIT(ctx->Color.ColorMask, buf, 3) ? 0xff : 0,
+      };
+      clear_rgba_buffer(ctx, rb, colormask);
    }
 }
 
@@ -187,8 +277,10 @@ clear_color_buffers(GLcontext *ctx)
  * \param all  if GL_TRUE, clear whole buffer, else clear specified region.
  */
 void
-_swrast_Clear(GLcontext *ctx, GLbitfield buffers)
+_swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
 {
+   const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
+
 #ifdef DEBUG_FOO
    {
       const GLbitfield legalBits =
@@ -207,25 +299,36 @@ _swrast_Clear(GLcontext *ctx, GLbitfield buffers)
    if (!_mesa_check_conditional_render(ctx))
       return; /* don't clear */
 
-   swrast_render_start(ctx);
+   if (SWRAST_CONTEXT(ctx)->NewState)
+      _swrast_validate_derived(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) {
-         _swrast_clear_accum_buffer(ctx,
-                       ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
+   if ((buffers & BUFFER_BITS_COLOR)
+       && (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
+      clear_color_buffers(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);
 }