/* $Id: texstore.c,v 1.10 2001/03/07 05:06:12 brianp Exp $ */

/*
 * Mesa 3-D graphics library
 * Version:  3.5
 *
 * Copyright (C) 1999-2001  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"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * Authors:
 *   Brian Paul
 */


/*
 * The functions in this file are mostly related to software texture fallbacks.
 * This includes texture image transfer/packing and texel fetching.
 * Hardware drivers will likely override most of this.
 */



#include "colormac.h"
#include "context.h"
#include "convolve.h"
#include "image.h"
#include "macros.h"
#include "mem.h"
#include "teximage.h"
#include "texstore.h"
#include "swrast/s_depth.h"  /* XXX this is kind of a cheat */
#include "swrast/s_span.h"


/*
 * Default 1-D texture texel fetch function.  This will typically be
 * overridden by hardware drivers which store their texture images in
 * special ways.
 */
static void
fetch_1d_texel(const struct gl_texture_image *img,
               GLint i, GLint j, GLint k, GLvoid *texel)
{
   switch (img->Format) {
   case GL_RGBA:
      {
         const GLchan *src = (GLchan *) img->Data + i * 4;
         GLchan *rgba = (GLchan *) texel;
         COPY_CHAN4(rgba, src);
         return;
      }
   case GL_RGB:
      {
         const GLchan *src = (GLchan *) img->Data + i * 3;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[1];
         rgba[BCOMP] = src[2];
         rgba[ACOMP] = CHAN_MAX;
         return;
      }
   case GL_ALPHA:
      {
         const GLchan *src = (GLchan *) img->Data + i;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = 0;
         rgba[GCOMP] = 0;
         rgba[BCOMP] = 0;
         rgba[ACOMP] = src[0];
         return;
      }
   case GL_LUMINANCE:
      {
         const GLchan *src = (GLchan *) img->Data + i;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = CHAN_MAX;
         return;
      }
   case GL_INTENSITY:
      {
         const GLchan *src = (GLchan *) img->Data + i;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = src[0];
         return;
      }
   case GL_LUMINANCE_ALPHA:
      {
         const GLchan *src = (GLchan *) img->Data + i * 2;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = src[1];
         return;
      }
   case GL_COLOR_INDEX:
      {
         const GLchan *src = (GLchan *) img->Data + i;
         GLchan *index = (GLchan *) texel;
         *index = *src;
         return;
      }
   case GL_DEPTH_COMPONENT:
      {
         const GLfloat *src = (GLfloat *) img->Data + i;
         GLfloat *depth = (GLfloat *) texel;
         *depth = *src;
         return;
      }
   default:
      _mesa_problem(NULL, "Bad format in fetch_1d_texel");
   }
}


/*
 * Default 2-D texture texel fetch function.
 */
static void
fetch_2d_texel(const struct gl_texture_image *img,
               GLint i, GLint j, GLint k, GLvoid *texel)
{
   switch (img->Format) {
   case GL_RGBA:
      {
         const GLchan *src = (GLchan *) img->Data + (img->Width * j + i) * 4;
         GLchan *rgba = (GLchan *) texel;
         COPY_CHAN4(rgba, src);
         return;
      }
   case GL_RGB:
      {
         const GLchan *src = (GLchan *) img->Data + (img->Width * j + i) * 3;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[1];
         rgba[BCOMP] = src[2];
         rgba[ACOMP] = CHAN_MAX;
         return;
      }
   case GL_ALPHA:
      {
         const GLchan *src = (GLchan *) img->Data + (img->Width * j + i);
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = 0;
         rgba[GCOMP] = 0;
         rgba[BCOMP] = 0;
         rgba[ACOMP] = src[0];
         return;
      }
   case GL_LUMINANCE:
      {
         const GLchan *src = (GLchan *) img->Data + (img->Width * j + i);
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = CHAN_MAX;
         return;
      }
   case GL_INTENSITY:
      {
         const GLchan *src = (GLchan *) img->Data + (img->Width * j + i);
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = src[0];
         return;
      }
   case GL_LUMINANCE_ALPHA:
      {
         const GLchan *src = (GLchan *) img->Data + (img->Width * j + i) * 2;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = src[1];
         return;
      }
   case GL_COLOR_INDEX:
      {
         const GLchan *src = (GLchan *) img->Data + (img->Width * j + i);
         GLchan *index = (GLchan *) texel;
         *index = *src;
         return;
      }
   case GL_DEPTH_COMPONENT:
      {
         const GLfloat *src = (GLfloat *) img->Data + (img->Width * j + i);
         GLfloat *depth = (GLfloat *) texel;
         *depth = *src;
         return;
      }
   default:
      _mesa_problem(NULL, "Bad format in fetch_2d_texel");
   }
}


/*
 * Default 2-D texture texel fetch function.
 */
static void
fetch_3d_texel(const struct gl_texture_image *img,
               GLint i, GLint j, GLint k, GLvoid *texel)
{
   const GLint width = img->Width;
   const GLint rectArea = width * img->Height;

   switch (img->Format) {
   case GL_RGBA:
      {
         const GLchan *src = (GLchan *) img->Data
                           + (rectArea * k + width * j + i) * 4;
         GLchan *rgba = (GLchan *) texel;
         COPY_CHAN4(rgba, src);
         return;
      }
   case GL_RGB:
      {
         const GLchan *src = (GLchan *) img->Data
                           + (rectArea * k + width * j + i) * 3;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[1];
         rgba[BCOMP] = src[2];
         rgba[ACOMP] = CHAN_MAX;
         return;
      }
   case GL_ALPHA:
      {
         const GLchan *src = (GLchan *) img->Data
                           + (rectArea * k + width * j + i);
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = 0;
         rgba[GCOMP] = 0;
         rgba[BCOMP] = 0;
         rgba[ACOMP] = src[0];
         return;
      }
   case GL_LUMINANCE:
      {
         const GLchan *src = (GLchan *) img->Data
                           + (rectArea * k + width * j + i);
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = CHAN_MAX;
         return;
      }
   case GL_INTENSITY:
      {
         const GLchan *src = (GLchan *) img->Data
                           + (rectArea * k + width * j + i);
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = src[0];
         return;
      }
   case GL_LUMINANCE_ALPHA:
      {
         const GLchan *src = (GLchan *) img->Data
                           + (rectArea * k + width * j + i) * 2;
         GLchan *rgba = (GLchan *) texel;
         rgba[RCOMP] = src[0];
         rgba[GCOMP] = src[0];
         rgba[BCOMP] = src[0];
         rgba[ACOMP] = src[1];
         return;
      }
   case GL_COLOR_INDEX:
      {
         const GLchan *src = (GLchan *) img->Data
                           + (rectArea * k + width * j + i);
         GLchan *index = (GLchan *) texel;
         *index = *src;
         return;
      }
   case GL_DEPTH_COMPONENT:
      {
         const GLfloat *src = (GLfloat *) img->Data
                            + (rectArea * k + width * j + i);
         GLfloat *depth = (GLfloat *) texel;
         *depth = *src;
         return;
      }
   default:
      _mesa_problem(NULL, "Bad format in fetch_3d_texel");
   }
}



/*
 * Examine the texImage->Format field and set the Red, Green, Blue, etc
 * texel component sizes to default values.
 * These fields are set only here by core Mesa but device drivers may
 * overwritting these fields to indicate true texel resolution.
 */
static void
set_teximage_component_sizes( struct gl_texture_image *texImage )
{
   switch (texImage->Format) {
      case GL_ALPHA:
         texImage->RedBits = 0;
         texImage->GreenBits = 0;
         texImage->BlueBits = 0;
         texImage->AlphaBits = 8 * sizeof(GLchan);
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_LUMINANCE:
         texImage->RedBits = 0;
         texImage->GreenBits = 0;
         texImage->BlueBits = 0;
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 8 * sizeof(GLchan);
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_LUMINANCE_ALPHA:
         texImage->RedBits = 0;
         texImage->GreenBits = 0;
         texImage->BlueBits = 0;
         texImage->AlphaBits = 8 * sizeof(GLchan);
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 8 * sizeof(GLchan);
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_INTENSITY:
         texImage->RedBits = 0;
         texImage->GreenBits = 0;
         texImage->BlueBits = 0;
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 8 * sizeof(GLchan);
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_RED:
         texImage->RedBits = 8 * sizeof(GLchan);
         texImage->GreenBits = 0;
         texImage->BlueBits = 0;
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_GREEN:
         texImage->RedBits = 0;
         texImage->GreenBits = 8 * sizeof(GLchan);
         texImage->BlueBits = 0;
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_BLUE:
         texImage->RedBits = 0;
         texImage->GreenBits = 0;
         texImage->BlueBits = 8 * sizeof(GLchan);
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_RGB:
      case GL_BGR:
         texImage->RedBits = 8 * sizeof(GLchan);
         texImage->GreenBits = 8 * sizeof(GLchan);
         texImage->BlueBits = 8 * sizeof(GLchan);
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_RGBA:
      case GL_BGRA:
      case GL_ABGR_EXT:
         texImage->RedBits = 8 * sizeof(GLchan);
         texImage->GreenBits = 8 * sizeof(GLchan);
         texImage->BlueBits = 8 * sizeof(GLchan);
         texImage->AlphaBits = 8 * sizeof(GLchan);
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 0;
         break;
      case GL_COLOR_INDEX:
         texImage->RedBits = 0;
         texImage->GreenBits = 0;
         texImage->BlueBits = 0;
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 8 * sizeof(GLchan);
         texImage->DepthBits = 0;
         break;
      case GL_DEPTH_COMPONENT:
         texImage->RedBits = 0;
         texImage->GreenBits = 0;
         texImage->BlueBits = 0;
         texImage->AlphaBits = 0;
         texImage->IntensityBits = 0;
         texImage->LuminanceBits = 0;
         texImage->IndexBits = 0;
         texImage->DepthBits = 8 * sizeof(GLfloat);
         break;
      default:
         _mesa_problem(NULL, "unexpected format in set_teximage_component_sizes");
   }
}



/*
 * Given an internal texture format enum or 1, 2, 3, 4 return the
 * corresponding _base_ internal format:  GL_ALPHA, GL_LUMINANCE,
 * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA.  Return the
 * number of components for the format.  Return -1 if invalid enum.
 */
static GLint
components_in_intformat( GLint format )
{
   switch (format) {
      case GL_ALPHA:
      case GL_ALPHA4:
      case GL_ALPHA8:
      case GL_ALPHA12:
      case GL_ALPHA16:
         return 1;
      case 1:
      case GL_LUMINANCE:
      case GL_LUMINANCE4:
      case GL_LUMINANCE8:
      case GL_LUMINANCE12:
      case GL_LUMINANCE16:
         return 1;
      case 2:
      case GL_LUMINANCE_ALPHA:
      case GL_LUMINANCE4_ALPHA4:
      case GL_LUMINANCE6_ALPHA2:
      case GL_LUMINANCE8_ALPHA8:
      case GL_LUMINANCE12_ALPHA4:
      case GL_LUMINANCE12_ALPHA12:
      case GL_LUMINANCE16_ALPHA16:
         return 2;
      case GL_INTENSITY:
      case GL_INTENSITY4:
      case GL_INTENSITY8:
      case GL_INTENSITY12:
      case GL_INTENSITY16:
         return 1;
      case 3:
      case GL_RGB:
      case GL_R3_G3_B2:
      case GL_RGB4:
      case GL_RGB5:
      case GL_RGB8:
      case GL_RGB10:
      case GL_RGB12:
      case GL_RGB16:
         return 3;
      case 4:
      case GL_RGBA:
      case GL_RGBA2:
      case GL_RGBA4:
      case GL_RGB5_A1:
      case GL_RGBA8:
      case GL_RGB10_A2:
      case GL_RGBA12:
      case GL_RGBA16:
         return 4;
      case GL_COLOR_INDEX:
      case GL_COLOR_INDEX1_EXT:
      case GL_COLOR_INDEX2_EXT:
      case GL_COLOR_INDEX4_EXT:
      case GL_COLOR_INDEX8_EXT:
      case GL_COLOR_INDEX12_EXT:
      case GL_COLOR_INDEX16_EXT:
         return 1;
      case GL_DEPTH_COMPONENT:
      case GL_DEPTH_COMPONENT16_SGIX:
      case GL_DEPTH_COMPONENT24_SGIX:
      case GL_DEPTH_COMPONENT32_SGIX:
         return 1;
      default:
         return -1;  /* error */
   }
}


/*
 * This function is used to transfer the user's image data into a texture
 * image buffer.  We handle both full texture images and subtexture images.
 * We also take care of all image transfer operations here, including
 * convolution, scale/bias, colortables, etc.
 *
 * The destination texel channel type is always GLchan.
 *
 * A hardware driver may use this as a helper routine to unpack and
 * apply pixel transfer ops into a temporary image buffer.  Then,
 * convert the temporary image into the special hardware format.
 *
 * Input:
 *   dimensions - 1, 2, or 3
 *   texFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA,
 *               GL_RGB or GL_RGBA
 *   texAddr - destination image address
 *   srcWidth, srcHeight, srcDepth - size (in pixels) of src and dest images
 *   dstXoffset, dstYoffset, dstZoffset - position to store the image within
 *      the destination 3D texture
 *   dstRowStride, dstImageStride - dest image strides in GLchan's
 *   srcFormat - source image format (GL_ALPHA, GL_RED, GL_RGB, etc)
 *   srcType - GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_FLOAT, etc
 *   srcPacking - describes packing of incoming image.
 */
void
_mesa_transfer_teximage(GLcontext *ctx, GLuint dimensions,
                        GLenum texFormat, GLchan *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 texComponents;

   ASSERT(ctx);
   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);

   texComponents = components_in_intformat(texFormat);

   /* try common 2D texture cases first */
   if (!ctx->_ImageTransferState && dimensions == 2 && srcType == CHAN_TYPE) {

      if (srcFormat == texFormat) {
         /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA,
          * GL_LUMINANCE_ALPHA, etc. texture formats.  Use memcpy().
          */
         const GLchan *src = (const GLchan *) _mesa_image_address(
                                   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 * sizeof(GLchan);
         GLchan *dst = texAddr + dstYoffset * dstRowStride
                      + dstXoffset * texComponents;
         if (srcRowStride == widthInBytes && dstRowStride == widthInBytes) {
            MEMCPY(dst, src, srcHeight * widthInBytes);
         }
         else {
            GLint i;
            for (i = 0; i < srcHeight; i++) {
               MEMCPY(dst, src, widthInBytes);
               src += srcRowStride;
               dst += dstRowStride;
            }
         }
         return;  /* all done */
      }
      else if (srcFormat == GL_RGBA && texFormat == GL_RGB) {
         /* commonly used by Quake */
         const GLchan *src = (const GLchan *) _mesa_image_address(
                                   srcPacking, srcAddr, srcWidth, srcHeight,
                                   srcFormat, srcType, 0, 0, 0);
         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
                                               srcWidth, srcFormat, srcType);
         GLchan *dst = texAddr + dstYoffset * dstRowStride
                      + dstXoffset * texComponents;
         GLint i, j;
         for (i = 0; i < srcHeight; i++) {
            const GLchan *s = src;
            GLchan *d = dst;
            for (j = 0; j < srcWidth; j++) {
               *d++ = *s++;  /*red*/
               *d++ = *s++;  /*green*/
               *d++ = *s++;  /*blue*/
               s++;          /*alpha*/
            }
            src += srcRowStride;
            dst += dstRowStride;
         }
         return;  /* all done */
      }
   }

   /*
    * General case solutions
    */
   if (texFormat == GL_COLOR_INDEX) {
      /* color index texture */
      const GLenum texType = CHAN_TYPE;
      GLint img, row;
      GLchan *dest = texAddr + dstZoffset * dstImageStride
                    + dstYoffset * dstRowStride
                    + dstXoffset * texComponents;
      for (img = 0; img < srcDepth; img++) {
         GLchan *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);
            destRow += dstRowStride;
         }
         dest += dstImageStride;
      }
   }
   else if (texFormat == GL_DEPTH_COMPONENT) {
      /* Depth texture (shadow maps) */
      GLint img, row;
      GLfloat *dest = (GLfloat *) texAddr + dstZoffset * dstImageStride
                    + dstYoffset * dstRowStride
                    + dstXoffset * texComponents;
      for (img = 0; img < srcDepth; img++) {
         GLfloat *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_depth_span(ctx, srcWidth, destRow,
                                    srcType, src, srcPacking);
            destRow += dstRowStride;
         }
         dest += dstImageStride;
      }
   }
   else {
      /* regular, color texture */
      if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) ||
          (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(srcWidth * srcHeight * 4 * sizeof(GLfloat));
         if (!tmpImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
            return;
         }
         convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
         if (!convImage) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
            FREE(tmpImage);
            return;
         }

         for (img = 0; img < srcDepth; img++) {
            const GLfloat *srcf;
            GLfloat *dstf = tmpImage;
            GLchan *dest;

            /* unpack and do transfer ops up to convolution */
            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 */
            if (dimensions == 1) {
               ASSERT(ctx->Pixel.Convolution1DEnabled);
               _mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage);
            }
            else {
               if (ctx->Pixel.Convolution2DEnabled) {
                  _mesa_convolve_2d_image(ctx, &convWidth, &convHeight,
                                          tmpImage, convImage);
               }
               else {
                  ASSERT(ctx->Pixel.Separable2DEnabled);
                  _mesa_convolve_sep_image(ctx, &convWidth, &convHeight,
                                           tmpImage, convImage);
               }
            }

            /* packing and transfer ops after convolution */
            srcf = convImage;
            dest = texAddr + (dstZoffset + img) * dstImageStride
                 + dstYoffset * dstRowStride;
            for (row = 0; row < convHeight; row++) {
               _mesa_pack_float_rgba_span(ctx, convWidth,
                                          (const GLfloat (*)[4]) srcf,
                                          texFormat, CHAN_TYPE,
                                          dest, &_mesa_native_packing,
                                          ctx->_ImageTransferState
                                          & IMAGE_POST_CONVOLUTION_BITS);
               srcf += convWidth * 4;
               dest += dstRowStride;
            }
         }

         FREE(convImage);
         FREE(tmpImage);
      }
      else {
         /*
          * no convolution
          */
         GLint img, row;
         GLchan *dest = texAddr + dstZoffset * dstImageStride
                       + dstYoffset * dstRowStride
                       + dstXoffset * texComponents;
         for (img = 0; img < srcDepth; img++) {
            GLchan *destRow = dest;
            for (row = 0; row < srcHeight; row++) {
               const GLvoid *srcRow = _mesa_image_address(srcPacking,
                                              srcAddr, srcWidth, srcHeight,
                                              srcFormat, srcType, img, row, 0);
               _mesa_unpack_chan_color_span(ctx, srcWidth, texFormat, destRow,
                                       srcFormat, srcType, srcRow, srcPacking,
                                       ctx->_ImageTransferState);
               destRow += dstRowStride;
            }
            dest += dstImageStride;
         }
      }
   }
}



/*
 * This is the software fallback for Driver.TexImage1D().
 * The texture image type will be GLchan.
 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
 *
 */
void
_mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
                       GLint internalFormat,
                       GLint width, GLint border,
                       GLenum format, GLenum type, const GLvoid *pixels,
                       const struct gl_pixelstore_attrib *packing,
                       struct gl_texture_object *texObj,
                       struct gl_texture_image *texImage)
{
   const GLint components = components_in_intformat(internalFormat);
   GLint compSize;
   GLint postConvWidth = width;

   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
   }

   /* setup the teximage struct's fields */
   texImage->Format = (GLenum) _mesa_base_tex_format(ctx, internalFormat);
   if (format == GL_DEPTH_COMPONENT) {
      texImage->Type = GL_FLOAT; /* XXX or GL_UNSIGNED_INT? */
      compSize = sizeof(GLfloat);
   }
   else {
      texImage->Type = CHAN_TYPE; /* usually GL_UNSIGNED_BYTE */
      compSize = sizeof(CHAN_TYPE);
   }
   texImage->FetchTexel = fetch_1d_texel;
   set_teximage_component_sizes(texImage);

   /* allocate memory */
   texImage->Data = (GLchan *) MALLOC(postConvWidth * components * compSize);
   if (!texImage->Data)
      return;      /* out of memory */

   /* unpack image, apply transfer ops and store in texImage->Data */
   _mesa_transfer_teximage(ctx, 1, texImage->Format, (GLchan *) texImage->Data,
                           width, 1, 1, 0, 0, 0,
                           0, /* dstRowStride */
                           0, /* dstImageStride */
                           format, type, pixels, packing);
}


/*
 * This is the software fallback for Driver.TexImage2D().
 * The texture image type will be GLchan.
 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
 *
 */
void
_mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
                       GLint internalFormat,
                       GLint width, GLint height, GLint border,
                       GLenum format, GLenum type, const void *pixels,
                       const struct gl_pixelstore_attrib *packing,
                       struct gl_texture_object *texObj,
                       struct gl_texture_image *texImage)
{
   const GLint components = components_in_intformat(internalFormat);
   GLint compSize;
   GLint postConvWidth = width, postConvHeight = height;

   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
                                         &postConvHeight);
   }

   /* setup the teximage struct's fields */
   texImage->Format = (GLenum) _mesa_base_tex_format(ctx, internalFormat);
   if (format == GL_DEPTH_COMPONENT) {
      texImage->Type = GL_FLOAT; /* XXX or GL_UNSIGNED_INT? */
      compSize = sizeof(GLfloat);
   }
   else {
      texImage->Type = CHAN_TYPE; /* usually GL_UNSIGNED_BYTE */
      compSize = sizeof(CHAN_TYPE);
   }
   texImage->FetchTexel = fetch_2d_texel;
   set_teximage_component_sizes(texImage);

   /* allocate memory */
   texImage->Data = (GLchan *) MALLOC(postConvWidth * postConvHeight
                                      * components * compSize);
   if (!texImage->Data)
      return;      /* out of memory */

   /* unpack image, apply transfer ops and store in texImage->Data */
   _mesa_transfer_teximage(ctx, 2, texImage->Format, (GLchan *) texImage->Data,
                           width, height, 1, 0, 0, 0,
                           texImage->Width * components * sizeof(GLchan),
                           0, /* dstImageStride */
                           format, type, pixels, packing);
}



/*
 * This is the software fallback for Driver.TexImage3D().
 * The texture image type will be GLchan.
 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
 *
 */
void
_mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
                       GLint internalFormat,
                       GLint width, GLint height, GLint depth, GLint border,
                       GLenum format, GLenum type, const void *pixels,
                       const struct gl_pixelstore_attrib *packing,
                       struct gl_texture_object *texObj,
                       struct gl_texture_image *texImage)
{
   const GLint components = components_in_intformat(internalFormat);
   GLint compSize;

   /* setup the teximage struct's fields */
   texImage->Format = (GLenum) _mesa_base_tex_format(ctx, internalFormat);
   if (format == GL_DEPTH_COMPONENT) {
      texImage->Type = GL_FLOAT; /* XXX or GL_UNSIGNED_INT? */
      compSize = sizeof(GLfloat);
   }
   else {
      texImage->Type = CHAN_TYPE; /* usually GL_UNSIGNED_BYTE */
      compSize = sizeof(CHAN_TYPE);
   }
   texImage->FetchTexel = fetch_3d_texel;
   set_teximage_component_sizes(texImage);

   /* allocate memory */
   texImage->Data = (GLchan *) MALLOC(width * height * depth
                                      * components * compSize);
   if (!texImage->Data)
      return;      /* out of memory */

   /* unpack image, apply transfer ops and store in texImage->Data */
   _mesa_transfer_teximage(ctx, 3, texImage->Format, (GLchan *) texImage->Data,
                           width, height, depth, 0, 0, 0,
                           texImage->Width * components * sizeof(GLchan),
                           texImage->Width * texImage->Height * components
                           * sizeof(GLchan),
                           format, type, pixels, packing);
}




/*
 * This is the software fallback for Driver.TexSubImage1D().
 */
void
_mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
                          GLint xoffset, GLint width,
                          GLenum format, GLenum type, const void *pixels,
                          const struct gl_pixelstore_attrib *packing,
                          struct gl_texture_object *texObj,
                          struct gl_texture_image *texImage)
{
   _mesa_transfer_teximage(ctx, 1, texImage->Format, (GLchan *) texImage->Data,
                           width, 1, 1, /* src size */
                           xoffset, 0, 0, /* dest offsets */
                           0, /* dstRowStride */
                           0, /* dstImageStride */
                           format, type, pixels, packing);
}


/*
 * This is the software fallback for Driver.TexSubImage2D().
 */
void
_mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
                          GLint xoffset, GLint yoffset,
                          GLint width, GLint height,
                          GLenum format, GLenum type, const void *pixels,
                          const struct gl_pixelstore_attrib *packing,
                          struct gl_texture_object *texObj,
                          struct gl_texture_image *texImage)
{
   const GLint components = components_in_intformat(texImage->IntFormat);
   const GLint compSize = _mesa_sizeof_type(texImage->Type);
   _mesa_transfer_teximage(ctx, 2, texImage->Format, (GLchan *) texImage->Data,
                           width, height, 1, /* src size */
                           xoffset, yoffset, 0, /* dest offsets */
                           texImage->Width * components * compSize,
                           0, /* dstImageStride */
                           format, type, pixels, packing);
}


/*
 * This is the software fallback for Driver.TexSubImage3D().
 */
void
_mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
                          GLint xoffset, GLint yoffset, GLint zoffset,
                          GLint width, GLint height, GLint depth,
                          GLenum format, GLenum type, const void *pixels,
                          const struct gl_pixelstore_attrib *packing,
                          struct gl_texture_object *texObj,
                          struct gl_texture_image *texImage)
{
   const GLint components = components_in_intformat(texImage->IntFormat);
   const GLint compSize = _mesa_sizeof_type(texImage->Type);
   _mesa_transfer_teximage(ctx, 3, texImage->Format, (GLchan *) texImage->Data,
                           width, height, depth, /* src size */
                           xoffset, yoffset, xoffset, /* dest offsets */
                           texImage->Width * components * compSize,
                           texImage->Width * texImage->Height * components
                           * compSize,
                           format, type, pixels, packing);
}




/*
 * 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.
 */
static GLchan *
read_color_image( GLcontext *ctx, GLint x, GLint y,
                  GLsizei width, GLsizei height )
{
   GLint stride, i;
   GLchan *image, *dst;

   image = (GLchan *) MALLOC(width * height * 4 * sizeof(GLchan));
   if (!image)
      return NULL;

   /* Select buffer to read from */
   (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
                                 ctx->Pixel.DriverReadBuffer );

   RENDER_START(ctx);

   dst = image;
   stride = width * 4;
   for (i = 0; i < height; i++) {
      _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, x, y + i,
                         (GLchan (*)[4]) dst );
      dst += stride;
   }

   RENDER_FINISH(ctx);

   /* Read from draw buffer (the default) */
   (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
                                 ctx->Color.DriverDrawBuffer );

   return image;
}


/*
 * As above, but read data from depth buffer.
 */
static GLfloat *
read_depth_image( GLcontext *ctx, GLint x, GLint y,
                  GLsizei width, GLsizei height )
{
   GLint i;
   GLfloat *image, *dst;

   image = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
   if (!image)
      return NULL;

   RENDER_START(ctx);

   dst = image;
   for (i = 0; i < height; i++) {
      _mesa_read_depth_span_float(ctx, width, x, y + i, dst);
      dst += width;
   }

   RENDER_FINISH(ctx);

   return image;
}



static GLboolean
is_depth_format(GLenum format)
{
   switch (format) {
      case GL_DEPTH_COMPONENT:
      case GL_DEPTH_COMPONENT16_SGIX:
      case GL_DEPTH_COMPONENT24_SGIX:
      case GL_DEPTH_COMPONENT32_SGIX:
         return GL_TRUE;
      default:
         return GL_FALSE;
   }
}


/*
 * Fallback for Driver.CopyTexImage1D().
 */
void
_mesa_copy_teximage1d( GLcontext *ctx, GLenum target, GLint level,
                       GLenum internalFormat,
                       GLint x, GLint y, GLsizei width, GLint border )
{
   struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;

   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   texObj = _mesa_select_tex_object(ctx, texUnit, target);
   ASSERT(texObj);
   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
   ASSERT(texImage);

   ASSERT(ctx->Driver.TexImage1D);

   if (is_depth_format(internalFormat)) {
      /* read depth image from framebuffer */
      GLfloat *image = read_depth_image(ctx, x, y, 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_DEPTH_COMPONENT, GL_FLOAT, image,
                                &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
   else {
      /* read RGBA image from framebuffer */
      GLchan *image = read_color_image(ctx, x, y, 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,
                                &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
}


/*
 * Fallback for Driver.CopyTexImage2D().
 */
void
_mesa_copy_teximage2d( GLcontext *ctx, GLenum target, GLint level,
                       GLenum internalFormat,
                       GLint x, GLint y, GLsizei width, GLsizei height,
                       GLint border )
{
   struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;

   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   texObj = _mesa_select_tex_object(ctx, texUnit, target);
   ASSERT(texObj);
   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
   ASSERT(texImage);

   ASSERT(ctx->Driver.TexImage2D);

   if (is_depth_format(internalFormat)) {
      /* read depth image from framebuffer */
      GLfloat *image = read_depth_image(ctx, x, y, 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_DEPTH_COMPONENT, GL_FLOAT, image,
                                &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
   else {
      /* read RGBA image from framebuffer */
      GLchan *image = read_color_image(ctx, x, y, 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,
                                &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
}


/*
 * Fallback for Driver.CopyTexSubImage1D().
 */
void
_mesa_copy_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
                         GLint xoffset, GLint x, GLint y, GLsizei width)
{
   struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;

   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   texObj = _mesa_select_tex_object(ctx, texUnit, target);
   ASSERT(texObj);
   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
   ASSERT(texImage);

   ASSERT(ctx->Driver.TexImage1D);

   if (is_depth_format(texImage->IntFormat)) {
      /* read depth image from framebuffer */
      GLfloat *image = read_depth_image(ctx, x, y, width, 1);
      if (!image) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage1D");
         return;
      }

      /* call glTexImage1D to redefine the texture */
      (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
                                   GL_DEPTH_COMPONENT, GL_FLOAT, image,
                                   &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
   else {
      GLchan *image = read_color_image(ctx, x, y, 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,
                                   &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
}


/*
 * Fallback for Driver.CopyTexSubImage2D().
 */
void
_mesa_copy_texsubimage2d( GLcontext *ctx,
                          GLenum target, GLint level,
                          GLint xoffset, GLint yoffset,
                          GLint x, GLint y, GLsizei width, GLsizei height )
{
   struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;

   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   texObj = _mesa_select_tex_object(ctx, texUnit, target);
   ASSERT(texObj);
   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
   ASSERT(texImage);

   ASSERT(ctx->Driver.TexImage2D);

   if (is_depth_format(texImage->IntFormat)) {
      /* read depth image from framebuffer */
      GLfloat *image = read_depth_image(ctx, x, y, width, height);
      if (!image) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D");
         return;
      }

      /* call glTexImage1D to redefine the texture */
      (*ctx->Driver.TexSubImage2D)(ctx, target, level,
                                   xoffset, yoffset, width, height,
                                   GL_DEPTH_COMPONENT, GL_FLOAT, image,
                                   &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
   else {
      /* read RGBA image from framebuffer */
      GLchan *image = read_color_image(ctx, x, y, width, height);
      if (!image) {
         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage2D" );
         return;
      }

      /* now call glTexSubImage2D to do the real work */
      (*ctx->Driver.TexSubImage2D)(ctx, target, level,
                                   xoffset, yoffset, width, height,
                                   GL_RGBA, CHAN_TYPE, image,
                                   &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
}


/*
 * Fallback for Driver.CopyTexSubImage3D().
 */
void
_mesa_copy_texsubimage3d( GLcontext *ctx,
                          GLenum target, GLint level,
                          GLint xoffset, GLint yoffset, GLint zoffset,
                          GLint x, GLint y, GLsizei width, GLsizei height )
{
   struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;

   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   texObj = _mesa_select_tex_object(ctx, texUnit, target);
   ASSERT(texObj);
   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
   ASSERT(texImage);

   ASSERT(ctx->Driver.TexImage3D);

   if (is_depth_format(texImage->IntFormat)) {
      /* read depth image from framebuffer */
      GLfloat *image = read_depth_image(ctx, x, y, width, height);
      if (!image) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D");
         return;
      }

      /* call glTexImage1D to redefine the texture */
      (*ctx->Driver.TexSubImage3D)(ctx, target, level,
                                   xoffset, yoffset, zoffset, width, height, 1,
                                   GL_DEPTH_COMPONENT, GL_FLOAT, image,
                                   &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
   else {
      /* read RGBA image from framebuffer */
      GLchan *image = read_color_image(ctx, x, y, width, height);
      if (!image) {
         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage3D" );
         return;
      }

      /* 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,
                                   &_mesa_native_packing, texObj, texImage);
      FREE(image);
   }
}



/*
 * Fallback for Driver.CompressedTexImage1D()
 */
void
_mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level,
                                  GLint internalFormat,
                                  GLint width, GLint border,
                                  GLsizei imageSize, const GLvoid *data,
                                  struct gl_texture_object *texObj,
                                  struct gl_texture_image *texImage)
{
   /* Nothing here.
    * The device driver has to do it all.
    */
}



/*
 * Fallback for Driver.CompressedTexImage2D()
 */
void
_mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level,
                                  GLint internalFormat,
                                  GLint width, GLint height, GLint border,
                                  GLsizei imageSize, const GLvoid *data,
                                  struct gl_texture_object *texObj,
                                  struct gl_texture_image *texImage)
{
   /* Nothing here.
    * The device driver has to do it all.
    */
}



/*
 * Fallback for Driver.CompressedTexImage3D()
 */
void
_mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
                                  GLint internalFormat,
                                  GLint width, GLint height, GLint depth,
                                  GLint border,
                                  GLsizei imageSize, const GLvoid *data,
                                  struct gl_texture_object *texObj,
                                  struct gl_texture_image *texImage)
{
   /* Nothing here.
    * The device driver has to do it all.
    */
}






/*
 * This is the fallback for Driver.TestProxyTexImage().
 */
GLboolean
_mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
                          GLint internalFormat, GLenum format, GLenum type,
                          GLint width, GLint height, GLint depth, GLint border)
{
   struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   GLint compSize;

   (void) format;
   (void) type;

   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   texObj = _mesa_select_tex_object(ctx, texUnit, target);
   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);

   /* We always pass.
    * The core Mesa code will have already tested the image size, etc.
    * Drivers may have more stringent texture limits to enforce and will
    * have to override this function.
    */
   /* setup the teximage struct's fields */
   texImage->Format = (GLenum) _mesa_base_tex_format(ctx, internalFormat);
   if (format == GL_DEPTH_COMPONENT) {
      texImage->Type = GL_FLOAT; /* XXX or GL_UNSIGNED_INT? */
      compSize = sizeof(GLfloat);
   }
   else {
      texImage->Type = CHAN_TYPE; /* usually GL_UNSIGNED_BYTE */
      compSize = sizeof(CHAN_TYPE);
   }
   set_teximage_component_sizes(texImage);

   return GL_TRUE;
}