Lots of changes to support runtime renderbuffer depths.
authorBrian Paul <brian.paul@tungstengraphics.com>
Thu, 12 Oct 2006 23:17:02 +0000 (23:17 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Thu, 12 Oct 2006 23:17:02 +0000 (23:17 +0000)
_swrast_read_rgba_span() now takes a datatype parameter.
New optimization for glReadPixels(format=GL_RGB).
New glCopyPixels optimization for the simple, common cases.

src/mesa/swrast/s_accum.c
src/mesa/swrast/s_context.h
src/mesa/swrast/s_copypix.c
src/mesa/swrast/s_drawpix.c
src/mesa/swrast/s_imaging.c
src/mesa/swrast/s_readpix.c
src/mesa/swrast/s_span.c
src/mesa/swrast/s_span.h
src/mesa/swrast/s_texstore.c

index 64b6d6b84edfce67cf3768069f04766d77ed342f..0b8ad0076232df0c4c1436fdb083853ce0ccb56b 100644 (file)
@@ -307,7 +307,7 @@ accum_accum(GLcontext *ctx, GLfloat value,
 
          /* read colors from color buffer */
          _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, width,
-                                xpos, ypos + i, rgba);
+                                xpos, ypos + i, CHAN_TYPE, rgba);
 
          /* do accumulation */
          if (swrast->_IntegerAccumMode) {
@@ -391,7 +391,7 @@ accum_load(GLcontext *ctx, GLfloat value,
 
          /* read colors from color buffer */
          _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, width,
-                                xpos, ypos + i, rgba);
+                                xpos, ypos + i, CHAN_TYPE, rgba);
 
          /* do load */
          if (swrast->_IntegerAccumMode) {
index 6ccee5438e74727c7b1f7f0f45e205c04fe951e6..37d7081d4d66ad73bfa6e26a075cca3e6800dd85 100644 (file)
@@ -432,6 +432,16 @@ _swrast_validate_derived( GLcontext *ctx );
 
 
 
+/**
+ * Size of an RGBA pixel, in bytes, for given datatype.
+ */
+#define RGBA_PIXEL_SIZE(TYPE)                                     \
+         ((TYPE == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :      \
+          ((TYPE == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)     \
+           : 4 * sizeof(GLfloat)))
+
+
+
 /*
  * XXX these macros are just bandages for now in order to make
  * CHAN_BITS==32 compile cleanly.
index be794e38e2a9fcc1e5821819f8784be8e00b230a..7c1f3c887791c06d70889032a60014f7fee68c88 100644 (file)
 
 
 
-/*
+/**
  * Determine if there's overlap in an image copy.
  * This test also compensates for the fact that copies are done from
  * bottom to top and overlaps can sometimes be handled correctly
  * without making a temporary image copy.
+ * \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
  */
 static GLboolean
 regions_overlap(GLint srcx, GLint srcy,
@@ -87,41 +88,6 @@ regions_overlap(GLint srcx, GLint srcy,
 
 
 /**
- * Convert GLfloat[n][4] colors to GLchan[n][4].
- * XXX maybe move into image.c
- */
-static void
-float_span_to_chan(GLuint n, CONST GLfloat in[][4], GLchan out[][4])
-{
-   GLuint i;
-   for (i = 0; i < n; i++) {
-      UNCLAMPED_FLOAT_TO_CHAN(out[i][RCOMP], in[i][RCOMP]);
-      UNCLAMPED_FLOAT_TO_CHAN(out[i][GCOMP], in[i][GCOMP]);
-      UNCLAMPED_FLOAT_TO_CHAN(out[i][BCOMP], in[i][BCOMP]);
-      UNCLAMPED_FLOAT_TO_CHAN(out[i][ACOMP], in[i][ACOMP]);
-   }
-}
-
-
-/**
- * Convert GLchan[n][4] colors to GLfloat[n][4].
- * XXX maybe move into image.c
- */
-static void
-chan_span_to_float(GLuint n, CONST GLchan in[][4], GLfloat out[][4])
-{
-   GLuint i;
-   for (i = 0; i < n; i++) {
-      out[i][RCOMP] = CHAN_TO_FLOAT(in[i][RCOMP]);
-      out[i][GCOMP] = CHAN_TO_FLOAT(in[i][GCOMP]);
-      out[i][BCOMP] = CHAN_TO_FLOAT(in[i][BCOMP]);
-      out[i][ACOMP] = CHAN_TO_FLOAT(in[i][ACOMP]);
-   }
-}
-
-
-
-/*
  * RGBA copypixels with convolution.
  */
 static void
@@ -129,11 +95,11 @@ copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                       GLint width, GLint height, GLint destx, GLint desty)
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
-   struct gl_renderbuffer *drawRb = NULL;
-   GLboolean quick_draw;
    GLint row;
    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
    const GLuint transferOps = ctx->_ImageTransferState;
+   const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
+      || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
    GLfloat *dest, *tmpImage, *convImage;
    SWspan span;
 
@@ -145,17 +111,6 @@ copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
       _swrast_span_default_fog(ctx, &span);
 
 
-   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
-       && !zoom
-       && destx >= 0
-       && destx + width <= (GLint) ctx->DrawBuffer->Width) {
-      quick_draw = GL_TRUE;
-      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
-   }
-   else {
-      quick_draw = GL_FALSE;
-   }
-
    /* allocate space for GLfloat image */
    tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
    if (!tmpImage) {
@@ -169,15 +124,11 @@ copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
       return;
    }
 
-   /* read source image */
+   /* read source image as float/RGBA */
    dest = tmpImage;
    for (row = 0; row < height; row++) {
-      GLchan rgba[MAX_WIDTH][4];
-      /* Read GLchan and convert to GLfloat */
       _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                             width, srcx, srcy + row, rgba);
-      chan_span_to_float(width, (CONST GLchan (*)[4]) rgba,
-                         (GLfloat (*)[4]) dest);
+                             width, srcx, srcy + row, GL_FLOAT, dest);
       dest += 4 * width;
    }
 
@@ -207,38 +158,36 @@ copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                                     width, rgba);
    }
 
-   /* write the new image */
-   for (row = 0; row < height; row++) {
-      const GLfloat *src = convImage + row * width * 4;
-      GLint dy;
+   if (!sink) {
+      /* write the new image */
+      for (row = 0; row < height; row++) {
+         const GLfloat *src = convImage + row * width * 4;
+         GLvoid *rgba = span.array->color.sz1.rgba; /* row storage */
 
-      /* convert floats back to chan */
-      float_span_to_chan(width, (const GLfloat (*)[4]) src, span.array->rgba);
+         /* copy convolved colors into span array */
+         _mesa_memcpy(rgba, src, width * 4 * sizeof(GLfloat));
 
-      /* write row to framebuffer */
-      dy = desty + row;
-      if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
-         drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
-      }
-      else {
+         /* write span */
          span.x = destx;
-         span.y = dy;
+         span.y = desty + row;
          span.end = width;
+         span.array->ChanType = GL_FLOAT;
          if (zoom) {
-            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, 
-                                           span.array->rgba);
+            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
          }
          else {
             _swrast_write_rgba_span(ctx, &span);
          }
       }
+      /* restore this */
+      span.array->ChanType = CHAN_TYPE;
    }
 
    _mesa_free(convImage);
 }
 
 
-/*
+/**
  * RGBA copypixels
  */
 static void
@@ -246,10 +195,8 @@ copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                  GLint width, GLint height, GLint destx, GLint desty)
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
-   struct gl_renderbuffer *drawRb;
-   GLchan *tmpImage,*p;
-   GLboolean quick_draw;
-   GLint sy, dy, stepy, j;
+   GLfloat *tmpImage, *p;
+   GLint sy, dy, stepy, row;
    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
    GLint overlapping;
    const GLuint transferOps = ctx->_ImageTransferState;
@@ -260,8 +207,6 @@ copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
       return;
    }
 
-   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
-
    if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
       copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
       return;
@@ -289,35 +234,23 @@ copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
       overlapping = GL_FALSE;
    }
 
+   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
    if (ctx->Depth.Test)
       _swrast_span_default_z(ctx, &span);
    if (swrast->_FogEnabled)
       _swrast_span_default_fog(ctx, &span);
 
-   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
-       && !zoom
-       && destx >= 0
-       && destx + width <= (GLint) ctx->DrawBuffer->Width) {
-      quick_draw = GL_TRUE;
-      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
-   }
-   else {
-      quick_draw = GL_FALSE;
-      drawRb = NULL;
-   }
-
    if (overlapping) {
-      GLint ssy = sy;
-      tmpImage = (GLchan *) _mesa_malloc(width * height * sizeof(GLchan) * 4);
+      tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4);
       if (!tmpImage) {
          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
          return;
       }
-      /* read the source image */
+      /* read the source image as RGBA/float */
       p = tmpImage;
-      for (j = 0; j < height; j++, ssy += stepy) {
+      for (row = 0; row < height; row++) {
          _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                                 width, srcx, ssy, (GLchan (*)[4]) p );
+                                 width, srcx, sy + row, GL_FLOAT, p );
          p += width * 4;
       }
       p = tmpImage;
@@ -327,49 +260,43 @@ copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
       p = NULL;
    }
 
-   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
-      /* Get source pixels */
+   ASSERT(width < MAX_WIDTH);
+
+   for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
+      GLvoid *rgba = span.array->color.sz4.rgba;
+
+      /* Get row/span of source pixels */
       if (overlapping) {
          /* get from buffered image */
-         ASSERT(width < MAX_WIDTH);
-         _mesa_memcpy(span.array->rgba, p, width * sizeof(GLchan) * 4);
+         _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4);
          p += width * 4;
       }
       else {
          /* get from framebuffer */
-         ASSERT(width < MAX_WIDTH);
          _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                                 width, srcx, sy, span.array->rgba );
+                                 width, srcx, sy, GL_FLOAT, rgba );
       }
 
       if (transferOps) {
-         GLfloat rgbaFloat[MAX_WIDTH][4];
-         /* convert to float, transfer, convert back to chan */
-         chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba,
-                            rgbaFloat);
-         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat);
-         float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat,
-                            span.array->rgba);
+         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
+                                       (GLfloat (*)[4]) rgba);
       }
 
       /* Write color span */
-      if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
-         drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
+      span.x = destx;
+      span.y = dy;
+      span.end = width;
+      span.array->ChanType = GL_FLOAT;
+      if (zoom) {
+         _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
       }
       else {
-         span.x = destx;
-         span.y = dy;
-         span.end = width;
-         if (zoom) {
-            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span,
-                                           span.array->rgba);
-         }
-         else {
-            _swrast_write_rgba_span(ctx, &span);
-         }
+         _swrast_write_rgba_span(ctx, &span);
       }
    }
 
+   span.array->ChanType = CHAN_TYPE; /* restore */
+
    if (overlapping)
       _mesa_free(tmpImage);
 }
@@ -902,6 +829,87 @@ copy_depth_stencil_pixels(GLcontext *ctx,
 }
 
 
+
+/**
+ * Try to do a fast copy pixels.
+ */
+static GLboolean
+fast_copy_pixels(GLcontext *ctx,
+                 GLint srcX, GLint srcY, GLsizei width, GLsizei height,
+                 GLint dstX, GLint dstY, GLenum type)
+{
+   struct gl_framebuffer *srcFb = ctx->ReadBuffer;
+   struct gl_framebuffer *dstFb = ctx->DrawBuffer;
+   struct gl_renderbuffer *srcRb, *dstRb;
+   GLint row, yStep;
+
+   if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
+       ctx->Pixel.ZoomX != 1.0F ||
+       ctx->Pixel.ZoomY != 1.0F ||
+       ctx->_ImageTransferState) {
+      /* can't handle these */
+      return GL_FALSE;
+   }
+
+   if (type == GL_COLOR) {
+      if (dstFb->_NumColorDrawBuffers[0] != 1)
+         return GL_FALSE;
+      srcRb = srcFb->_ColorReadBuffer;
+      dstRb = dstFb->_ColorDrawBuffers[0][0];
+   }
+   else if (type == GL_STENCIL) {
+      srcRb = srcFb->_StencilBuffer;
+      dstRb = dstFb->_StencilBuffer;
+   }
+   else if (type == GL_DEPTH) {
+      srcRb = srcFb->_DepthBuffer;
+      dstRb = dstFb->_DepthBuffer;
+   }
+   else if (type == GL_DEPTH_STENCIL_EXT) {
+      /* XXX correct? */
+      srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
+      dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
+   }
+
+   /* src and dst renderbuffers must be same format and type */
+   if (!srcRb || !dstRb ||
+       srcRb->DataType != dstRb->DataType ||
+       srcRb->_BaseFormat != dstRb->_BaseFormat) {
+      return GL_FALSE;
+   }
+
+   /* clipping not supported */
+   if (srcX < 0 || srcX + width > srcFb->Width ||
+       srcY < 0 || srcY + height > srcFb->Width ||
+       dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
+       dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
+      return GL_FALSE;
+   }
+
+   /* overlapping src/dst doesn't matter, just determine Y direction */
+   if (srcY < dstY) {
+      /* top-down  max-to-min */
+      srcY = srcY + height - 1;
+      dstY = dstY + height - 1;
+      yStep = -1;
+   }
+   else {
+      /* bottom-up  min-to-max */
+      yStep = 1;
+   }
+
+   for (row = 0; row < height; row++) {
+      GLuint temp[MAX_WIDTH][4];
+      srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp);
+      dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL);
+      srcY += yStep;
+      dstY += yStep;
+   }
+
+   return GL_TRUE;
+}
+
+
 /**
  * Do software-based glCopyPixels.
  * By time we get here, all parameters will have been error-checked.
@@ -917,26 +925,28 @@ _swrast_CopyPixels( GLcontext *ctx,
    if (swrast->NewState)
       _swrast_validate_derived( ctx );
 
-   switch (type) {
-   case GL_COLOR:
-      if (ctx->Visual.rgbMode) {
-         copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
+   if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) {
+      switch (type) {
+      case GL_COLOR:
+         if (ctx->Visual.rgbMode) {
+            copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
+         }
+         else {
+            copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
+         }
+         break;
+      case GL_DEPTH:
+         copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
+         break;
+      case GL_STENCIL:
+         copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
+         break;
+      case GL_DEPTH_STENCIL_EXT:
+         copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
+         break;
+      default:
+         _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
       }
-      else {
-         copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
-      }
-      break;
-   case GL_DEPTH:
-      copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
-      break;
-   case GL_STENCIL:
-      copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
-      break;
-   case GL_DEPTH_STENCIL_EXT:
-      copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
-      break;
-   default:
-      _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
    }
 
    RENDER_FINISH(swrast,ctx);
index 5be2934b409d079e85a3132c98828a3bf8a547c3..46dd79702396e9b758a13ac00d92e20c634ad991 100644 (file)
 #include "s_zoom.h"
 
 
+
 /**
  * Try to do a fast and simple RGB(a) glDrawPixels.
  * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
  */
 static GLboolean
-fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
-                 GLsizei width, GLsizei height,
-                 GLenum format, GLenum type,
-                 const struct gl_pixelstore_attrib *userUnpack,
-                 const GLvoid *pixels)
+fast_draw_rgba_pixels(GLcontext *ctx, GLint x, GLint y,
+                      GLsizei width, GLsizei height,
+                      GLenum format, GLenum type,
+                      const struct gl_pixelstore_attrib *userUnpack,
+                      const GLvoid *pixels)
 {
    const GLint imgX = x, imgY = y;
    struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
@@ -63,7 +64,6 @@ fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
 
    if ((swrast->_RasterMask & ~CLIP_BIT) ||
        ctx->Texture._EnabledCoordUnits ||
-       userUnpack->Alignment != 1 ||
        userUnpack->SwapBytes ||
        ctx->_ImageTransferState) {
       /* can't handle any of those conditions */
@@ -100,26 +100,25 @@ fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
    else {
       /* non-simple zooming */
       simpleZoom = GL_FALSE;
+      yStep = 1;
       if (unpack.RowLength == 0)
          unpack.RowLength = width;
    }
 
    /*
     * Ready to draw!
-    * The window region at (destX, destY) of size (drawWidth, drawHeight)
-    * will be written to.
-    * We'll take pixel data from buffer pointed to by "pixels" but we'll
-    * skip "unpack.SkipRows" rows and skip "unpack.SkipPixels" pixels/row.
     */
 
-   if (format == GL_RGBA && type == CHAN_TYPE && rbType == CHAN_TYPE) {
-      const GLchan *src = (const GLchan *) pixels
-         + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels) * 4;
+   if (format == GL_RGBA && type == rbType) {
+      const GLubyte *src = _mesa_image_address2d(&unpack, pixels, width,
+                                                 height, format, type, 0, 0);
+      const GLint srcStride = _mesa_image_row_stride(&unpack, width,
+                                                     format, type);
       if (simpleZoom) {
          GLint row;
          for (row = 0; row < drawHeight; row++) {
             rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL);
-            src += unpack.RowLength * 4;
+            src += srcStride;
             destY += yStep;
          }
       }
@@ -130,21 +129,25 @@ fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
             span.x = destX;
             span.y = destY + row;
             span.end = drawWidth;
+            span.array->ChanType = rbType;
             _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, src);
-            src += unpack.RowLength * 4;
+            src += srcStride;
          }
+         span.array->ChanType = CHAN_TYPE;
       }
       return GL_TRUE;
    }
 
-   if (format == GL_RGB && type == CHAN_TYPE && rbType == CHAN_TYPE) {
-      const GLchan *src = (const GLchan *) pixels
-         + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels) * 3;
+   if (format == GL_RGB && type == rbType) {
+      const GLubyte *src = _mesa_image_address2d(&unpack, pixels, width,
+                                                 height, format, type, 0, 0);
+      const GLint srcStride = _mesa_image_row_stride(&unpack, width,
+                                                     format, type);
       if (simpleZoom) {
          GLint row;
          for (row = 0; row < drawHeight; row++) {
             rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL);
-            src += unpack.RowLength * 3;
+            src += srcStride;
             destY += yStep;
          }
       }
@@ -155,14 +158,20 @@ fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
             span.x = destX;
             span.y = destY;
             span.end = drawWidth;
+            span.array->ChanType = rbType;
             _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, src);
-            src += unpack.RowLength * 3;
-               destY++;
+            src += srcStride;
+            destY++;
          }
+         span.array->ChanType = CHAN_TYPE;
       }
       return GL_TRUE;
    }
 
+   /* Remaining cases haven't been tested with alignment != 1 */
+   if (userUnpack->Alignment != 1)
+      return GL_FALSE;
+
    if (format == GL_LUMINANCE && type == CHAN_TYPE && rbType == CHAN_TYPE) {
       const GLchan *src = (const GLchan *) pixels
          + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels);
@@ -530,7 +539,7 @@ draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
 
 
 
-/*
+/**
  * Draw RGBA image.
  */
 static void
@@ -542,19 +551,17 @@ draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    const GLint imgX = x, imgY = y;
-   struct gl_renderbuffer *rb = NULL; /* only used for quickDraw path */
    const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
-   GLboolean quickDraw;
    GLfloat *convImage = NULL;
    GLuint transferOps = ctx->_ImageTransferState;
    SWspan span;
 
    /* Try an optimized glDrawPixels first */
-   if (fast_draw_pixels(ctx, x, y, width, height, format, type, unpack, pixels))
+   if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type,
+                             unpack, pixels))
       return;
 
    INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
-
    if (ctx->Depth.Test)
       _swrast_span_default_z(ctx, &span);
    if (swrast->_FogEnabled)
@@ -562,21 +569,6 @@ draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
    if (ctx->Texture._EnabledCoordUnits)
       _swrast_span_default_texcoords(ctx, &span);
 
-   if (swrast->_RasterMask == 0 && !zoom && x >= 0 && y >= 0
-       && x + width <= (GLint) ctx->DrawBuffer->Width
-       && y + height <= (GLint) ctx->DrawBuffer->Height
-       && ctx->DrawBuffer->_NumColorDrawBuffers[0] == 1) {
-      rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
-      if (rb->DataType == format)
-         quickDraw = GL_TRUE;
-      else
-         quickDraw = GL_FALSE;
-   }
-   else {
-      quickDraw = GL_FALSE;
-      rb = NULL;
-   }
-
    if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
       /* Convolution has to be handled specially.  We'll create an
        * intermediate image, applying all pixel transfer operations
@@ -628,6 +620,13 @@ draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
       transferOps &= IMAGE_POST_CONVOLUTION_BITS;
    }
 
+   if (ctx->DrawBuffer->_NumColorDrawBuffers[0] > 0 &&
+       ctx->DrawBuffer->_ColorDrawBuffers[0][0]->DataType != GL_FLOAT &&
+       ctx->Color.ClampFragmentColor != GL_FALSE) {
+      /* need to clamp colors before applying fragment ops */
+      transferOps |= IMAGE_CLAMP_BIT;
+   }
+
    /*
     * General solution
     */
@@ -636,53 +635,51 @@ draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
          || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
       const GLbitfield interpMask = span.interpMask;
       const GLbitfield arrayMask = span.arrayMask;
+      const GLint srcStride
+         = _mesa_image_row_stride(unpack, width, format, type);
       GLint skipPixels = 0;
+      /* use span array for temp color storage */
+      GLfloat *rgba = (GLfloat *) span.array->color.sz4.rgba;
 
       /* if the span is wider than MAX_WIDTH we have to do it in chunks */
       while (skipPixels < width) {
          const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
+         const GLubyte *source = _mesa_image_address2d(unpack, pixels,
+                               width, height, format, type, 0, skipPixels);
          GLint row;
 
-         ASSERT(span.end <= MAX_WIDTH);
-
          for (row = 0; row < height; row++) {
-            const GLvoid *source = _mesa_image_address2d(unpack,
-                     pixels, width, height, format, type, row, skipPixels);
-
-            /* Set these for each row since the _swrast_write_* function may
-             * change them while clipping.
-             */
-            span.array->ChanType = CHAN_TYPE;
-            span.x = x + skipPixels;
-            span.y = y + row;
-            span.end = spanWidth;
-            span.arrayMask = arrayMask;
-            span.interpMask = interpMask;
-
-            _mesa_unpack_color_span_chan(ctx, spanWidth, GL_RGBA,
-                                         (GLchan *) span.array->rgba,
-                                         format, type, source, unpack,
-                                         transferOps);
-
-            if (sink)
-               continue;
-
+            /* get image row as float/RGBA */
+            _mesa_unpack_color_span_float(ctx, spanWidth, GL_RGBA, rgba,
+                                     format, type, source, unpack,
+                                     transferOps);
             /* draw the span */
-            if (quickDraw) {
-               rb->PutRow(ctx, rb, span.end, span.x, span.y,
-                          span.array->rgba, NULL);
-            }
-            else if (zoom) {
-               _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
-                                              span.array->rgba);
-            }
-            else {
-               _swrast_write_rgba_span(ctx, &span);
+            if (!sink) {
+               /* Set these for each row since the _swrast_write_* functions
+                * may change them while clipping/rendering.
+                */
+               span.array->ChanType = GL_FLOAT;
+               span.x = x + skipPixels;
+               span.y = y + row;
+               span.end = spanWidth;
+               span.arrayMask = arrayMask;
+               span.interpMask = interpMask;
+               if (zoom) {
+                  _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba);
+               }
+               else {
+                  _swrast_write_rgba_span(ctx, &span);
+               }
             }
-         }
+
+            source += srcStride;
+         } /* for row */
 
          skipPixels += spanWidth;
-      }
+      } /* while skipPixels < width */
+
+      /* XXX this is ugly/temporary, to undo above change */
+      span.array->ChanType = CHAN_TYPE;
    }
 
    if (convImage) {
index ac69d270b88f075589de622507425dea882e52ad..73aaba1ec9fe4919f3f11814af3ead827c9bc975 100644 (file)
@@ -54,7 +54,7 @@ _swrast_CopyColorTable( GLcontext *ctx,
 
    /* read the data from framebuffer */
    _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                           width, x, y, data );
+                           width, x, y, CHAN_TYPE, data );
 
    RENDER_FINISH(swrast,ctx);
 
@@ -89,7 +89,7 @@ _swrast_CopyColorSubTable( GLcontext *ctx,GLenum target, GLsizei start,
 
    /* read the data from framebuffer */
    _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                           width, x, y, data );
+                           width, x, y, CHAN_TYPE, data );
 
    RENDER_FINISH(swrast,ctx);
 
@@ -122,7 +122,7 @@ _swrast_CopyConvolutionFilter1D(GLcontext *ctx, GLenum target,
 
    /* read the data from framebuffer */
    _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                           width, x, y, (GLchan (*)[4]) rgba );
+                           width, x, y, CHAN_TYPE, rgba );
    
    RENDER_FINISH( swrast, ctx );
 
@@ -160,7 +160,7 @@ _swrast_CopyConvolutionFilter2D(GLcontext *ctx, GLenum target,
    /* read pixels from framebuffer */
    for (i = 0; i < height; i++) {
       _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                              width, x, y + i, (GLchan (*)[4]) rgba[i] );
+                              width, x, y + i, CHAN_TYPE, rgba[i] );
    }
 
    RENDER_FINISH(swrast,ctx);
index a73bb81aacb25c2f799547fa89636111cb798b08..334dc02918d26794e40b274aef680d8e6dd311bb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5
+ * Version:  6.5.2
  *
  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  *
@@ -197,7 +197,7 @@ read_stencil_pixels( GLcontext *ctx,
  * scaling, biasing, mapping, etc. are disabled.
  */
 static GLboolean
-read_fast_rgba_pixels( GLcontext *ctx,
+fast_read_rgba_pixels( GLcontext *ctx,
                        GLint x, GLint y,
                        GLsizei width, GLsizei height,
                        GLenum format, GLenum type,
@@ -206,53 +206,59 @@ read_fast_rgba_pixels( GLcontext *ctx,
 {
    struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
 
+   ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB);
+
    /* clipping should have already been done */
    ASSERT(x + width <= rb->Width);
    ASSERT(y + height <= rb->Height);
 
-   /* can't do scale, bias, mapping, etc */
-   if (ctx->_ImageTransferState)
-       return GL_FALSE;
-
-   /* can't do fancy pixel packing */
-   if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
+   /* check for things we can't handle here */
+   if (ctx->_ImageTransferState ||
+       packing->SwapBytes ||
+       packing->LsbFirst) {
       return GL_FALSE;
+   }
 
-   /* if the pixel format exactly matches the renderbuffer format */
    if (format == GL_RGBA && rb->DataType == type) {
-      GLint rowLength = (packing->RowLength > 0) ? packing->RowLength : width;
-      GLint pixelSize, row;
-      GLubyte *dest;
-
-      if (type == GL_UNSIGNED_BYTE)
-         pixelSize = 4 * sizeof(GLubyte);
-      else if (type == GL_UNSIGNED_SHORT)
-         pixelSize = 4 * sizeof(GLushort);
-      else {
-         ASSERT(type == GL_FLOAT);
-         pixelSize = 4 * sizeof(GLfloat);
-      }
-
-      dest = (GLubyte *) pixels
-         + (packing->SkipRows * rowLength + packing->SkipPixels) * pixelSize;
-
-      if (packing->Invert) {
-         /* start at top and go down */
-         dest += (height - 1) * rowLength * pixelSize;
-         rowLength = -rowLength;
-      }
-
+      const GLint dstStride = _mesa_image_row_stride(packing, width,
+                                                     format, type);
+      GLubyte *dest = _mesa_image_address2d(packing, pixels, width, height,
+                                            format, type, 0, 0);
+      GLint row;
       ASSERT(rb->GetRow);
       for (row = 0; row < height; row++) {
          rb->GetRow(ctx, rb, width, x, y + row, dest);
-         dest += rowLength * pixelSize;
+         dest += dstStride;
       }
       return GL_TRUE;
    }
-   else {
-      /* can't do this format/type combination */
-      return GL_FALSE;
+
+   if (format == GL_RGB &&
+       rb->DataType == GL_UNSIGNED_BYTE &&
+       type == GL_UNSIGNED_BYTE) {
+      const GLint dstStride = _mesa_image_row_stride(packing, width,
+                                                     format, type);
+      GLubyte *dest = _mesa_image_address2d(packing, pixels, width, height,
+                                            format, type, 0, 0);
+      GLint row;
+      ASSERT(rb->GetRow);
+      for (row = 0; row < height; row++) {
+         GLubyte tempRow[MAX_WIDTH][4];
+         GLint col;
+         rb->GetRow(ctx, rb, width, x, y + row, tempRow);
+         /* convert RGBA to RGB */
+         for (col = 0; col < width; col++) {
+            dest[col * 3 + 0] = tempRow[col][0];
+            dest[col * 3 + 1] = tempRow[col][1];
+            dest[col * 3 + 2] = tempRow[col][2];
+         }
+         dest += dstStride;
+      }
+      return GL_TRUE;
    }
+
+   /* not handled */
+   return GL_FALSE;
 }
 
 
@@ -267,14 +273,15 @@ read_rgba_pixels( GLcontext *ctx,
                   GLenum format, GLenum type, GLvoid *pixels,
                   const struct gl_pixelstore_attrib *packing )
 {
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
    struct gl_framebuffer *fb = ctx->ReadBuffer;
    struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
 
    ASSERT(rb);
 
    /* Try optimized path first */
-   if (read_fast_rgba_pixels( ctx, x, y, width, height,
-                              format, type, pixels, packing )) {
+   if (fast_read_rgba_pixels(ctx, x, y, width, height,
+                             format, type, pixels, packing)) {
       return; /* done! */
    }
 
@@ -301,9 +308,8 @@ read_rgba_pixels( GLcontext *ctx,
       /* read full RGBA, FLOAT image */
       dest = tmpImage;
       for (row = 0; row < height; row++, y++) {
-         GLchan rgba[MAX_WIDTH][4];
          if (fb->Visual.rgbMode) {
-            _swrast_read_rgba_span(ctx, rb, width, x, y, rgba);
+            _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, dest);
          }
          else {
             GLuint index[MAX_WIDTH];
@@ -312,11 +318,11 @@ read_rgba_pixels( GLcontext *ctx,
             if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
                _mesa_map_ci(ctx, width, index);
             }
-            _mesa_map_ci_to_rgba_chan(ctx, width, index, rgba);
+            _mesa_map_ci_to_rgba(ctx, width, index, (GLfloat (*)[4]) dest);
          }
-         _mesa_pack_rgba_span_chan(ctx, width, (const GLchan (*)[4]) rgba,
-                              GL_RGBA, GL_FLOAT, dest, &ctx->DefaultPacking,
-                              transferOps & IMAGE_PRE_CONVOLUTION_BITS);
+         _mesa_apply_rgba_transfer_ops(ctx, 
+                                      transferOps & IMAGE_PRE_CONVOLUTION_BITS,
+                                      width, (GLfloat (*)[4]) dest);
          dest += width * 4;
       }
 
@@ -346,24 +352,35 @@ read_rgba_pixels( GLcontext *ctx,
    }
    else {
       /* no convolution */
+      const GLint dstStride
+         = _mesa_image_row_stride(packing, width, format, type);
+      GLfloat (*rgba)[4] = swrast->SpanArrays->color.sz4.rgba;
       GLint row;
+      GLubyte *dst = _mesa_image_address2d(packing, pixels, width, height,
+                                           format, type, 0, 0);
+
       for (row = 0; row < height; row++, y++) {
-         GLchan rgba[MAX_WIDTH][4];
-         GLvoid *dst;
+
+         /* Get float rgba pixels */
          if (fb->Visual.rgbMode) {
-            _swrast_read_rgba_span(ctx, rb, width, x, y, rgba);
+            _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);
             if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
                _mesa_map_ci(ctx, width, index);
             }
-            _mesa_map_ci_to_rgba_chan(ctx, width, index, rgba);
+            _mesa_map_ci_to_rgba(ctx, width, index, rgba);
          }
-         dst = _mesa_image_address2d(packing, pixels, width, height,
-                                     format, type, row, 0);
+
+         /* pack the row of RGBA pixels into user's buffer */
+#if 0
+         /* XXX may need to rejuvinate this code if we get conformance
+          * falures on 16bpp displays (i.e. 5/6/5).
+          */
          if (fb->Visual.redBits < CHAN_BITS ||
              fb->Visual.greenBits < CHAN_BITS ||
              fb->Visual.blueBits < CHAN_BITS) {
@@ -379,12 +396,15 @@ read_rgba_pixels( GLcontext *ctx,
                                        format, type, dst, packing,
                                        ctx->_ImageTransferState);
          }
-         else {
-            /* GLubytes are fine */
-            _mesa_pack_rgba_span_chan(ctx, width, (CONST GLchan (*)[4]) rgba,
-                                 format, type, dst, packing,
-                                 ctx->_ImageTransferState);
+         else
+#endif
+         {
+            _mesa_pack_rgba_span_float(ctx, width, (CONST GLfloat (*)[4]) rgba,
+                                       format, type, dst,
+                                       packing, ctx->_ImageTransferState);
          }
+
+         dst += dstStride;
       }
    }
 }
index 4d0ccf5f1d0095988a558190b1908a8381997392..59a5361632b11829247c91da71e51307693d1f21 100644 (file)
@@ -1560,14 +1560,16 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span)
 }
 
 
-
 /**
  * Read RGBA pixels from frame buffer.  Clipping will be done to prevent
  * reading ouside the buffer's boundaries.
+ * \param type  datatype for returned colors
+ * \param rgba  the returned colors
  */
 void
 _swrast_read_rgba_span( GLcontext *ctx, struct gl_renderbuffer *rb,
-                        GLuint n, GLint x, GLint y, GLchan rgba[][4] )
+                        GLuint n, GLint x, GLint y, GLenum dstType,
+                        GLvoid *rgba)
 {
    const GLint bufWidth = (GLint) rb->Width;
    const GLint bufHeight = (GLint) rb->Height;
@@ -1609,8 +1611,18 @@ _swrast_read_rgba_span( GLcontext *ctx, struct gl_renderbuffer *rb,
       ASSERT(rb);
       ASSERT(rb->GetRow);
       ASSERT(rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RGBA);
-      ASSERT(rb->DataType == CHAN_TYPE);
-      rb->GetRow(ctx, rb, length, x + skip, y, rgba + skip);
+
+      if (rb->DataType == dstType) {
+         rb->GetRow(ctx, rb, length, x + skip, y,
+                    (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(rb->DataType));
+      }
+      else {
+         GLuint temp[MAX_WIDTH * 4];
+         rb->GetRow(ctx, rb, length, x + skip, y, temp);
+         _mesa_convert_colors(rb->DataType, temp,
+                   dstType, (GLubyte *) rgba + skip * RGBA_PIXEL_SIZE(dstType),
+                   length, NULL);
+      }
    }
 }
 
@@ -1801,7 +1813,7 @@ void *
 _swrast_get_dest_rgba(GLcontext *ctx, struct gl_renderbuffer *rb,
                       SWspan *span)
 {
-   GLuint pixelSize;
+   const GLuint pixelSize = RGBA_PIXEL_SIZE(span->array->ChanType);
    void *rbPixels;
 
    /*
@@ -1809,15 +1821,12 @@ _swrast_get_dest_rgba(GLcontext *ctx, struct gl_renderbuffer *rb,
     * Point rbPixels to a temporary space (use specular color arrays).
     */
    if (span->array->ChanType == GL_UNSIGNED_BYTE) {
-      pixelSize = 4 * sizeof(GLubyte);
       rbPixels = span->array->color.sz1.spec;
    }
    else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
-      pixelSize = 4 * sizeof(GLushort);
       rbPixels = span->array->color.sz2.spec;
    }
    else {
-      pixelSize = 4 * sizeof(GLfloat);
       rbPixels = span->array->color.sz4.spec;
    }
 
index efc98f290c46aba251b1651dc419df6474d28624..c441106abae707bb2e89fa3ce43f2810ad17ca66 100644 (file)
@@ -60,8 +60,8 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span);
 
 
 extern void
-_swrast_read_rgba_span( GLcontext *ctx, struct gl_renderbuffer *rb,
-                        GLuint n, GLint x, GLint y, GLchan rgba[][4] );
+_swrast_read_rgba_span(GLcontext *ctx, struct gl_renderbuffer *rb,
+                       GLuint n, GLint x, GLint y, GLenum type, GLvoid *rgba);
 
 extern void
 _swrast_read_index_span( GLcontext *ctx, struct gl_renderbuffer *rb,
index b018c5a4a63e6960999e60a92062e4053b9a62c6..ddaf7471f597da3073f175deab19c4feb203cb29 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5.1
+ * Version:  6.5.2
  *
  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  *
 #include "s_depth.h"
 #include "s_span.h"
 
-/*
+
+/**
  * Read an RGBA image from the frame buffer.
  * This is used by glCopyTex[Sub]Image[12]D().
- * Input:  ctx - the context
- *         x, y - lower left corner
- *         width, height - size of region to read
- * Return: pointer to block of GL_RGBA, GLchan data.
+ * \param x  window source x
+ * \param y  window source y
+ * \param width  image width
+ * \param height  image height
+ * \param type  datatype for returned GL_RGBA image
+ * \return pointer to image
  */
-static GLchan *
-read_color_image( GLcontext *ctx, GLint x, GLint y,
+static GLvoid *
+read_color_image( GLcontext *ctx, GLint x, GLint y, GLenum type,
                   GLsizei width, GLsizei height )
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
-   const GLint stride = 4 * width;
-   GLint i;
-   GLchan *image, *dst;
+   struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
+   const GLint pixelSize = _mesa_bytes_per_pixel(GL_RGBA, type);
+   const GLint stride = width * pixelSize;
+   GLint row;
+   GLubyte *image, *dst;
 
-   image = (GLchan *) _mesa_malloc(width * height * 4 * sizeof(GLchan));
+   image = (GLubyte *) _mesa_malloc(width * height * pixelSize);
    if (!image)
       return NULL;
 
    RENDER_START(swrast, ctx);
 
    dst = image;
-   for (i = 0; i < height; i++) {
-      _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
-                             width, x, y + i, (GLchan (*)[4]) dst);
+   for (row = 0; row < height; row++) {
+      _swrast_read_rgba_span(ctx, rb, width, x, y + row, type, dst);
       dst += stride;
    }
 
@@ -285,15 +289,16 @@ _swrast_copy_teximage1d( GLcontext *ctx, GLenum target, GLint level,
    }
    else {
       /* read RGBA image from framebuffer */
-      GLchan *image = read_color_image(ctx, x, y, width, 1);
+      const GLenum format = GL_RGBA;
+      const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
+      GLvoid *image = read_color_image(ctx, x, y, type, width, 1);
       if (!image) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
          return;
       }
       /* call glTexImage1D to redefine the texture */
       ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
-                             width, border,
-                             GL_RGBA, CHAN_TYPE, image,
+                             width, border, format, type, image,
                              &ctx->DefaultPacking, texObj, texImage);
       _mesa_free(image);
    }
@@ -360,15 +365,16 @@ _swrast_copy_teximage2d( GLcontext *ctx, GLenum target, GLint level,
    }
    else {
       /* read RGBA image from framebuffer */
-      GLchan *image = read_color_image(ctx, x, y, width, height);
+      const GLenum format = GL_RGBA;
+      const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
+      GLvoid *image = read_color_image(ctx, x, y, type, width, height);
       if (!image) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
          return;
       }
       /* call glTexImage2D to redefine the texture */
       ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
-                             width, height, border,
-                             GL_RGBA, CHAN_TYPE, image,
+                             width, height, border, format, type, image,
                              &ctx->DefaultPacking, texObj, texImage);
       _mesa_free(image);
    }
@@ -428,14 +434,16 @@ _swrast_copy_texsubimage1d( GLcontext *ctx, GLenum target, GLint level,
    }
    else {
       /* read RGBA image from framebuffer */
-      GLchan *image = read_color_image(ctx, x, y, width, 1);
+      const GLenum format = GL_RGBA;
+      const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
+      GLvoid *image = read_color_image(ctx, x, y, type, width, 1);
       if (!image) {
          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D" );
          return;
       }
       /* now call glTexSubImage1D to do the real work */
       ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, width,
-                                GL_RGBA, CHAN_TYPE, image,
+                                format, type, image,
                                 &ctx->DefaultPacking, texObj, texImage);
       _mesa_free(image);
    }
@@ -501,7 +509,9 @@ _swrast_copy_texsubimage2d( GLcontext *ctx,
    }
    else {
       /* read RGBA image from framebuffer */
-      GLchan *image = read_color_image(ctx, x, y, width, height);
+      const GLenum format = GL_RGBA;
+      const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
+      GLvoid *image = read_color_image(ctx, x, y, type, width, height);
       if (!image) {
          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D" );
          return;
@@ -509,7 +519,7 @@ _swrast_copy_texsubimage2d( GLcontext *ctx,
       /* now call glTexSubImage2D to do the real work */
       ctx->Driver.TexSubImage2D(ctx, target, level,
                                 xoffset, yoffset, width, height,
-                                GL_RGBA, CHAN_TYPE, image,
+                                format, type, image,
                                 &ctx->DefaultPacking, texObj, texImage);
       _mesa_free(image);
    }
@@ -572,7 +582,9 @@ _swrast_copy_texsubimage3d( GLcontext *ctx,
    }
    else {
       /* read RGBA image from framebuffer */
-      GLchan *image = read_color_image(ctx, x, y, width, height);
+      const GLenum format = GL_RGBA;
+      const GLenum type = ctx->ReadBuffer->_ColorReadBuffer->DataType;
+      GLvoid *image = read_color_image(ctx, x, y, type, width, height);
       if (!image) {
          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D" );
          return;
@@ -580,7 +592,7 @@ _swrast_copy_texsubimage3d( GLcontext *ctx,
       /* now call glTexSubImage3D to do the real work */
       ctx->Driver.TexSubImage3D(ctx, target, level,
                                 xoffset, yoffset, zoffset, width, height, 1,
-                                GL_RGBA, CHAN_TYPE, image,
+                                format, type, image,
                                 &ctx->DefaultPacking, texObj, texImage);
       _mesa_free(image);
    }