Merge branch 'gallium-polygon-stipple'
[mesa.git] / src / mesa / swrast / s_readpix.c
index a1aeb2e01fbb8882685595e49f7a2287b11c5636..66ca39293a61ba8bcd22cb93aac8da5efddc316d 100644 (file)
 
 
 #include "main/glheader.h"
-#include "main/bufferobj.h"
 #include "main/colormac.h"
-#include "main/convolve.h"
-#include "main/context.h"
 #include "main/feedback.h"
+#include "main/formats.h"
 #include "main/image.h"
-#include "main/macros.h"
 #include "main/imports.h"
-#include "main/pixel.h"
+#include "main/macros.h"
+#include "main/pack.h"
+#include "main/pbo.h"
 #include "main/state.h"
 
 #include "s_context.h"
 #include "s_stencil.h"
 
 
-/*
- * Read a block of color index pixels.
- */
-static void
-read_index_pixels( GLcontext *ctx,
-                   GLint x, GLint y,
-                   GLsizei width, GLsizei height,
-                   GLenum type, GLvoid *pixels,
-                   const struct gl_pixelstore_attrib *packing )
-{
-   struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
-   GLint i;
-
-   if (!rb)
-      return;
-
-   /* width should never be > MAX_WIDTH since we did clipping earlier */
-   ASSERT(width <= MAX_WIDTH);
-
-   /* process image row by row */
-   for (i = 0; i < height; i++) {
-      GLuint index[MAX_WIDTH];
-      GLvoid *dest;
-      ASSERT(rb->DataType == GL_UNSIGNED_INT);
-      rb->GetRow(ctx, rb, width, x, y + i, index);
-
-      dest = _mesa_image_address2d(packing, pixels, width, height,
-                                   GL_COLOR_INDEX, type, i, 0);
-
-      _mesa_pack_index_span(ctx, width, type, dest, index,
-                            &ctx->Pack, ctx->_ImageTransferState);
-   }
-}
-
-
-
 /**
  * Read pixels for format=GL_DEPTH_COMPONENT.
  */
 static void
-read_depth_pixels( GLcontext *ctx,
+read_depth_pixels( struct gl_context *ctx,
                    GLint x, GLint y,
                    GLsizei width, GLsizei height,
                    GLenum type, GLvoid *pixels,
@@ -107,7 +70,7 @@ read_depth_pixels( GLcontext *ctx,
        && !biasOrScale && !packing->SwapBytes) {
       /* Special case: directly read 16-bit unsigned depth values. */
       GLint j;
-      ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT16);
+      ASSERT(rb->Format == MESA_FORMAT_Z16);
       ASSERT(rb->DataType == GL_UNSIGNED_SHORT);
       for (j = 0; j < height; j++, y++) {
          void *dest =_mesa_image_address2d(packing, pixels, width, height,
@@ -119,8 +82,12 @@ read_depth_pixels( GLcontext *ctx,
             && !biasOrScale && !packing->SwapBytes) {
       /* Special case: directly read 24-bit unsigned depth values. */
       GLint j;
-      ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT24);
-      ASSERT(rb->DataType == GL_UNSIGNED_INT);
+      ASSERT(rb->Format == MESA_FORMAT_X8_Z24 ||
+             rb->Format == MESA_FORMAT_S8_Z24 ||
+             rb->Format == MESA_FORMAT_Z24_X8 ||
+             rb->Format == MESA_FORMAT_Z24_S8);
+      ASSERT(rb->DataType == GL_UNSIGNED_INT ||
+             rb->DataType == GL_UNSIGNED_INT_24_8);
       for (j = 0; j < height; j++, y++) {
          GLuint *dest = (GLuint *)
             _mesa_image_address2d(packing, pixels, width, height,
@@ -128,9 +95,18 @@ read_depth_pixels( GLcontext *ctx,
          GLint k;
          rb->GetRow(ctx, rb, width, x, y, dest);
          /* convert range from 24-bit to 32-bit */
-         for (k = 0; k < width; k++) {
-            /* Note: put MSByte of 24-bit value into LSByte */
-            dest[k] = (dest[k] << 8) | ((dest[k] >> 16) & 0xff);
+         if (rb->Format == MESA_FORMAT_X8_Z24 ||
+             rb->Format == MESA_FORMAT_S8_Z24) {
+            for (k = 0; k < width; k++) {
+               /* Note: put MSByte of 24-bit value into LSByte */
+               dest[k] = (dest[k] << 8) | ((dest[k] >> 16) & 0xff);
+            }
+         }
+         else {
+            for (k = 0; k < width; k++) {
+               /* Note: fill in LSByte by replication */
+               dest[k] = dest[k] | ((dest[k] >> 8) & 0xff);
+            }
          }
       }
    }
@@ -138,7 +114,7 @@ read_depth_pixels( GLcontext *ctx,
             && !biasOrScale && !packing->SwapBytes) {
       /* Special case: directly read 32-bit unsigned depth values. */
       GLint j;
-      ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT32);
+      ASSERT(rb->Format == MESA_FORMAT_Z32);
       ASSERT(rb->DataType == GL_UNSIGNED_INT);
       for (j = 0; j < height; j++, y++) {
          void *dest = _mesa_image_address2d(packing, pixels, width, height,
@@ -164,7 +140,7 @@ read_depth_pixels( GLcontext *ctx,
  * Read pixels for format=GL_STENCIL_INDEX.
  */
 static void
-read_stencil_pixels( GLcontext *ctx,
+read_stencil_pixels( struct gl_context *ctx,
                      GLint x, GLint y,
                      GLsizei width, GLsizei height,
                      GLenum type, GLvoid *pixels,
@@ -202,7 +178,7 @@ read_stencil_pixels( GLcontext *ctx,
  * \return GL_TRUE if success, GL_FALSE if unable to do the readpixels
  */
 static GLboolean
-fast_read_rgba_pixels( GLcontext *ctx,
+fast_read_rgba_pixels( struct gl_context *ctx,
                        GLint x, GLint y,
                        GLsizei width, GLsizei height,
                        GLenum format, GLenum type,
@@ -215,7 +191,14 @@ fast_read_rgba_pixels( GLcontext *ctx,
    if (!rb)
       return GL_FALSE;
 
-   ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB);
+   ASSERT(rb->_BaseFormat == GL_RGBA ||
+         rb->_BaseFormat == GL_RGB ||
+         rb->_BaseFormat == GL_RG ||
+         rb->_BaseFormat == GL_RED ||
+         rb->_BaseFormat == GL_LUMINANCE ||
+         rb->_BaseFormat == GL_INTENSITY ||
+         rb->_BaseFormat == GL_LUMINANCE_ALPHA ||
+         rb->_BaseFormat == GL_ALPHA);
 
    /* clipping should have already been done */
    ASSERT(x + width <= (GLint) rb->Width);
@@ -276,22 +259,30 @@ fast_read_rgba_pixels( GLcontext *ctx,
 /**
  * When we're using a low-precision color buffer (like 16-bit 5/6/5)
  * we have to adjust our color values a bit to pass conformance.
- * The problem is when a 5 or 6-bit color value is convert to an 8-bit
+ * The problem is when a 5 or 6-bit color value is converted to an 8-bit
  * value and then a floating point value, the floating point values don't
  * increment uniformly as the 5 or 6-bit value is incremented.
  *
  * This function adjusts floating point values to compensate.
  */
 static void
-adjust_colors(GLcontext *ctx, GLuint n, GLfloat rgba[][4])
+adjust_colors(const struct gl_framebuffer *fb, GLuint n, GLfloat rgba[][4])
 {
-   const GLuint rShift = 8 - ctx->Visual.redBits;
-   const GLuint gShift = 8 - ctx->Visual.greenBits;
-   const GLuint bShift = 8 - ctx->Visual.blueBits;
-   const GLfloat rScale = 1.0F / (GLfloat) ((1 << ctx->Visual.redBits  ) - 1);
-   const GLfloat gScale = 1.0F / (GLfloat) ((1 << ctx->Visual.greenBits) - 1);
-   const GLfloat bScale = 1.0F / (GLfloat) ((1 << ctx->Visual.blueBits ) - 1);
+   const GLuint rShift = 8 - fb->Visual.redBits;
+   const GLuint gShift = 8 - fb->Visual.greenBits;
+   const GLuint bShift = 8 - fb->Visual.blueBits;
+   GLfloat rScale = 1.0F / (GLfloat) ((1 << fb->Visual.redBits  ) - 1);
+   GLfloat gScale = 1.0F / (GLfloat) ((1 << fb->Visual.greenBits) - 1);
+   GLfloat bScale = 1.0F / (GLfloat) ((1 << fb->Visual.blueBits ) - 1);
    GLuint i;
+
+   if (fb->Visual.redBits == 0)
+      rScale = 0;
+   if (fb->Visual.greenBits == 0)
+      gScale = 0;
+   if (fb->Visual.blueBits == 0)
+      bScale = 0;
+
    for (i = 0; i < n; i++) {
       GLint r, g, b;
       /* convert float back to ubyte */
@@ -313,7 +304,7 @@ adjust_colors(GLcontext *ctx, GLuint n, GLfloat rgba[][4])
  * Read R, G, B, A, RGB, L, or LA pixels.
  */
 static void
-read_rgba_pixels( GLcontext *ctx,
+read_rgba_pixels( struct gl_context *ctx,
                   GLint x, GLint y,
                   GLsizei width, GLsizei height,
                   GLenum format, GLenum type, GLvoid *pixels,
@@ -327,12 +318,12 @@ read_rgba_pixels( GLcontext *ctx,
    if (!rb)
       return;
 
-   if (type == GL_FLOAT && ((ctx->Color.ClampReadColor == GL_TRUE) ||
-                            (ctx->Color.ClampReadColor == GL_FIXED_ONLY_ARB &&
-                             rb->DataType != GL_FLOAT)))
+   if ((ctx->Color._ClampReadColor == GL_TRUE || type != GL_FLOAT) &&
+       !_mesa_is_integer_format(format)) {
       transferOps |= IMAGE_CLAMP_BIT;
+   }
 
-   /* Try optimized path first */
+   /* Try the optimized path first. */
    if (fast_read_rgba_pixels(ctx, x, y, width, height,
                              format, type, pixels, packing, transferOps)) {
       return; /* done! */
@@ -341,68 +332,7 @@ read_rgba_pixels( GLcontext *ctx,
    /* width should never be > MAX_WIDTH since we did clipping earlier */
    ASSERT(width <= MAX_WIDTH);
 
-   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
-      GLfloat *dest, *src, *tmpImage, *convImage;
-      GLint row;
-
-      tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
-      if (!tmpImage) {
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
-         return;
-      }
-      convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
-      if (!convImage) {
-         _mesa_free(tmpImage);
-         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
-         return;
-      }
-
-      /* read full RGBA, FLOAT image */
-      dest = tmpImage;
-      for (row = 0; row < height; row++, y++) {
-         if (fb->Visual.rgbMode) {
-            _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, dest);
-         }
-         else {
-            GLuint index[MAX_WIDTH];
-            ASSERT(rb->DataType == GL_UNSIGNED_INT);
-            rb->GetRow(ctx, rb, width, x, y, index);
-            _mesa_apply_ci_transfer_ops(ctx,
-                                        transferOps & IMAGE_SHIFT_OFFSET_BIT,
-                                        width, index);
-            _mesa_map_ci_to_rgba(ctx, width, index, (GLfloat (*)[4]) dest);
-         }
-         _mesa_apply_rgba_transfer_ops(ctx, 
-                                      transferOps & IMAGE_PRE_CONVOLUTION_BITS,
-                                      width, (GLfloat (*)[4]) dest);
-         dest += width * 4;
-      }
-
-      /* do convolution */
-      if (ctx->Pixel.Convolution2DEnabled) {
-         _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
-      }
-      else {
-         ASSERT(ctx->Pixel.Separable2DEnabled);
-         _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
-      }
-      _mesa_free(tmpImage);
-
-      /* finish transfer ops and pack the resulting image */
-      src = convImage;
-      for (row = 0; row < height; row++) {
-         GLvoid *dest;
-         dest = _mesa_image_address2d(packing, pixels, width, height,
-                                      format, type, row, 0);
-         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) src,
-                                    format, type, dest, packing,
-                                    transferOps & IMAGE_POST_CONVOLUTION_BITS);
-         src += width * 4;
-      }
-      _mesa_free(convImage);
-   }
-   else {
-      /* no convolution */
+   do {
       const GLint dstStride
          = _mesa_image_row_stride(packing, width, format, type);
       GLfloat (*rgba)[4] = swrast->SpanArrays->attribs[FRAG_ATTRIB_COL0];
@@ -411,32 +341,16 @@ read_rgba_pixels( GLcontext *ctx,
          = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
                                              format, type, 0, 0);
 
-      /* make sure we don't apply 1D convolution */
-      transferOps &= ~(IMAGE_CONVOLUTION_BIT |
-                       IMAGE_POST_CONVOLUTION_SCALE_BIAS);
-
       for (row = 0; row < height; row++, y++) {
 
          /* Get float rgba pixels */
-         if (fb->Visual.rgbMode) {
-            _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, rgba);
-         }
-         else {
-            /* read CI and convert to RGBA */
-            GLuint index[MAX_WIDTH];
-            ASSERT(rb->DataType == GL_UNSIGNED_INT);
-            rb->GetRow(ctx, rb, width, x, y, index);
-            _mesa_apply_ci_transfer_ops(ctx,
-                                        transferOps & IMAGE_SHIFT_OFFSET_BIT,
-                                        width, index);
-            _mesa_map_ci_to_rgba(ctx, width, index, rgba);
-         }
+         _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, rgba);
 
          /* apply fudge factor for shallow color buffers */
-         if (fb->Visual.redBits < 8 ||
-             fb->Visual.greenBits < 8 ||
-             fb->Visual.blueBits < 8) {
-            adjust_colors(ctx, width, rgba);
+         if ((fb->Visual.redBits < 8 && fb->Visual.redBits != 0) ||
+             (fb->Visual.greenBits < 8 && fb->Visual.greenBits != 0) ||
+            (fb->Visual.blueBits < 8 && fb->Visual.blueBits != 0)) {
+            adjust_colors(fb, width, rgba);
          }
 
          /* pack the row of RGBA pixels into user's buffer */
@@ -445,7 +359,7 @@ read_rgba_pixels( GLcontext *ctx,
 
          dst += dstStride;
       }
-   }
+   } while (0);
 }
 
 
@@ -455,7 +369,7 @@ read_rgba_pixels( GLcontext *ctx,
  * depth and stencil buffers really exist.
  */
 static void
-read_depth_stencil_pixels(GLcontext *ctx,
+read_depth_stencil_pixels(struct gl_context *ctx,
                           GLint x, GLint y,
                           GLsizei width, GLsizei height,
                           GLenum type, GLvoid *pixels,
@@ -532,7 +446,7 @@ read_depth_stencil_pixels(GLcontext *ctx,
             GLfloat depthVals[MAX_WIDTH];
             _swrast_read_depth_span_float(ctx, depthRb, width, x, y + i,
                                           depthVals);
-            _mesa_pack_depth_stencil_span(ctx, width, depthStencilDst,
+            _mesa_pack_depth_stencil_span(ctx, width, type, depthStencilDst,
                                           depthVals, stencilVals, packing);
          }
       }
@@ -546,7 +460,7 @@ read_depth_stencil_pixels(GLcontext *ctx,
  * By time we get here, all error checking will have been done.
  */
 void
-_swrast_ReadPixels( GLcontext *ctx,
+_swrast_ReadPixels( struct gl_context *ctx,
                    GLint x, GLint y, GLsizei width, GLsizei height,
                    GLenum format, GLenum type,
                    const struct gl_pixelstore_attrib *packing,
@@ -568,53 +482,33 @@ _swrast_ReadPixels( GLcontext *ctx,
       _swrast_validate_derived( ctx );
 
    /* Do all needed clipping here, so that we can forget about it later */
-   if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
-      /* The ReadPixels region is totally outside the window bounds */
-      swrast_render_finish(ctx);
-      return;
-   }
-
-   pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
-   if (!pixels)
-      return;
-  
-   switch (format) {
-      case GL_COLOR_INDEX:
-         read_index_pixels(ctx, x, y, width, height, type, pixels,
-                           &clippedPacking);
-        break;
-      case GL_STENCIL_INDEX:
-        read_stencil_pixels(ctx, x, y, width, height, type, pixels,
+   if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
+
+      pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
+
+      if (pixels) {
+         switch (format) {
+         case GL_STENCIL_INDEX:
+            read_stencil_pixels(ctx, x, y, width, height, type, pixels,
+                                &clippedPacking);
+            break;
+         case GL_DEPTH_COMPONENT:
+            read_depth_pixels(ctx, x, y, width, height, type, pixels,
+                              &clippedPacking);
+            break;
+         case GL_DEPTH_STENCIL_EXT:
+            read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels,
+                                      &clippedPacking);
+            break;
+         default:
+            /* all other formats should be color formats */
+            read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
                              &clippedPacking);
-         break;
-      case GL_DEPTH_COMPONENT:
-        read_depth_pixels(ctx, x, y, width, height, type, pixels,
-                           &clippedPacking);
-        break;
-      case GL_RED:
-      case GL_GREEN:
-      case GL_BLUE:
-      case GL_ALPHA:
-      case GL_RGB:
-      case GL_LUMINANCE:
-      case GL_LUMINANCE_ALPHA:
-      case GL_RGBA:
-      case GL_BGR:
-      case GL_BGRA:
-      case GL_ABGR_EXT:
-         read_rgba_pixels(ctx, x, y, width, height,
-                          format, type, pixels, &clippedPacking);
-        break;
-      case GL_DEPTH_STENCIL_EXT:
-         read_depth_stencil_pixels(ctx, x, y, width, height,
-                                   type, pixels, &clippedPacking);
-         break;
-      default:
-        _mesa_problem(ctx, "unexpected format in _swrast_ReadPixels");
-         /* don't return yet, clean-up */
+         }
+
+         _mesa_unmap_pbo_dest(ctx, &clippedPacking);
+      }
    }
 
    swrast_render_finish(ctx);
-
-   _mesa_unmap_pbo_dest(ctx, &clippedPacking);
 }