finished convolution
authorBrian Paul <brian.paul@tungstengraphics.com>
Sat, 2 Sep 2000 17:52:21 +0000 (17:52 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Sat, 2 Sep 2000 17:52:21 +0000 (17:52 +0000)
src/mesa/main/teximage.c

index 2fb8e8b4041ca9a60dca963d829394cc166569da..92fd5cfb6bf47e8f982c76dc75230a635a7623f3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teximage.c,v 1.44 2000/09/01 22:01:12 brianp Exp $ */
+/* $Id: teximage.c,v 1.45 2000/09/02 17:52:21 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -670,184 +670,157 @@ adjust_texture_size_for_convolution(const GLcontext *ctx, GLuint dimensions,
 
 
 
-/* Need this to prevent an out-of-bounds memory access when using
- * X86 optimized code.
- */
-#ifdef USE_X86_ASM
-#  define EXTRA_BYTE 1
-#else
-#  define EXTRA_BYTE 0
-#endif
-
-
-
 /*
- * Called by glTexImage[123]D.  Fill in a texture image with data given
- * by the client.  All pixel transfer and unpack modes are handled here.
- * Input:  dimensions (1, 2, or 3)
- *         texImage - destination texture image (we'll malloc the memory)
- *         width, height, depth - size of source image
- *         srcFormat, srcType - source image format and type
- *         pixels - source image data
- *         srcPacking - source image packing parameters
- *
- * NOTE: All texture image parameters should have already been error checked.
- *
- * NOTE: the texImage dimensions and source image dimensions must be correct
- * with respect to convolution with border mode = reduce.
+ * This function is used to move user image data into a texture image.
+ * We handle full texture images and subtexture images.  We also take
+ * care of all image transfer operations here, including convolution.
+ * Input:
+ *         dstXoffset, dstYoffset, dstZoffset - offsets in pixels
+ *         dstRowStride, dstImageStride - strides in bytes
  */
 static void
-make_texture_image( GLcontext *ctx, GLuint dimensions,
-                    struct gl_texture_image *texImage,
-                    GLint width, GLint height, GLint depth,
-                    GLenum srcFormat, GLenum srcType, const GLvoid *pixels,
+fill_texture_image( GLcontext *ctx, GLuint dimensions,
+                    GLenum texFormat, GLubyte *texAddr,
+                    GLint srcWidth, GLint srcHeight, GLint srcDepth,
+                    GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
+                    GLint dstRowStride, GLint dstImageStride,
+                    GLenum srcFormat, GLenum srcType, const GLvoid *srcAddr,
                     const struct gl_pixelstore_attrib *srcPacking)
 {
-   GLint components, numPixels;
-   GLint internalFormat, border;
+   GLint texComponents;
 
    ASSERT(ctx);
-   ASSERT(texImage);
-   ASSERT(!texImage->Data);
-   ASSERT(pixels);
+   ASSERT(dimensions >= 1 && dimensions <= 3);
+   ASSERT(texAddr);
+   ASSERT(srcWidth >= 1);
+   ASSERT(srcHeight >= 1);
+   ASSERT(srcDepth >= 1);
+   ASSERT(dstXoffset >= 0);
+   ASSERT(dstYoffset >= 0);
+   ASSERT(dstZoffset >= 0);
+   ASSERT(dstRowStride >= 0);
+   ASSERT(dstImageStride >= 0);
+   ASSERT(srcAddr);
    ASSERT(srcPacking);
 
-   internalFormat = texImage->IntFormat;
-   border = texImage->Border;
-   components = components_in_intformat(internalFormat);
-
-   ASSERT(width > 0);
-   ASSERT(height > 0);
-   ASSERT(depth > 0);
-   ASSERT(border == 0 || border == 1);
-   ASSERT(components);
-
-   numPixels = width * height * depth;
-
-   texImage->Data = (GLubyte *) MALLOC(numPixels * components + EXTRA_BYTE);
-   if (!texImage->Data)
-      return;      /* out of memory */
-
-   /*
-    * OK, the texture image struct has been initialized and the texture
-    * image memory has been allocated.
-    * Now fill in the texture image from the source data.
-    * This includes applying the pixel transfer operations.
-    */
-
-   if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE)
-      _mesa_update_image_transfer_state(ctx);
+   texComponents = components_in_intformat(texFormat);
 
    /* try common 2D texture cases first */
-   if (!ctx->ImageTransferState && srcType == GL_UNSIGNED_BYTE && depth == 1) {
+   if (!ctx->ImageTransferState && dimensions == 2
+       && srcType == GL_UNSIGNED_BYTE) {
 
-      if (srcFormat == internalFormat ||
-          (srcFormat == GL_LUMINANCE && internalFormat == 1) ||
-          (srcFormat == GL_LUMINANCE_ALPHA && internalFormat == 2) ||
-          (srcFormat == GL_RGB && internalFormat == 3) ||
-          (srcFormat == GL_RGBA && internalFormat == 4)) {
+      if (srcFormat == texFormat) {
          /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA,
-          * GL_LUMINANCE_ALPHA, etc. texture formats.
+          * GL_LUMINANCE_ALPHA, etc. texture formats.  Use memcpy().
           */
          const GLubyte *src = (const GLubyte *) _mesa_image_address(
-            srcPacking, pixels, width, height, srcFormat, srcType, 0, 0, 0);
-         const GLint srcStride = _mesa_image_row_stride(srcPacking, width,
-                                                        srcFormat, srcType);
-         GLubyte *dst = texImage->Data;
-         GLint dstBytesPerRow = width * components * sizeof(GLubyte);
-         if (srcStride == dstBytesPerRow) {
-            MEMCPY(dst, src, height * dstBytesPerRow);
+                                   srcPacking, srcAddr, srcWidth, srcHeight,
+                                   srcFormat, srcType, 0, 0, 0);
+         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
+                                               srcWidth, srcFormat, srcType);
+         const GLint widthInBytes = srcWidth * texComponents;
+         GLubyte *dst = texAddr + dstYoffset * dstRowStride
+                      + dstXoffset * texComponents * sizeof(GLubyte);
+         if (srcRowStride == widthInBytes && dstRowStride == widthInBytes) {
+            MEMCPY(dst, src, srcHeight * widthInBytes);
          }
          else {
             GLint i;
-            for (i = 0; i < height; i++) {
-               MEMCPY(dst, src, dstBytesPerRow);
-               src += srcStride;
-               dst += dstBytesPerRow;
+            for (i = 0; i < srcHeight; i++) {
+               MEMCPY(dst, src, widthInBytes);
+               src += srcRowStride;
+               dst += dstRowStride;
             }
          }
          return;  /* all done */
       }
-      else if (srcFormat == GL_RGBA && internalFormat == GL_RGB) {
+      else if (srcFormat == GL_RGBA && texFormat == GL_RGB) {
          /* commonly used by Quake */
          const GLubyte *src = (const GLubyte *) _mesa_image_address(
-            srcPacking, pixels, width, height, srcFormat, srcType, 0, 0, 0);
-         const GLint srcStride = _mesa_image_row_stride(srcPacking, width,
-                                                        srcFormat, srcType);
-         GLubyte *dst = texImage->Data;
+                                   srcPacking, srcAddr, srcWidth, srcHeight,
+                                   srcFormat, srcType, 0, 0, 0);
+         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
+                                               srcWidth, srcFormat, srcType);
+         GLubyte *dst = texAddr + dstYoffset * dstRowStride
+                      + dstXoffset * texComponents * sizeof(GLubyte);
          GLint i, j;
-         for (i = 0; i < height; i++) {
+         for (i = 0; i < srcHeight; i++) {
             const GLubyte *s = src;
-            for (j = 0; j < width; j++) {
-               *dst++ = *s++;  /*red*/
-               *dst++ = *s++;  /*green*/
-               *dst++ = *s++;  /*blue*/
-               s++;            /*alpha*/
+            GLubyte *d = dst;
+            for (j = 0; j < srcWidth; j++) {
+               *d++ = *s++;  /*red*/
+               *d++ = *s++;  /*green*/
+               *d++ = *s++;  /*blue*/
+               s++;          /*alpha*/
             }
-            src += srcStride;
+            src += srcRowStride;
+            dst += dstRowStride;
          }
          return;  /* all done */
       }
    }      
 
-
    /*
     * General case solutions
     */
-   if (texImage->Format == GL_COLOR_INDEX) {
+   if (texFormat == GL_COLOR_INDEX) {
       /* color index texture */
-      const GLint destBytesPerRow = width * components * sizeof(GLubyte);
-      const GLenum dstType = GL_UNSIGNED_BYTE;
-      GLubyte *destTex = texImage->Data;
+      const GLenum texType = GL_UNSIGNED_BYTE;
       GLint img, row;
-      for (img = 0; img < depth; img++) {
-         for (row = 0; row < height; row++) {
-            const GLvoid *srcAddr = _mesa_image_address(srcPacking,
-                pixels, width, height, srcFormat, srcType, img, row, 0);
-            _mesa_unpack_index_span(ctx, width, dstType, destTex,
-                                    srcType, srcAddr, srcPacking,
+      GLubyte *dest = texAddr + dstZoffset * dstImageStride
+                    + dstYoffset * dstRowStride
+                    + dstXoffset * texComponents * sizeof(GLubyte);
+      for (img = 0; img < srcDepth; img++) {
+         GLubyte *destRow = dest;
+         for (row = 0; row < srcHeight; row++) {
+            const GLvoid *src = _mesa_image_address(srcPacking,
+                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
+            _mesa_unpack_index_span(ctx, srcWidth, texType, destRow,
+                                    srcType, src, srcPacking,
                                     ctx->ImageTransferState);
-            destTex += destBytesPerRow;
+            destRow += dstRowStride;
          }
+         dest += dstImageStride;
       }
    }
    else {
       /* regular, color texture */
-      GLint destBytesPerRow;
-      const GLenum dstFormat = texImage->Format;
-      GLubyte *destTex = texImage->Data;
-      GLint img, row;
-      GLint convWidth = width, convHeight = height;
-
       if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) ||
-          (dimensions >= 2 &&
-           (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled)
-           )) {
+          (dimensions >= 2 && ctx->Pixel.Convolution2DEnabled) ||
+          (dimensions >= 2 && ctx->Pixel.Separable2DEnabled)) {
+         /*
+          * Fill texture image with convolution
+          */
+         GLint img, row;
+         GLint convWidth = srcWidth, convHeight = srcHeight;
          GLfloat *tmpImage, *convImage;
-         tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+         tmpImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
          if (!tmpImage) {
             gl_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
             return;
          }
-         convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+         convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
          if (!convImage) {
             gl_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
             FREE(tmpImage);
             return;
          }
 
-         for (img = 0; img < depth; img++) {
+         for (img = 0; img < srcDepth; img++) {
             const GLfloat *srcf;
             GLfloat *dstf = tmpImage;
+            GLubyte *dest;
+
             /* unpack and do transfer ops up to convolution */
-            for (row = 0; row < height; row++) {
-               const GLvoid *srcAddr = _mesa_image_address(srcPacking,
-                      pixels, width, height, srcFormat, srcType, img, row, 0);
-               _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dstf,
-                      srcFormat, srcType, srcAddr, srcPacking,
-                      ctx->ImageTransferState & IMAGE_PRE_CONVOLUTION_BITS,
-                      GL_TRUE);
-               dstf += width * 4;
+            for (row = 0; row < srcHeight; row++) {
+               const GLvoid *src = _mesa_image_address(srcPacking,
+                                              srcAddr, srcWidth, srcHeight,
+                                              srcFormat, srcType, img, row, 0);
+               _mesa_unpack_float_color_span(ctx, srcWidth, GL_RGBA, dstf,
+                          srcFormat, srcType, src, srcPacking,
+                          ctx->ImageTransferState & IMAGE_PRE_CONVOLUTION_BITS,
+                          GL_TRUE);
+               dstf += srcWidth * 4;
             }
 
             /* convolve */
@@ -869,16 +842,17 @@ make_texture_image( GLcontext *ctx, GLuint dimensions,
 
             /* packing and transfer ops after convolution */
             srcf = convImage;
-            destBytesPerRow = convWidth * components * sizeof(GLubyte);
+            dest = texAddr + (dstZoffset + img) * dstImageStride
+                 + dstYoffset * dstRowStride;
             for (row = 0; row < convHeight; row++) {
                _mesa_pack_float_rgba_span(ctx, convWidth,
                                           (const GLfloat (*)[4]) srcf,
-                                          dstFormat, GL_UNSIGNED_BYTE,
-                                          destTex, &_mesa_native_packing,
+                                          texFormat, GL_UNSIGNED_BYTE,
+                                          dest, &_mesa_native_packing,
                                           ctx->ImageTransferState
                                           & IMAGE_POST_CONVOLUTION_BITS);
                srcf += convWidth * 4;
-               destTex += destBytesPerRow;
+               dest += dstRowStride;
             }
          }
 
@@ -886,17 +860,25 @@ make_texture_image( GLcontext *ctx, GLuint dimensions,
          FREE(tmpImage);
       }
       else {
-         /* no convolution */
-         destBytesPerRow = width * components * sizeof(GLubyte);
-         for (img = 0; img < depth; img++) {
-            for (row = 0; row < height; row++) {
+         /*
+          * no convolution
+          */
+         GLint img, row;
+         GLubyte *dest = texAddr + dstZoffset * dstImageStride
+                       + dstYoffset * dstRowStride
+                       + dstXoffset * texComponents * sizeof(GLubyte);
+         for (img = 0; img < srcDepth; img++) {
+            GLubyte *destRow = dest;
+            for (row = 0; row < srcHeight; row++) {
                const GLvoid *srcAddr = _mesa_image_address(srcPacking,
-                      pixels, width, height, srcFormat, srcType, img, row, 0);
-               _mesa_unpack_ubyte_color_span(ctx, width, dstFormat, destTex,
-                      srcFormat, srcType, srcAddr, srcPacking,
-                      ctx->ImageTransferState);
-               destTex += destBytesPerRow;
+                                              srcAddr, srcWidth, srcHeight,
+                                              srcFormat, srcType, img, row, 0);
+               _mesa_unpack_ubyte_color_span(ctx, srcWidth, texFormat, destRow,
+                                       srcFormat, srcType, srcAddr, srcPacking,
+                                       ctx->ImageTransferState);
+               destRow += dstRowStride;
             }
+            dest += dstImageStride;
          }
       }
    }
@@ -904,6 +886,66 @@ make_texture_image( GLcontext *ctx, GLuint dimensions,
 
 
 
+/* Need this to prevent an out-of-bounds memory access when using
+ * X86 optimized code.
+ */
+#ifdef USE_X86_ASM
+#  define EXTRA_BYTE 1
+#else
+#  define EXTRA_BYTE 0
+#endif
+
+
+
+/*
+ * Called by glTexImage[123]D.  Fill in a texture image with data given
+ * by the client.  All pixel transfer and unpack modes are handled here.
+ * Input:  dimensions (1, 2, or 3)
+ *         texImage - destination texture image (we'll malloc the memory)
+ *         width, height, depth - size of source image
+ *         srcFormat, srcType - source image format and type
+ *         pixels - source image data
+ *         srcPacking - source image packing parameters
+ *
+ * NOTE: All texture image parameters should have already been error checked.
+ *
+ * NOTE: the texImage dimensions and source image dimensions must be correct
+ * with respect to convolution with border mode = reduce.
+ */
+static void
+make_texture_image( GLcontext *ctx, GLuint dimensions,
+                    struct gl_texture_image *texImage,
+                    GLint width, GLint height, GLint depth,
+                    GLenum srcFormat, GLenum srcType, const GLvoid *pixels,
+                    const struct gl_pixelstore_attrib *srcPacking)
+{
+   const GLint internalFormat = texImage->IntFormat;
+   const GLint components = components_in_intformat(internalFormat);
+   GLint convWidth = width, convHeight = height;
+
+   if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE) {
+      _mesa_update_image_transfer_state(ctx);
+   }
+
+   if (ctx->ImageTransferState & IMAGE_CONVOLUTION_BIT) {
+      adjust_texture_size_for_convolution(ctx, dimensions,
+                                          &convWidth, &convHeight);
+   }
+
+   texImage->Data = (GLubyte *) MALLOC(convWidth * convHeight * depth
+                                       * components + EXTRA_BYTE);
+   if (!texImage->Data)
+      return;      /* out of memory */
+
+   fill_texture_image(ctx, dimensions, texImage->Format, texImage->Data,
+                      width, height, depth, 0, 0, 0,
+                      convWidth * components * sizeof(GLubyte),
+                      convWidth * convHeight * components * sizeof(GLubyte),
+                      srcFormat, srcType, pixels, srcPacking);
+}
+
+
+
 /*
  * glTexImage[123]D can accept a NULL image pointer.  In this case we
  * create a texture image with unspecified image contents per the OpenGL
@@ -2213,9 +2255,13 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLboolean success = GL_FALSE;
+   GLsizei postConvWidth;
+
+   postConvWidth = width;
+   adjust_texture_size_for_convolution(ctx, 1, &postConvWidth, NULL);
 
    if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0,
-                              width, 1, 1, format, type)) {
+                              postConvWidth, 1, 1, format, type)) {
       return;   /* error was detected */
    }
 
@@ -2237,10 +2283,6 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
    }
    if (!success) {
       /* XXX if Driver.TexSubImage1D, unpack image and try again? */
-
-      const GLint texComponents = components_in_intformat(texImage->Format);
-      const GLenum texFormat = texImage->Format;
-      const GLint xoffsetb = xoffset + texImage->Border;
       GLboolean retain = GL_TRUE;
       if (!texImage->Data) {
          _mesa_get_teximage_from_driver( ctx, target, level, texObj );
@@ -2251,25 +2293,10 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
             return;  /* we're really out of luck! */
       }
 
-      if (texFormat == GL_COLOR_INDEX) {
-         /* color index texture */
-         GLubyte *dst = texImage->Data + xoffsetb * texComponents;
-         const GLvoid *src = _mesa_image_address(&ctx->Unpack, pixels, width,
-                                                 1, format, type, 0, 0, 0);
-         _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst,
-                                 type, src, &ctx->Unpack,
-                                 ctx->ImageTransferState);
-      }
-      else {
-         /* color texture */
-         GLubyte *dst = texImage->Data + xoffsetb * texComponents;
-         const GLvoid *src = _mesa_image_address(&ctx->Unpack, pixels, width,
-                                                 1, format, type, 0, 0, 0);
-         /* XXX change for convolution */
-         _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst, format,
-                                       type, src, &ctx->Unpack,
-                                       ctx->ImageTransferState);
-      }
+      fill_texture_image(ctx, 1, texImage->Format, texImage->Data,
+                         width, 1, 1, xoffset, 0, 0, /* size and offsets */
+                         0, 0, /* strides */
+                         format, type, pixels, &ctx->Unpack);
 
       if (ctx->Driver.TexImage1D) {
          (*ctx->Driver.TexImage1D)( ctx, target, level, texImage->Format,
@@ -2283,8 +2310,6 @@ _mesa_TexSubImage1D( GLenum target, GLint level,
          texImage->Data = NULL;
       }
    }
-
-   /*gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[1] );*/
 }
 
 
@@ -2300,9 +2325,14 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
    GLboolean success = GL_FALSE;
+   GLsizei postConvWidth, postConvHeight;
+
+   postConvWidth = width;
+   postConvHeight = height;
+   adjust_texture_size_for_convolution(ctx, 2, &postConvWidth,&postConvHeight);
 
    if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0,
-                              width, height, 1, format, type)) {
+                             postConvWidth, postConvHeight, 1, format, type)) {
       return;   /* error was detected */
    }
 
@@ -2324,14 +2354,8 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
    }
    if (!success) {
       /* XXX if Driver.TexSubImage2D, unpack image and try again? */
-
-      const GLint texComponents = components_in_intformat(texImage->Format);
-      const GLenum texFormat = texImage->Format;
-      const GLint xoffsetb = xoffset + texImage->Border;
-      const GLint yoffsetb = yoffset + texImage->Border;
-      const GLint srcStride = _mesa_image_row_stride(&ctx->Unpack, width,
-                                                     format, type);
-      const GLint dstStride = texImage->Width * texComponents *sizeof(GLubyte);
+      const GLint texComps = components_in_intformat(texImage->Format);
+      const GLint texRowStride = texImage->Width * texComps * sizeof(GLubyte);
       GLboolean retain = GL_TRUE;
 
       if (!texImage->Data) {
@@ -2343,38 +2367,10 @@ _mesa_TexSubImage2D( GLenum target, GLint level,
             return;  /* we're really out of luck! */
       }
 
-      if (texFormat == GL_COLOR_INDEX) {
-         /* color index texture */
-         GLubyte *dst = texImage->Data
-                    + (yoffsetb * texImage->Width + xoffsetb) * texComponents;
-         const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels,
-                                     width, height, format, type, 0, 0, 0);
-         GLint row;
-         for (row = 0; row < height; row++) {
-            _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst, type,
-                                    (const GLvoid *) src, &ctx->Unpack,
-                                    ctx->ImageTransferState);
-            src += srcStride;
-            dst += dstStride;
-         }
-      }
-      else {
-         /* color texture */
-         GLubyte *dst = texImage->Data
-                    + (yoffsetb * texImage->Width + xoffsetb) * texComponents;
-         const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels,
-                                     width, height, format, type, 0, 0, 0);
-         GLint row;
-         /* XXX change for convolution */
-         for (row = 0; row < height; row++) {
-            _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst, format,
-                                          type, (const GLvoid *) src,
-                                          &ctx->Unpack,
-                                          ctx->ImageTransferState);
-            src += srcStride;
-            dst += dstStride;
-         }
-      }
+      fill_texture_image(ctx, 2, texImage->Format, texImage->Data,
+                         width, height, 1, xoffset, yoffset, 0,
+                         texRowStride, 0,
+                         format, type, pixels, &ctx->Unpack);
 
       if (ctx->Driver.TexImage2D) {
          (*ctx->Driver.TexImage2D)(ctx, target, level, texImage->Format,
@@ -2441,57 +2437,25 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
    }
    if (!success) {
       /* XXX if Driver.TexSubImage3D, unpack image and try again? */
-
-      const GLint texComponents = components_in_intformat(texImage->Format);
-      const GLenum texFormat = texImage->Format;
-      const GLint xoffsetb = xoffset + texImage->Border;
-      const GLint yoffsetb = yoffset + texImage->Border;
-      const GLint zoffsetb = zoffset + texImage->Border;
-      const GLint texWidth = texImage->Width;
-      const GLint dstRectArea = texWidth * texImage->Height;
-      const GLint srcStride = _mesa_image_row_stride(&ctx->Unpack,
-                                                     width, format, type);
-      const GLint dstStride = texWidth * texComponents * sizeof(GLubyte);
+      const GLint texComps = components_in_intformat(texImage->Format);
+      const GLint texRowStride = texImage->Width * texComps * sizeof(GLubyte);
+      const GLint texImgStride = texRowStride * texImage->Height;
       GLboolean retain = GL_TRUE;
 
-      if (texFormat == GL_COLOR_INDEX) {
-         /* color index texture */
-         GLint img, row;
-         for (img = 0; img < depth; img++) {
-            const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels,
-                                    width, height, format, type, img, 0, 0);
-            GLubyte *dst = texImage->Data + ((zoffsetb + img) * dstRectArea
-                     + yoffsetb * texWidth + xoffsetb) * texComponents;
-            for (row = 0; row < height; row++) {
-               _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst,
-                                       type, (const GLvoid *) src,
-                                       &ctx->Unpack, ctx->ImageTransferState);
-               src += srcStride;
-               dst += dstStride;
-            }
-         }
-      }
-      else {
-         /* color texture */
-         GLint img, row;
-         /* XXX convolution */
-         for (img = 0; img < depth; img++) {
-            const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels,
-                                     width, height, format, type, img, 0, 0);
-            GLubyte *dst = texImage->Data + ((zoffsetb + img) * dstRectArea
-                     + yoffsetb * texWidth + xoffsetb) * texComponents;
-            for (row = 0; row < height; row++) {
-               _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst,
-                                             format, type,
-                                             (const GLvoid *) src,
-                                             &ctx->Unpack,
-                                             ctx->ImageTransferState);
-               src += srcStride;
-               dst += dstStride;
-            }
+      if (!texImage->Data) {
+         _mesa_get_teximage_from_driver( ctx, target, level, texObj );
+         if (!texImage->Data) {
+            make_null_texture(texImage);
          }
+         if (!texImage->Data)
+            return;  /* we're really out of luck! */
       }
 
+      fill_texture_image(ctx, 3, texImage->Format, texImage->Data,
+                         width, height, depth, xoffset, yoffset, zoffset,
+                         texRowStride, texImgStride,
+                         format, type, pixels, &ctx->Unpack);
+
       if (ctx->Driver.TexImage3D) {
          (*ctx->Driver.TexImage3D)(ctx, target, level, texImage->Format,
                                    GL_UNSIGNED_BYTE, texImage->Data,
@@ -2510,7 +2474,7 @@ _mesa_TexSubImage3D( GLenum target, GLint level,
 
 /*
  * Read an RGBA image from the frame buffer.
- * This is used by glCopyTexSubImage[12]D().
+ * 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
@@ -2531,8 +2495,6 @@ read_color_image( GLcontext *ctx, GLint x, GLint y,
    (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
                                  ctx->Pixel.DriverReadBuffer );
 
-   /* XXX TODO we have to apply pixel transfer ops here! */
-
    dst = image;
    stride = width * 4 * sizeof(GLubyte);
    for (i = 0; i < height; i++) {
@@ -2568,12 +2530,11 @@ _mesa_CopyTexImage1D( GLenum target, GLint level,
 
    if (ctx->ImageTransferState || !ctx->Driver.CopyTexImage1D 
        || !(*ctx->Driver.CopyTexImage1D)(ctx, target, level,
-                         internalFormat, x, y, width, border))
-   {
+                         internalFormat, x, y, width, border)) {
       struct gl_pixelstore_attrib unpackSave;
 
       /* get image from framebuffer */
-      GLubyte *image  = read_color_image( ctx, x, y, width, 1 );
+      GLubyte *image = read_color_image( ctx, x, y, width, 1 );
       if (!image) {
          gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D" );
          return;
@@ -2609,12 +2570,11 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
 
    if (ctx->ImageTransferState || !ctx->Driver.CopyTexImage2D
        || !(*ctx->Driver.CopyTexImage2D)(ctx, target, level,
-                         internalFormat, x, y, width, height, border))
-   {
+                         internalFormat, x, y, width, height, border)) {
       struct gl_pixelstore_attrib unpackSave;
 
       /* get image from framebuffer */
-      GLubyte *image  = read_color_image( ctx, x, y, width, height );
+      GLubyte *image = read_color_image( ctx, x, y, width, height );
       if (!image) {
          gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D" );
          return;