check for framebuffer completeness, code clean-up
[mesa.git] / src / mesa / main / image.c
index 17737cafcfd31b1fd9eae90e7f7f37ccbb79e167..b6841d7a13612cbe65eea6bba066707b1987777d 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.3
+ * Version:  6.5
  *
- * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2005  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"),
@@ -30,7 +30,6 @@
 
 
 #include "glheader.h"
-#include "bufferobj.h"
 #include "colormac.h"
 #include "context.h"
 #include "image.h"
@@ -38,7 +37,6 @@
 #include "histogram.h"
 #include "macros.h"
 #include "pixel.h"
-#include "mtypes.h"
 
 
 /** Compute ceiling of integer quotient of A divided by B. */
@@ -201,7 +199,9 @@ GLint _mesa_sizeof_packed_type( GLenum type )
          return sizeof(GLuint);
       case GL_UNSIGNED_SHORT_8_8_MESA:
       case GL_UNSIGNED_SHORT_8_8_REV_MESA:
-          return sizeof(GLushort);      
+         return sizeof(GLushort);      
+      case GL_UNSIGNED_INT_24_8_EXT:
+         return sizeof(GLuint);
       default:
          return -1;
    }
@@ -248,6 +248,8 @@ GLint _mesa_components_in_format( GLenum format )
          return 4;
       case GL_YCBCR_MESA:
          return 2;
+      case GL_DEPTH_STENCIL_EXT:
+         return 2;
       default:
          return -1;
    }
@@ -318,6 +320,11 @@ GLint _mesa_bytes_per_pixel( GLenum format, GLenum type )
             return sizeof(GLushort);
          else
             return -1;
+      case GL_UNSIGNED_INT_24_8_EXT:
+         if (format == GL_DEPTH_STENCIL_EXT)
+            return sizeof(GLuint);
+         else
+            return -1;
       default:
          return -1;
    }
@@ -443,6 +450,12 @@ _mesa_is_legal_format_and_type( GLcontext *ctx, GLenum format, GLenum type )
             return GL_TRUE;
          else
             return GL_FALSE;
+      case GL_DEPTH_STENCIL_EXT:
+         if (ctx->Extensions.EXT_packed_depth_stencil
+             && type == GL_UNSIGNED_INT_24_8_EXT)
+            return GL_TRUE;
+         else
+            return GL_FALSE;
       default:
          ; /* fall-through */
    }
@@ -451,31 +464,31 @@ _mesa_is_legal_format_and_type( GLcontext *ctx, GLenum format, GLenum type )
 
 
 /**
- * Get the address of a pixel in an image (actually a volume).
+ * Return the address of a specific pixel in an image (1D, 2D or 3D).
  *
  * Pixel unpacking/packing parameters are observed according to \p packing.
  *
- * \param image start of image data.
- * \param width image width.
- * \param height image height.
- * \param format pixel format.
- * \param type pixel data type.
- * \param packing the pixelstore attributes
- * \param img which image in the volume (0 for 1D or 2D images)
- * \param row of pixel in the image
- * \param column of pixel in the image
+ * \param dimensions either 1, 2 or 3 to indicate dimensionality of image
+ * \param image  starting address of image data
+ * \param width  the image width
+ * \param height  theimage height
+ * \param format  the pixel format
+ * \param type  the pixel data type
+ * \param packing  the pixelstore attributes
+ * \param img  which image in the volume (0 for 1D or 2D images)
+ * \param row  row of pixel in the image (0 for 1D images)
+ * \param column column of pixel in the image
  * 
  * \return address of pixel on success, or NULL on error.
  *
- * According to the \p packing information calculates the number of pixel/bytes
- * per row/image and refers it.
- *
  * \sa gl_pixelstore_attrib.
  */
 GLvoid *
-_mesa_image_address( const struct gl_pixelstore_attrib *packing,
-                     const GLvoid *image, GLsizei width,
-                     GLsizei height, GLenum format, GLenum type,
+_mesa_image_address( GLuint dimensions,
+                     const struct gl_pixelstore_attrib *packing,
+                     const GLvoid *image,
+                     GLsizei width, GLsizei height,
+                     GLenum format, GLenum type,
                      GLint img, GLint row, GLint column )
 {
    GLint alignment;        /* 1, 2 or 4 */
@@ -486,6 +499,8 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing,
    GLint skipimages;       /* for 3-D volume images */
    GLubyte *pixel_addr;
 
+   ASSERT(dimensions >= 1 && dimensions <= 3);
+
    alignment = packing->Alignment;
    if (packing->RowLength > 0) {
       pixels_per_row = packing->RowLength;
@@ -499,9 +514,12 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing,
    else {
       rows_per_image = height;
    }
-   skiprows = packing->SkipRows;
+
    skippixels = packing->SkipPixels;
-   skipimages = packing->SkipImages;
+   /* Note: SKIP_ROWS _is_ used for 1D images */
+   skiprows = packing->SkipRows;
+   /* Note: SKIP_IMAGES is only used for 3D images */
+   skipimages = (dimensions == 3) ? packing->SkipImages : 0;
 
    if (type == GL_BITMAP) {
       /* BITMAP data */
@@ -572,6 +590,43 @@ _mesa_image_address( const struct gl_pixelstore_attrib *packing,
 }
 
 
+GLvoid *
+_mesa_image_address1d( const struct gl_pixelstore_attrib *packing,
+                       const GLvoid *image,
+                       GLsizei width,
+                       GLenum format, GLenum type,
+                       GLint column )
+{
+   return _mesa_image_address(1, packing, image, width, 1,
+                              format, type, 0, 0, column);
+}
+
+
+GLvoid *
+_mesa_image_address2d( const struct gl_pixelstore_attrib *packing,
+                       const GLvoid *image,
+                       GLsizei width, GLsizei height,
+                       GLenum format, GLenum type,
+                       GLint row, GLint column )
+{
+   return _mesa_image_address(2, packing, image, width, height,
+                              format, type, 0, row, column);
+}
+
+
+GLvoid *
+_mesa_image_address3d( const struct gl_pixelstore_attrib *packing,
+                       const GLvoid *image,
+                       GLsizei width, GLsizei height,
+                       GLenum format, GLenum type,
+                       GLint img, GLint row, GLint column )
+{
+   return _mesa_image_address(3, packing, image, width, height,
+                              format, type, img, row, column);
+}
+
+
+
 /**
  * Compute the stride between image rows.
  *
@@ -744,8 +799,8 @@ _mesa_unpack_bitmap( GLint width, GLint height, const GLubyte *pixels,
    dst = buffer;
    for (row = 0; row < height; row++) {
       const GLubyte *src = (const GLubyte *)
-         _mesa_image_address(packing, pixels, width, height,
-                             GL_COLOR_INDEX, GL_BITMAP, 0, row, 0);
+         _mesa_image_address2d(packing, pixels, width, height,
+                               GL_COLOR_INDEX, GL_BITMAP, row, 0);
       if (!src) {
          FREE(buffer);
          return NULL;
@@ -838,8 +893,8 @@ _mesa_pack_bitmap( GLint width, GLint height, const GLubyte *source,
    width_in_bytes = CEILING( width, 8 );
    src = source;
    for (row = 0; row < height; row++) {
-      GLubyte *dst = (GLubyte *) _mesa_image_addresspacking, dest,
-                       width, height, GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 );
+      GLubyte *dst = (GLubyte *) _mesa_image_address2d(packing, dest,
+                       width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0);
       if (!dst)
          return;
 
@@ -1007,18 +1062,14 @@ _mesa_pack_rgba_span_float( GLcontext *ctx,
 
    if (transferOps) {
       /* make copy of incoming data */
-      DEFMARRAY(GLfloat, rgbaCopy, MAX_WIDTH, 4);  /* mac 32k limitation */
-      CHECKARRAY(rgbaCopy, return);  /* mac 32k limitation */
-
+      GLfloat rgbaCopy[MAX_WIDTH][4];
       _mesa_memcpy(rgbaCopy, rgbaIn, n * 4 * sizeof(GLfloat));
       _mesa_apply_rgba_transfer_ops(ctx, transferOps, n, rgbaCopy);
       rgba = (const GLfloat (*)[4]) rgbaCopy;
 
       if ((transferOps & IMAGE_MIN_MAX_BIT) && ctx->MinMax.Sink) {
-         UNDEFARRAY(rgbaCopy);  /* mac 32k limitation */
          return;
       }
-      UNDEFARRAY(rgbaCopy);  /* mac 32k limitation */
    }
    else {
       /* use incoming data, not a copy */
@@ -1978,9 +2029,7 @@ _mesa_pack_rgba_span_chan( GLcontext *ctx,
    else {
       /* general solution */
       GLuint i;
-      DEFMARRAY(GLfloat, rgba, MAX_WIDTH, 4);  /* mac 32k limitation */
-      CHECKARRAY(rgba, return);  /* mac 32k limitation */
-
+      GLfloat rgba[MAX_WIDTH][4];
       assert(n <= MAX_WIDTH);
       /* convert color components to floating point */
       for (i = 0; i < n; i++) {
@@ -1992,7 +2041,6 @@ _mesa_pack_rgba_span_chan( GLcontext *ctx,
       _mesa_pack_rgba_span_float(ctx, n, (const GLfloat (*)[4]) rgba,
                                  dstFormat, dstType, dstAddr,
                                  dstPacking, transferOps);
-      UNDEFARRAY(rgba);  /* mac 32k limitation */
    }
 }
 
@@ -2031,6 +2079,7 @@ extract_uint_indexes(GLuint n, GLuint indexes[],
           srcType == GL_SHORT ||
           srcType == GL_UNSIGNED_INT ||
           srcType == GL_INT ||
+          srcType == GL_UNSIGNED_INT_24_8_EXT ||
           srcType == GL_HALF_FLOAT_ARB ||
           srcType == GL_FLOAT);
 
@@ -2186,6 +2235,24 @@ extract_uint_indexes(GLuint n, GLuint indexes[],
             }
          }
          break;
+      case GL_UNSIGNED_INT_24_8_EXT:
+         {
+            GLuint i;
+            const GLuint *s = (const GLuint *) src;
+            if (unpack->SwapBytes) {
+               for (i = 0; i < n; i++) {
+                  GLuint value = s[i];
+                  SWAP4BYTE(value);
+                  indexes[i] = value & 0xff;  /* lower 8 bits */
+               }
+            }
+            else {
+               for (i = 0; i < n; i++)
+                  indexes[i] = s[i] & 0xfff;  /* lower 8 bits */
+            }
+         }
+         break;
+
       default:
          _mesa_problem(NULL, "bad srcType in extract_uint_indexes");
          return;
@@ -2901,8 +2968,7 @@ _mesa_unpack_color_span_chan( GLcontext *ctx,
       GLint dstComponents;
       GLint dstRedIndex, dstGreenIndex, dstBlueIndex, dstAlphaIndex;
       GLint dstLuminanceIndex, dstIntensityIndex;
-      DEFMARRAY(GLfloat, rgba, MAX_WIDTH, 4);  /* mac 32k limitation */
-      CHECKARRAY(rgba, return);  /* mac 32k limitation */
+      GLfloat rgba[MAX_WIDTH][4];
 
       dstComponents = _mesa_components_in_format( dstFormat );
       /* source & dest image formats should have been error checked by now */
@@ -2931,7 +2997,6 @@ _mesa_unpack_color_span_chan( GLcontext *ctx,
             for (i = 0; i < n; i++) {
                dest[i] = (GLchan) (indexes[i] & 0xff);
             }
-            UNDEFARRAY(rgba);  /* mac 32k limitation */
             return;
          }
          else {
@@ -2999,7 +3064,6 @@ _mesa_unpack_color_span_chan( GLcontext *ctx,
             break;
          default:
             _mesa_problem(ctx, "bad dstFormat in _mesa_unpack_chan_span()");
-            UNDEFARRAY(rgba);  /* mac 32k limitation */
             return;
       }
 
@@ -3063,7 +3127,6 @@ _mesa_unpack_color_span_chan( GLcontext *ctx,
             dst += dstComponents;
          }
       }
-      UNDEFARRAY(rgba);  /* mac 32k limitation */
    }
 }
 
@@ -3129,8 +3192,7 @@ _mesa_unpack_color_span_float( GLcontext *ctx,
       GLint dstComponents;
       GLint dstRedIndex, dstGreenIndex, dstBlueIndex, dstAlphaIndex;
       GLint dstLuminanceIndex, dstIntensityIndex;
-      DEFMARRAY(GLfloat, rgba, MAX_WIDTH, 4);  /* mac 32k limitation */
-      CHECKARRAY(rgba, return);  /* mac 32k limitation */
+      GLfloat rgba[MAX_WIDTH][4];
 
       dstComponents = _mesa_components_in_format( dstFormat );
       /* source & dest image formats should have been error checked by now */
@@ -3159,7 +3221,6 @@ _mesa_unpack_color_span_float( GLcontext *ctx,
             for (i = 0; i < n; i++) {
                dest[i] = (GLchan) (indexes[i] & 0xff);
             }
-            UNDEFARRAY(rgba);  /* mac 32k limitation */
             return;
          }
          else {
@@ -3222,7 +3283,6 @@ _mesa_unpack_color_span_float( GLcontext *ctx,
             break;
          default:
             _mesa_problem(ctx, "bad dstFormat in _mesa_unpack_color_span_float()");
-            UNDEFARRAY(rgba);  /* mac 32k limitation */
             return;
       }
 
@@ -3284,7 +3344,6 @@ _mesa_unpack_color_span_float( GLcontext *ctx,
             dst += dstComponents;
          }
       }
-      UNDEFARRAY(rgba);  /* mac 32k limitation */
    }
 }
 
@@ -3536,6 +3595,7 @@ _mesa_unpack_stencil_span( const GLcontext *ctx, GLuint n,
           srcType == GL_SHORT ||
           srcType == GL_UNSIGNED_INT ||
           srcType == GL_INT ||
+          srcType == GL_UNSIGNED_INT_24_8_EXT ||
           srcType == GL_HALF_FLOAT_ARB ||
           srcType == GL_FLOAT);
 
@@ -3774,10 +3834,20 @@ _mesa_pack_stencil_span( const GLcontext *ctx, GLuint n,
 
 
 void
-_mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
+_mesa_unpack_depth_span( const GLcontext *ctx, GLuint n,
+                         GLenum dstType, GLvoid *dest, GLfloat depthScale,
                          GLenum srcType, const GLvoid *source,
                          const struct gl_pixelstore_attrib *srcPacking )
 {
+   GLfloat depthTemp[MAX_WIDTH], *depthValues;
+
+   if (dstType == GL_FLOAT) {
+      depthValues = (GLfloat *) dest;
+   }
+   else {
+      depthValues = depthTemp;
+   }
+
    (void) srcPacking;
 
    switch (srcType) {
@@ -3786,7 +3856,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
             GLuint i;
             const GLubyte *src = (const GLubyte *) source;
             for (i = 0; i < n; i++) {
-               dest[i] = BYTE_TO_FLOAT(src[i]);
+               depthValues[i] = BYTE_TO_FLOAT(src[i]);
             }
          }
          break;
@@ -3795,7 +3865,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
             GLuint i;
             const GLubyte *src = (const GLubyte *) source;
             for (i = 0; i < n; i++) {
-               dest[i] = UBYTE_TO_FLOAT(src[i]);
+               depthValues[i] = UBYTE_TO_FLOAT(src[i]);
             }
          }
          break;
@@ -3804,7 +3874,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
             GLuint i;
             const GLshort *src = (const GLshort *) source;
             for (i = 0; i < n; i++) {
-               dest[i] = SHORT_TO_FLOAT(src[i]);
+               depthValues[i] = SHORT_TO_FLOAT(src[i]);
             }
          }
          break;
@@ -3813,7 +3883,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
             GLuint i;
             const GLushort *src = (const GLushort *) source;
             for (i = 0; i < n; i++) {
-               dest[i] = USHORT_TO_FLOAT(src[i]);
+               depthValues[i] = USHORT_TO_FLOAT(src[i]);
             }
          }
          break;
@@ -3822,7 +3892,7 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
             GLuint i;
             const GLint *src = (const GLint *) source;
             for (i = 0; i < n; i++) {
-               dest[i] = INT_TO_FLOAT(src[i]);
+               depthValues[i] = INT_TO_FLOAT(src[i]);
             }
          }
          break;
@@ -3831,19 +3901,39 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
             GLuint i;
             const GLuint *src = (const GLuint *) source;
             for (i = 0; i < n; i++) {
-               dest[i] = UINT_TO_FLOAT(src[i]);
+               depthValues[i] = UINT_TO_FLOAT(src[i]);
+            }
+         }
+         break;
+      case GL_UNSIGNED_INT_24_8_EXT: /* GL_EXT_packed_depth_stencil */
+         if (dstType == GL_UNSIGNED_INT && ctx->Pixel.DepthScale == 1.0 &&
+             ctx->Pixel.DepthBias == 0.0 && depthScale == (GLfloat) 0xffffff) {
+            const GLuint *src = (const GLuint *) source;
+            GLuint *zValues = (GLuint *) dest;
+            GLuint i;
+            for (i = 0; i < n; i++) {
+               zValues[i] = src[i] & 0xffffff00;
+            }
+            return;
+         }
+         else {
+            const GLuint *src = (const GLuint *) source;
+            const GLfloat scale = 1.0f / 0xffffff;
+            GLuint i;
+            for (i = 0; i < n; i++) {
+               depthValues[i] = (src[i] >> 8) * scale;
             }
          }
          break;
       case GL_FLOAT:
-         MEMCPY(dest, source, n * sizeof(GLfloat));
+         MEMCPY(depthValues, source, n * sizeof(GLfloat));
          break;
       case GL_HALF_FLOAT_ARB:
          {
             GLuint i;
             const GLhalfARB *src = (const GLhalfARB *) source;
             for (i = 0; i < n; i++) {
-               dest[i] = _mesa_half_to_float(src[i]);
+               depthValues[i] = _mesa_half_to_float(src[i]);
             }
          }
          break;
@@ -3855,12 +3945,27 @@ _mesa_unpack_depth_span( const GLcontext *ctx, GLuint n, GLfloat *dest,
 
    /* apply depth scale and bias and clamp to [0,1] */
    if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) {
+      _mesa_scale_and_bias_depth(ctx, n, depthValues);
+   }
+
+   if (dstType == GL_UNSIGNED_INT) {
+      GLuint *zValues = (GLuint *) dest;
+      GLuint i;
+      for (i = 0; i < n; i++) {
+         zValues[i] = (GLuint) (depthValues[i] * depthScale);
+      }
+   }
+   else if (dstType == GL_UNSIGNED_SHORT) {
+      GLushort *zValues = (GLushort *) dest;
       GLuint i;
       for (i = 0; i < n; i++) {
-         GLfloat d = dest[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
-         dest[i] = CLAMP(d, 0.0F, 1.0F);
+         zValues[i] = (GLushort) (depthValues[i] * depthScale);
       }
    }
+   else {
+      ASSERT(dstType == GL_FLOAT);
+      ASSERT(depthScale == 1.0F);
+   }
 }
 
 
@@ -3873,18 +3978,12 @@ _mesa_pack_depth_span( const GLcontext *ctx, GLuint n, GLvoid *dest,
                        const struct gl_pixelstore_attrib *dstPacking )
 {
    GLfloat depthCopy[MAX_WIDTH];
-   const GLboolean bias_or_scale = ctx->Pixel.DepthBias != 0.0 ||
-                                   ctx->Pixel.DepthScale != 1.0;
 
    ASSERT(n <= MAX_WIDTH);
 
-   if (bias_or_scale) {
-      GLuint i;
-      for (i = 0; i < n; i++) {
-         GLfloat d;
-         d = depthSpan[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
-         depthCopy[i] = CLAMP(d, 0.0F, 1.0F);
-      }
+   if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) {
+      _mesa_memcpy(depthCopy, depthSpan, n * sizeof(GLfloat));
+      _mesa_scale_and_bias_depth(ctx, n, depthCopy);
       depthSpan = depthCopy;
    }
 
@@ -3992,7 +4091,8 @@ _mesa_pack_depth_span( const GLcontext *ctx, GLuint n, GLvoid *dest,
  * need a copy of the data in a standard format.
  */
 void *
-_mesa_unpack_image( GLsizei width, GLsizei height, GLsizei depth,
+_mesa_unpack_image( GLuint dimensions,
+                    GLsizei width, GLsizei height, GLsizei depth,
                     GLenum format, GLenum type, const GLvoid *pixels,
                     const struct gl_pixelstore_attrib *unpack )
 {
@@ -4036,7 +4136,7 @@ _mesa_unpack_image( GLsizei width, GLsizei height, GLsizei depth,
       dst = destBuffer;
       for (img = 0; img < depth; img++) {
          for (row = 0; row < height; row++) {
-            const GLvoid *src = _mesa_image_address(unpack, pixels,
+            const GLvoid *src = _mesa_image_address(dimensions, unpack, pixels,
                                width, height, format, type, img, row, 0);
             MEMCPY(dst, src, bytesPerRow);
             /* byte flipping/swapping */
@@ -4061,7 +4161,7 @@ _mesa_unpack_image( GLsizei width, GLsizei height, GLsizei depth,
 
 /**
  * Perform clipping for glDrawPixels.  The image's window position
- * and size, and the unpack skipPixels and skipRows are adjusted so
+ * and size, and the unpack SkipPixels and SkipRows are adjusted so
  * that the image region is entirely within the window and scissor bounds.
  * NOTE: this will only work when glPixelZoom is (1, 1).
  *
@@ -4072,15 +4172,19 @@ GLboolean
 _mesa_clip_drawpixels(const GLcontext *ctx,
                       GLint *destX, GLint *destY,
                       GLsizei *width, GLsizei *height,
-                      GLint *skipPixels, GLint *skipRows)
+                      struct gl_pixelstore_attrib *unpack)
 {
    const GLframebuffer *buffer = ctx->DrawBuffer;
 
+   if (unpack->RowLength == 0) {
+      unpack->RowLength = *width;
+   }
+
    ASSERT(ctx->Pixel.ZoomX == 1.0F && ctx->Pixel.ZoomY == 1.0F);
 
    /* left clipping */
    if (*destX < buffer->_Xmin) {
-      *skipPixels += (buffer->_Xmin - *destX);
+      unpack->SkipPixels += (buffer->_Xmin - *destX);
       *width -= (buffer->_Xmin - *destX);
       *destX = buffer->_Xmin;
    }
@@ -4093,7 +4197,7 @@ _mesa_clip_drawpixels(const GLcontext *ctx,
 
    /* bottom clipping */
    if (*destY < buffer->_Ymin) {
-      *skipRows += (buffer->_Ymin - *destY);
+      unpack->SkipRows += (buffer->_Ymin - *destY);
       *height -= (buffer->_Ymin - *destY);
       *destY = buffer->_Ymin;
    }
@@ -4110,11 +4214,11 @@ _mesa_clip_drawpixels(const GLcontext *ctx,
 
 /**
  * Perform clipping for glReadPixels.  The image's window position
- * and size, and the pack skipPixels and skipRows are adjusted so
- * that the image region is entirely within the window bounds.
+ * and size, and the pack skipPixels, skipRows and rowLength are adjusted
+ * so that the image region is entirely within the window bounds.
  * Note: this is different from _mesa_clip_drawpixels() in that the
- * scissor box is ignored, and we use the bounds of the current "read"
- * surface;
+ * scissor box is ignored, and we use the bounds of the current readbuffer
+ * surface.
  *
  * \return  GL_TRUE if image is ready for drawing or
  *          GL_FALSE if image was completely clipped away (draw nothing)
@@ -4123,18 +4227,22 @@ GLboolean
 _mesa_clip_readpixels(const GLcontext *ctx,
                       GLint *srcX, GLint *srcY,
                       GLsizei *width, GLsizei *height,
-                      GLint *skipPixels, GLint *skipRows)
+                      struct gl_pixelstore_attrib *pack)
 {
    const GLframebuffer *buffer = ctx->ReadBuffer;
 
+   if (pack->RowLength == 0) {
+      pack->RowLength = *width;
+   }
+
    /* left clipping */
    if (*srcX < 0) {
-      *skipPixels += (0 - *srcX);
+      pack->SkipPixels += (0 - *srcX);
       *width -= (0 - *srcX);
       *srcX = 0;
    }
    /* right clipping */
-   if (*srcX + *width > buffer->Width)
+   if (*srcX + *width > (GLsizei) buffer->Width)
       *width -= (*srcX + *width - buffer->Width);
 
    if (*width <= 0)
@@ -4142,12 +4250,12 @@ _mesa_clip_readpixels(const GLcontext *ctx,
 
    /* bottom clipping */
    if (*srcY < 0) {
-      *skipRows += (0 - *srcY);
+      pack->SkipRows += (0 - *srcY);
       *height -= (0 - *srcY);
       *srcY = 0;
    }
    /* top clipping */
-   if (*srcY + *height > buffer->Height)
+   if (*srcY + *height > (GLsizei) buffer->Height)
       *height -= (*srcY + *height - buffer->Height);
 
    if (*height <= 0)