texstore.c revision defb035b6cf03c555318d9dd48864242ed036f39
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.1
4 *
5 * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/*
26 * Authors:
27 *   Brian Paul
28 */
29
30/*
31 * The GL texture image functions in teximage.c basically just do
32 * error checking and data structure allocation.  They in turn call
33 * device driver functions which actually copy/convert/store the user's
34 * texture image data.
35 *
36 * However, most device drivers will be able to use the fallback functions
37 * in this file.  That is, most drivers will have the following bit of
38 * code:
39 *   ctx->Driver.TexImage1D = _mesa_store_teximage1d;
40 *   ctx->Driver.TexImage2D = _mesa_store_teximage2d;
41 *   ctx->Driver.TexImage3D = _mesa_store_teximage3d;
42 *   etc...
43 *
44 * Texture image processing is actually kind of complicated.  We have to do:
45 *    Format/type conversions
46 *    pixel unpacking
47 *    pixel transfer (scale, bais, lookup, convolution!, etc)
48 *
49 * These functions can handle most everything, including processing full
50 * images and sub-images.
51 */
52
53
54#include "glheader.h"
55#include "bufferobj.h"
56#include "colormac.h"
57#include "context.h"
58#include "convolve.h"
59#include "image.h"
60#include "macros.h"
61#include "imports.h"
62#include "texcompress.h"
63#include "texformat.h"
64#include "teximage.h"
65#include "texstore.h"
66
67
68static const GLint ZERO = 1000, ONE = 1001;
69
70/**
71 * When promoting texture formats (see below) we need to compute the
72 * mapping of dest components back to source components.
73 * This function does that.
74 * \param logicalBaseFormat  the logical format of the texture
75 * \param textureBaseFormat  the final texture format
76 * \return map[4]  the four mapping values
77 */
78static void
79compute_component_mapping(GLenum logicalBaseFormat, GLenum textureBaseFormat,
80                          GLint map[4])
81{
82   /* compute mapping from dest components back to src components */
83   switch (logicalBaseFormat) {
84   case GL_LUMINANCE:
85      map[0] = map[1] = map[2] = 0;
86      if (textureBaseFormat == GL_RGBA)
87         map[3] = ONE;
88      break;
89   case GL_ALPHA:
90      ASSERT(textureBaseFormat == GL_RGBA);
91      map[0] = map[1] = map[2] = ZERO;
92      map[3] = 0;
93      break;
94   case GL_INTENSITY:
95      map[0] = map[1] = map[2] = 0;
96      if (textureBaseFormat == GL_RGBA)
97         map[3] = 0;
98      break;
99   case GL_LUMINANCE_ALPHA:
100      ASSERT(textureBaseFormat == GL_RGBA);
101      map[0] = map[1] = map[2] = 0;
102      map[3] = 1;
103      break;
104   case GL_RGB:
105      ASSERT(textureBaseFormat == GL_RGBA);
106      map[0] = 0;
107      map[1] = 1;
108      map[2] = 2;
109      map[3] = ONE;
110      break;
111   default:
112      _mesa_problem(NULL, "Unexpected logicalBaseFormat");
113      map[0] = map[1] = map[2] = map[3] = 0;
114   }
115}
116
117
118/**
119 * Make a temporary (color) texture image with GLfloat components.
120 * Apply all needed pixel unpacking and pixel transfer operations.
121 * Note that there are both logicalBaseFormat and textureBaseFormat parameters.
122 * Suppose the user specifies GL_LUMINANCE as the internal texture format
123 * but the graphics hardware doesn't support luminance textures.  So, might
124 * use an RGB hardware format instead.
125 * If logicalBaseFormat != textureBaseFormat we have some extra work to do.
126 *
127 * \param ctx  the rendering context
128 * \param dims  image dimensions: 1, 2 or 3
129 * \param logicalBaseFormat  basic texture derived from the user's
130 *    internal texture format value
131 * \param textureBaseFormat  the actual basic format of the texture
132 * \param srcWidth  source image width
133 * \param srcHeight  source image height
134 * \param srcDepth  source image depth
135 * \param srcFormat  source image format
136 * \param srcType  source image type
137 * \param srcAddr  source image address
138 * \param srcPacking  source image pixel packing
139 * \return resulting image with format = textureBaseFormat and type = GLfloat.
140 */
141static GLfloat *
142make_temp_float_image(GLcontext *ctx, GLuint dims,
143                      GLenum logicalBaseFormat,
144                      GLenum textureBaseFormat,
145                      GLint srcWidth, GLint srcHeight, GLint srcDepth,
146                      GLenum srcFormat, GLenum srcType,
147                      const GLvoid *srcAddr,
148                      const struct gl_pixelstore_attrib *srcPacking)
149{
150   GLuint transferOps = ctx->_ImageTransferState;
151   GLfloat *tempImage;
152
153   ASSERT(dims >= 1 && dims <= 3);
154
155   ASSERT(logicalBaseFormat == GL_RGBA ||
156          logicalBaseFormat == GL_RGB ||
157          logicalBaseFormat == GL_LUMINANCE_ALPHA ||
158          logicalBaseFormat == GL_LUMINANCE ||
159          logicalBaseFormat == GL_ALPHA ||
160          logicalBaseFormat == GL_INTENSITY ||
161          logicalBaseFormat == GL_COLOR_INDEX ||
162          logicalBaseFormat == GL_DEPTH_COMPONENT);
163
164   ASSERT(textureBaseFormat == GL_RGBA ||
165          textureBaseFormat == GL_RGB ||
166          textureBaseFormat == GL_LUMINANCE_ALPHA ||
167          textureBaseFormat == GL_LUMINANCE ||
168          textureBaseFormat == GL_ALPHA ||
169          textureBaseFormat == GL_INTENSITY ||
170          textureBaseFormat == GL_COLOR_INDEX ||
171          textureBaseFormat == GL_DEPTH_COMPONENT);
172
173   /* conventional color image */
174
175   if ((dims == 1 && ctx->Pixel.Convolution1DEnabled) ||
176       (dims >= 2 && ctx->Pixel.Convolution2DEnabled) ||
177       (dims >= 2 && ctx->Pixel.Separable2DEnabled)) {
178      /* need image convolution */
179      const GLuint preConvTransferOps
180         = (transferOps & IMAGE_PRE_CONVOLUTION_BITS) | IMAGE_CLAMP_BIT;
181      const GLuint postConvTransferOps
182         = (transferOps & IMAGE_POST_CONVOLUTION_BITS) | IMAGE_CLAMP_BIT;
183      GLint img, row;
184      GLint convWidth, convHeight;
185      GLfloat *convImage;
186
187      /* pre-convolution image buffer (3D) */
188      tempImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth
189                                           * 4 * sizeof(GLfloat));
190      if (!tempImage)
191         return NULL;
192
193      /* post-convolution image buffer (2D) */
194      convImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight
195                                           * 4 * sizeof(GLfloat));
196      if (!convImage) {
197         _mesa_free(tempImage);
198         return NULL;
199      }
200
201      /* loop over 3D image slices */
202      for (img = 0; img < srcDepth; img++) {
203         GLfloat *dst = tempImage + img * (srcWidth * srcHeight * 4);
204
205         /* unpack and do transfer ops up to convolution */
206         for (row = 0; row < srcHeight; row++) {
207            const GLvoid *src = _mesa_image_address(srcPacking,
208                                              srcAddr, srcWidth, srcHeight,
209                                              srcFormat, srcType, img, row, 0);
210            _mesa_unpack_color_span_float(ctx, srcWidth, GL_RGBA, dst,
211                                          srcFormat, srcType, src,
212                                          srcPacking,
213                                          preConvTransferOps);
214            dst += srcWidth * 4;
215         }
216
217         /* do convolution */
218         {
219            GLfloat *src = tempImage + img * (srcWidth * srcHeight * 4);
220            convWidth = srcWidth;
221            convHeight = srcHeight;
222            if (dims == 1) {
223               ASSERT(ctx->Pixel.Convolution1DEnabled);
224               _mesa_convolve_1d_image(ctx, &convWidth, src, convImage);
225            }
226            else {
227               if (ctx->Pixel.Convolution2DEnabled) {
228                  _mesa_convolve_2d_image(ctx, &convWidth, &convHeight,
229                                          src, convImage);
230               }
231               else {
232                  ASSERT(ctx->Pixel.Separable2DEnabled);
233                  _mesa_convolve_sep_image(ctx, &convWidth, &convHeight,
234                                           src, convImage);
235               }
236            }
237         }
238
239         /* do post-convolution transfer and pack into tempImage */
240         {
241            const GLint logComponents
242               = _mesa_components_in_format(logicalBaseFormat);
243            const GLfloat *src = convImage;
244            GLfloat *dst = tempImage + img * (convWidth * convHeight * 4);
245            for (row = 0; row < convHeight; row++) {
246               _mesa_pack_rgba_span_float(ctx, convWidth,
247                                          (const GLfloat (*)[4]) src,
248                                          logicalBaseFormat, GL_FLOAT,
249                                          dst, &ctx->DefaultPacking,
250                                          postConvTransferOps);
251               src += convWidth * 4;
252               dst += convWidth * logComponents;
253            }
254         }
255      } /* loop over 3D image slices */
256
257      _mesa_free(convImage);
258
259      /* might need these below */
260      srcWidth = convWidth;
261      srcHeight = convHeight;
262   }
263   else {
264      /* no convolution */
265      const GLint components = _mesa_components_in_format(logicalBaseFormat);
266      const GLint srcStride = _mesa_image_row_stride(srcPacking,
267                                                 srcWidth, srcFormat, srcType);
268      GLfloat *dst;
269      GLint img, row;
270
271      tempImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth
272                                           * components * sizeof(GLfloat));
273      if (!tempImage)
274         return NULL;
275
276      dst = tempImage;
277      for (img = 0; img < srcDepth; img++) {
278         const GLubyte *src
279            = (const GLubyte *) _mesa_image_address(srcPacking, srcAddr,
280                                                    srcWidth, srcHeight,
281                                                    srcFormat, srcType,
282                                                    img, 0, 0);
283         for (row = 0; row < srcHeight; row++) {
284            _mesa_unpack_color_span_float(ctx, srcWidth, logicalBaseFormat,
285                                          dst, srcFormat, srcType, src,
286                                          srcPacking, transferOps);
287            dst += srcWidth * components;
288            src += srcStride;
289         }
290      }
291   }
292
293   if (logicalBaseFormat != textureBaseFormat) {
294      /* more work */
295      GLint texComponents = _mesa_components_in_format(textureBaseFormat);
296      GLint logComponents = _mesa_components_in_format(logicalBaseFormat);
297      GLfloat *newImage;
298      GLint i, n;
299      GLint map[4];
300
301      /* we only promote up to RGB and RGBA formats for now */
302      ASSERT(textureBaseFormat == GL_RGB || textureBaseFormat == GL_RGBA);
303
304      /* The actual texture format should have at least as many components
305       * as the logical texture format.
306       */
307      ASSERT(texComponents >= logComponents);
308
309      newImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth
310                                          * texComponents * sizeof(GLfloat));
311      if (!newImage) {
312         _mesa_free(tempImage);
313         return NULL;
314      }
315
316      compute_component_mapping(logicalBaseFormat, textureBaseFormat, map);
317
318      n = srcWidth * srcHeight * srcDepth;
319      for (i = 0; i < n; i++) {
320         GLint k;
321         for (k = 0; k < texComponents; k++) {
322            GLint j = map[k];
323            if (j == ZERO)
324               newImage[i * texComponents + k] = 0.0F;
325            else if (j == ONE)
326               newImage[i * texComponents + k] = 1.0F;
327            else
328               newImage[i * texComponents + k] = tempImage[i * logComponents + j];
329         }
330      }
331
332      _mesa_free(tempImage);
333      tempImage = newImage;
334   }
335
336   return tempImage;
337}
338
339
340/**
341 * Make a temporary (color) texture image with GLchan components.
342 * Apply all needed pixel unpacking and pixel transfer operations.
343 * Note that there are both logicalBaseFormat and textureBaseFormat parameters.
344 * Suppose the user specifies GL_LUMINANCE as the internal texture format
345 * but the graphics hardware doesn't support luminance textures.  So, might
346 * use an RGB hardware format instead.
347 * If logicalBaseFormat != textureBaseFormat we have some extra work to do.
348 *
349 * \param ctx  the rendering context
350 * \param dims  image dimensions: 1, 2 or 3
351 * \param logicalBaseFormat  basic texture derived from the user's
352 *    internal texture format value
353 * \param textureBaseFormat  the actual basic format of the texture
354 * \param srcWidth  source image width
355 * \param srcHeight  source image height
356 * \param srcDepth  source image depth
357 * \param srcFormat  source image format
358 * \param srcType  source image type
359 * \param srcAddr  source image address
360 * \param srcPacking  source image pixel packing
361 * \return resulting image with format = textureBaseFormat and type = GLchan.
362 */
363GLchan *
364_mesa_make_temp_chan_image(GLcontext *ctx, GLuint dims,
365                           GLenum logicalBaseFormat,
366                           GLenum textureBaseFormat,
367                           GLint srcWidth, GLint srcHeight, GLint srcDepth,
368                           GLenum srcFormat, GLenum srcType,
369                           const GLvoid *srcAddr,
370                           const struct gl_pixelstore_attrib *srcPacking)
371{
372   GLuint transferOps = ctx->_ImageTransferState;
373   const GLint components = _mesa_components_in_format(logicalBaseFormat);
374   GLboolean freeSrcImage = GL_FALSE;
375   GLint img, row;
376   GLchan *tempImage, *dst;
377
378   ASSERT(dims >= 1 && dims <= 3);
379
380   ASSERT(logicalBaseFormat == GL_RGBA ||
381          logicalBaseFormat == GL_RGB ||
382          logicalBaseFormat == GL_LUMINANCE_ALPHA ||
383          logicalBaseFormat == GL_LUMINANCE ||
384          logicalBaseFormat == GL_ALPHA ||
385          logicalBaseFormat == GL_INTENSITY);
386
387   ASSERT(textureBaseFormat == GL_RGBA ||
388          textureBaseFormat == GL_RGB ||
389          textureBaseFormat == GL_LUMINANCE_ALPHA ||
390          textureBaseFormat == GL_LUMINANCE ||
391          textureBaseFormat == GL_ALPHA ||
392          textureBaseFormat == GL_INTENSITY);
393
394   if ((dims == 1 && ctx->Pixel.Convolution1DEnabled) ||
395       (dims >= 2 && ctx->Pixel.Convolution2DEnabled) ||
396       (dims >= 2 && ctx->Pixel.Separable2DEnabled)) {
397      /* get convolved image */
398      GLfloat *convImage = make_temp_float_image(ctx, dims,
399                                                 logicalBaseFormat,
400                                                 logicalBaseFormat,
401                                                 srcWidth, srcHeight, srcDepth,
402                                                 srcFormat, srcType,
403                                                 srcAddr, srcPacking);
404      if (!convImage)
405         return NULL;
406      /* the convolved image is our new source image */
407      srcAddr = convImage;
408      srcFormat = logicalBaseFormat;
409      srcType = GL_FLOAT;
410      srcPacking = &ctx->DefaultPacking;
411      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
412      transferOps = 0;
413      freeSrcImage = GL_TRUE;
414   }
415
416   /* unpack and transfer the source image */
417   tempImage = (GLchan *) _mesa_malloc(srcWidth * srcHeight * srcDepth
418                                       * components * sizeof(GLchan));
419   if (!tempImage)
420      return NULL;
421
422   dst = tempImage;
423   for (img = 0; img < srcDepth; img++) {
424      const GLint srcStride = _mesa_image_row_stride(srcPacking,
425                                                     srcWidth, srcFormat,
426                                                     srcType);
427      const GLubyte *src
428         = (const GLubyte *) _mesa_image_address(srcPacking, srcAddr,
429                                                 srcWidth, srcHeight,
430                                                 srcFormat, srcType,
431                                                 img, 0, 0);
432      for (row = 0; row < srcHeight; row++) {
433         _mesa_unpack_color_span_chan(ctx, srcWidth, logicalBaseFormat, dst,
434                                      srcFormat, srcType, src, srcPacking,
435                                      transferOps);
436         dst += srcWidth * components;
437         src += srcStride;
438      }
439   }
440
441   /* If we made a temporary image for convolution, free it here */
442   if (freeSrcImage) {
443      _mesa_free((void *) srcAddr);
444   }
445
446   if (logicalBaseFormat != textureBaseFormat) {
447      /* one more conversion step */
448      GLint texComponents = _mesa_components_in_format(textureBaseFormat);
449      GLint logComponents = _mesa_components_in_format(logicalBaseFormat);
450      GLchan *newImage;
451      GLint i, n;
452      GLint map[4];
453
454      /* we only promote up to RGB and RGBA formats for now */
455      ASSERT(textureBaseFormat == GL_RGB || textureBaseFormat == GL_RGBA);
456
457      /* The actual texture format should have at least as many components
458       * as the logical texture format.
459       */
460      ASSERT(texComponents >= logComponents);
461
462      newImage = (GLchan *) _mesa_malloc(srcWidth * srcHeight * srcDepth
463                                          * texComponents * sizeof(GLchan));
464      if (!newImage) {
465         _mesa_free(tempImage);
466         return NULL;
467      }
468
469      compute_component_mapping(logicalBaseFormat, textureBaseFormat, map);
470
471      n = srcWidth * srcHeight * srcDepth;
472      for (i = 0; i < n; i++) {
473         GLint k;
474         for (k = 0; k < texComponents; k++) {
475            GLint j = map[k];
476            if (j == ZERO)
477               newImage[i * texComponents + k] = 0;
478            else if (j == ONE)
479               newImage[i * texComponents + k] = CHAN_MAX;
480            else
481               newImage[i * texComponents + k] = tempImage[i * logComponents + j];
482         }
483      }
484
485      _mesa_free(tempImage);
486      tempImage = newImage;
487   }
488
489   return tempImage;
490}
491
492
493
494/**
495 * Teximage storage routine for when a simple memcpy will do.
496 * No pixel transfer operations or special texel encodings allowed.
497 * 1D, 2D and 3D images supported.
498 */
499static void
500memcpy_texture(const struct gl_texture_format *dstFormat,
501               GLvoid *dstAddr,
502               GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
503               GLint dstRowStride, GLint dstImageStride,
504               GLint srcWidth, GLint srcHeight, GLint srcDepth,
505               GLenum srcFormat, GLenum srcType,
506               const GLvoid *srcAddr,
507               const struct gl_pixelstore_attrib *srcPacking)
508{
509   const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth,
510                                                     srcFormat, srcType);
511   const GLint srcImageStride = _mesa_image_image_stride(srcPacking,
512                                      srcWidth, srcHeight, srcFormat, srcType);
513   const GLubyte *srcImage = (const GLubyte *) _mesa_image_address(srcPacking,
514                    srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0);
515   const GLint bytesPerRow = srcWidth * dstFormat->TexelBytes;
516   const GLint bytesPerImage = srcHeight * bytesPerRow;
517   const GLint bytesPerTexture = srcDepth * bytesPerImage;
518   GLubyte *dstImage = (GLubyte *) dstAddr
519                     + dstZoffset * dstImageStride
520                     + dstYoffset * dstRowStride
521                     + dstXoffset * dstFormat->TexelBytes;
522
523   if (dstRowStride == srcRowStride &&
524       dstRowStride == bytesPerRow &&
525       ((dstImageStride == srcImageStride &&
526         dstImageStride == bytesPerImage) ||
527        (srcDepth == 1))) {
528      /* one big memcpy */
529      _mesa_memcpy(dstImage, srcImage, bytesPerTexture);
530   }
531   else {
532      GLint img, row;
533      for (img = 0; img < srcDepth; img++) {
534         const GLubyte *srcRow = srcImage;
535         GLubyte *dstRow = dstImage;
536         for (row = 0; row < srcHeight; row++) {
537            _mesa_memcpy(dstRow, srcRow, bytesPerRow);
538            dstRow += dstRowStride;
539            srcRow += srcRowStride;
540         }
541         srcImage += srcImageStride;
542         dstImage += dstImageStride;
543      }
544   }
545}
546
547
548
549/**
550 * Store an image in any of the formats:
551 *   _mesa_texformat_rgba
552 *   _mesa_texformat_rgb
553 *   _mesa_texformat_alpha
554 *   _mesa_texformat_luminance
555 *   _mesa_texformat_luminance_alpha
556 *   _mesa_texformat_intensity
557 *
558 * \param dims  either 1 or 2 or 3
559 * \param baseInternalFormat  user-specified base internal format
560 * \param dstFormat  destination Mesa texture format
561 * \param dstAddr  destination image address
562 * \param dstX/Y/Zoffset  destination x/y/z offset (ala TexSubImage), in texels
563 * \param dstRowStride  destination image row stride, in bytes
564 * \param dstImageStride  destination image layer stride, in bytes
565 * \param srcWidth/Height/Depth  source image size, in pixels
566 * \param srcFormat  incoming image format
567 * \param srcType  incoming image data type
568 * \param srcAddr  source image address
569 * \param srcPacking  source image packing parameters
570 */
571GLboolean
572_mesa_texstore_rgba(GLcontext *ctx, GLuint dims,
573                    GLenum baseInternalFormat,
574                    const struct gl_texture_format *dstFormat,
575                    GLvoid *dstAddr,
576                    GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
577                    GLint dstRowStride, GLint dstImageStride,
578                    GLint srcWidth, GLint srcHeight, GLint srcDepth,
579                    GLenum srcFormat, GLenum srcType,
580                    const GLvoid *srcAddr,
581                    const struct gl_pixelstore_attrib *srcPacking)
582{
583   const GLint components = _mesa_components_in_format(baseInternalFormat);
584
585   ASSERT(dstFormat == &_mesa_texformat_rgba ||
586          dstFormat == &_mesa_texformat_rgb ||
587          dstFormat == &_mesa_texformat_alpha ||
588          dstFormat == &_mesa_texformat_luminance ||
589          dstFormat == &_mesa_texformat_luminance_alpha ||
590          dstFormat == &_mesa_texformat_intensity);
591   ASSERT(baseInternalFormat == GL_RGBA ||
592          baseInternalFormat == GL_RGB ||
593          baseInternalFormat == GL_ALPHA ||
594          baseInternalFormat == GL_LUMINANCE ||
595          baseInternalFormat == GL_LUMINANCE_ALPHA ||
596          baseInternalFormat == GL_INTENSITY);
597   ASSERT(dstFormat->TexelBytes == components * sizeof(GLchan));
598
599   if (!ctx->_ImageTransferState &&
600       !srcPacking->SwapBytes &&
601       baseInternalFormat == srcFormat &&
602       srcType == CHAN_TYPE) {
603      /* simple memcpy path */
604      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
605                     dstRowStride, dstImageStride,
606                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
607                     srcAddr, srcPacking);
608   }
609   else if (!ctx->_ImageTransferState &&
610            !srcPacking->SwapBytes &&
611            dstFormat == &_mesa_texformat_rgb &&
612            srcFormat == GL_RGBA &&
613            srcType == CHAN_TYPE) {
614      /* extract RGB from RGBA */
615      int img, row, col;
616      GLchan *dstImage = (GLchan *) (GLubyte *) dstAddr
617                       + dstZoffset * dstImageStride
618                       + dstYoffset * dstRowStride
619                       + dstXoffset * dstFormat->TexelBytes;
620      for (img = 0; img < srcDepth; img++) {
621         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
622                                                 srcWidth, srcFormat, srcType);
623         GLchan *srcRow = (GLchan *) _mesa_image_address(srcPacking, srcAddr,
624                           srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
625         GLchan *dstRow = dstImage;
626         for (row = 0; row < srcHeight; row++) {
627            for (col = 0; col < srcWidth; col++) {
628               dstRow[col * 3 + RCOMP] = srcRow[col * 4 + RCOMP];
629               dstRow[col * 3 + GCOMP] = srcRow[col * 4 + GCOMP];
630               dstRow[col * 3 + BCOMP] = srcRow[col * 4 + BCOMP];
631            }
632            dstRow += dstRowStride;
633            srcRow = (GLchan *) ((GLubyte *) srcRow + srcRowStride);
634         }
635         dstImage += dstImageStride;
636      }
637   }
638   else {
639      /* general path */
640      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
641                                                 baseInternalFormat,
642                                                 dstFormat->BaseFormat,
643                                                 srcWidth, srcHeight, srcDepth,
644                                                 srcFormat, srcType, srcAddr,
645                                                 srcPacking);
646      const GLchan *src = tempImage;
647      GLint bytesPerRow;
648      GLubyte *dstImage = (GLubyte *) dstAddr
649                        + dstZoffset * dstImageStride
650                        + dstYoffset * dstRowStride
651                        + dstXoffset * dstFormat->TexelBytes;
652      GLint img, row;
653      if (!tempImage)
654         return GL_FALSE;
655      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
656      bytesPerRow = srcWidth * components * sizeof(GLchan);
657      for (img = 0; img < srcDepth; img++) {
658         GLubyte *dstRow = dstImage;
659         for (row = 0; row < srcHeight; row++) {
660            _mesa_memcpy(dstRow, src, bytesPerRow);
661            dstRow += dstRowStride;
662            src += srcWidth * components;
663         }
664         dstImage += dstImageStride;
665      }
666
667      _mesa_free((void *) tempImage);
668   }
669   return GL_TRUE;
670}
671
672
673/**
674 * Store a floating point depth component texture image.
675 */
676GLboolean
677_mesa_texstore_depth_component_float32(STORE_PARAMS)
678{
679   ASSERT(dstFormat == &_mesa_texformat_depth_component_float32);
680   ASSERT(dstFormat->TexelBytes == sizeof(GLfloat));
681
682   if (!ctx->_ImageTransferState &&
683       !srcPacking->SwapBytes &&
684       baseInternalFormat == GL_DEPTH_COMPONENT &&
685       srcFormat == GL_DEPTH_COMPONENT &&
686       srcType == GL_FLOAT) {
687      /* simple memcpy path */
688      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
689                     dstRowStride, dstImageStride,
690                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
691                     srcAddr, srcPacking);
692   }
693   else {
694      /* general path */
695      GLubyte *dstImage = (GLubyte *) dstAddr
696                        + dstZoffset * dstImageStride
697                        + dstYoffset * dstRowStride
698                        + dstXoffset * dstFormat->TexelBytes;
699      GLint img, row;
700      for (img = 0; img < srcDepth; img++) {
701         GLubyte *dstRow = dstImage;
702         for (row = 0; row < srcHeight; row++) {
703            const GLvoid *src = _mesa_image_address(srcPacking,
704                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
705            _mesa_unpack_depth_span(ctx, srcWidth, (GLfloat *) dstRow,
706                                    srcType, src, srcPacking);
707            dstRow += dstRowStride;
708         }
709         dstImage += dstImageStride;
710      }
711   }
712   return GL_TRUE;
713}
714
715
716/**
717 * Store a 16-bit integer depth component texture image.
718 */
719GLboolean
720_mesa_texstore_depth_component16(STORE_PARAMS)
721{
722   ASSERT(dstFormat == &_mesa_texformat_depth_component16);
723   ASSERT(dstFormat->TexelBytes == sizeof(GLushort));
724
725   if (!ctx->_ImageTransferState &&
726       !srcPacking->SwapBytes &&
727       baseInternalFormat == GL_DEPTH_COMPONENT &&
728       srcFormat == GL_DEPTH_COMPONENT &&
729       srcType == GL_UNSIGNED_SHORT) {
730      /* simple memcpy path */
731      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
732                     dstRowStride, dstImageStride,
733                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
734                     srcAddr, srcPacking);
735   }
736   else {
737      /* general path */
738      GLubyte *dstImage = (GLubyte *) dstAddr
739                        + dstZoffset * dstImageStride
740                        + dstYoffset * dstRowStride
741                        + dstXoffset * dstFormat->TexelBytes;
742      GLint img, row, col;
743      for (img = 0; img < srcDepth; img++) {
744         GLubyte *dstRow = dstImage;
745         for (row = 0; row < srcHeight; row++) {
746            GLfloat depthTemp[MAX_WIDTH];
747            const GLvoid *src = _mesa_image_address(srcPacking,
748                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
749            GLushort *dst16 = (GLushort *) dstRow;
750            _mesa_unpack_depth_span(ctx, srcWidth, depthTemp,
751                                    srcType, src, srcPacking);
752            for (col = 0; col < srcWidth; col++) {
753               dst16[col] = (GLushort) (depthTemp[col] * 65535.0F);
754            }
755            dstRow += dstRowStride;
756         }
757         dstImage += dstImageStride;
758      }
759   }
760   return GL_TRUE;
761}
762
763
764/**
765 * Store an rgb565 or rgb565_rev texture image.
766 */
767GLboolean
768_mesa_texstore_rgb565(STORE_PARAMS)
769{
770   ASSERT(dstFormat == &_mesa_texformat_rgb565 ||
771          dstFormat == &_mesa_texformat_rgb565_rev);
772   ASSERT(dstFormat->TexelBytes == 2);
773
774   if (!ctx->_ImageTransferState &&
775       !srcPacking->SwapBytes &&
776       dstFormat == &_mesa_texformat_rgb565 &&
777       baseInternalFormat == GL_RGB &&
778       srcFormat == GL_RGB &&
779       srcType == GL_UNSIGNED_SHORT_5_6_5) {
780      /* simple memcpy path */
781      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
782                     dstRowStride, dstImageStride,
783                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
784                     srcAddr, srcPacking);
785   }
786   else if (!ctx->_ImageTransferState &&
787            !srcPacking->SwapBytes &&
788            baseInternalFormat == GL_RGB &&
789            srcFormat == GL_RGB &&
790            srcType == GL_UNSIGNED_BYTE &&
791            dims == 2) {
792      /* do optimized tex store */
793      const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth,
794                                                        srcFormat, srcType);
795      const GLubyte *src = (const GLubyte *)
796         _mesa_image_address(srcPacking, srcAddr, srcWidth, srcHeight,
797                             srcFormat, srcType, 0, 0, 0);
798      GLubyte *dst = (GLubyte *) dstAddr
799                   + dstZoffset * dstImageStride
800                   + dstYoffset * dstRowStride
801                   + dstXoffset * dstFormat->TexelBytes;
802      GLint row, col;
803      for (row = 0; row < srcHeight; row++) {
804         const GLubyte *srcUB = (const GLubyte *) src;
805         GLushort *dstUS = (GLushort *) dst;
806         for (col = 0; col < srcWidth; col++) {
807            dstUS[col] = PACK_COLOR_565( srcUB[0], srcUB[1], srcUB[2] );
808            srcUB += 3;
809         }
810         /* check for byteswapped format */
811         if (dstFormat == &_mesa_texformat_rgb565_rev) {
812            _mesa_swap2(dstUS, srcWidth);
813         }
814         dst += dstRowStride;
815         src += srcRowStride;
816      }
817   }
818   else {
819      /* general path */
820      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
821                                                 baseInternalFormat,
822                                                 dstFormat->BaseFormat,
823                                                 srcWidth, srcHeight, srcDepth,
824                                                 srcFormat, srcType, srcAddr,
825                                                 srcPacking);
826      const GLchan *src = tempImage;
827      GLubyte *dstImage = (GLubyte *) dstAddr
828                        + dstZoffset * dstImageStride
829                        + dstYoffset * dstRowStride
830                        + dstXoffset * dstFormat->TexelBytes;
831      GLint img, row, col;
832      if (!tempImage)
833         return GL_FALSE;
834      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
835      for (img = 0; img < srcDepth; img++) {
836         GLubyte *dstRow = dstImage;
837         for (row = 0; row < srcHeight; row++) {
838            GLushort *dstUS = (GLushort *) dstRow;
839            for (col = 0; col < srcWidth; col++) {
840               dstUS[col] = PACK_COLOR_565( CHAN_TO_UBYTE(src[RCOMP]),
841                                            CHAN_TO_UBYTE(src[GCOMP]),
842                                            CHAN_TO_UBYTE(src[BCOMP]) );
843               src += 3;
844            }
845            /* check for byteswapped format */
846            if (dstFormat == &_mesa_texformat_rgb565_rev) {
847               _mesa_swap2(dstUS, srcWidth);
848            }
849            dstRow += dstRowStride;
850         }
851         dstImage += dstImageStride;
852      }
853      _mesa_free((void *) tempImage);
854   }
855   return GL_TRUE;
856}
857
858
859GLboolean
860_mesa_texstore_rgba8888(STORE_PARAMS)
861{
862   ASSERT(dstFormat == &_mesa_texformat_rgba8888 ||
863          dstFormat == &_mesa_texformat_rgba8888_rev);
864   ASSERT(dstFormat->TexelBytes == 4);
865
866   if (!ctx->_ImageTransferState &&
867       !srcPacking->SwapBytes &&
868       dstFormat == &_mesa_texformat_rgba8888 &&
869       baseInternalFormat == GL_RGBA &&
870      ((srcFormat == GL_RGBA && srcType == GL_UNSIGNED_INT_8_8_8_8) ||
871       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_INT_8_8_8_8_REV))) {
872      /* simple memcpy path */
873      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
874                     dstRowStride, dstImageStride,
875                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
876                     srcAddr, srcPacking);
877   }
878   else {
879      /* general path */
880      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
881                                                 baseInternalFormat,
882                                                 dstFormat->BaseFormat,
883                                                 srcWidth, srcHeight, srcDepth,
884                                                 srcFormat, srcType, srcAddr,
885                                                 srcPacking);
886      const GLchan *src = tempImage;
887      GLubyte *dstImage = (GLubyte *) dstAddr
888                        + dstZoffset * dstImageStride
889                        + dstYoffset * dstRowStride
890                        + dstXoffset * dstFormat->TexelBytes;
891      GLint img, row, col;
892      if (!tempImage)
893         return GL_FALSE;
894      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
895      for (img = 0; img < srcDepth; img++) {
896         GLubyte *dstRow = dstImage;
897         for (row = 0; row < srcHeight; row++) {
898            GLuint *dstUI = (GLuint *) dstRow;
899            for (col = 0; col < srcWidth; col++) {
900               dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[RCOMP]),
901                                             CHAN_TO_UBYTE(src[GCOMP]),
902                                             CHAN_TO_UBYTE(src[BCOMP]),
903                                             CHAN_TO_UBYTE(src[ACOMP]) );
904               src += 4;
905            }
906            /* check for byteswapped format */
907            if (dstFormat == &_mesa_texformat_rgba8888_rev) {
908               _mesa_swap4(dstUI, srcWidth);
909            }
910            dstRow += dstRowStride;
911         }
912         dstImage += dstImageStride;
913      }
914      _mesa_free((void *) tempImage);
915   }
916   return GL_TRUE;
917}
918
919
920GLboolean
921_mesa_texstore_argb8888(STORE_PARAMS)
922{
923   const GLuint ui = 1;
924   const GLubyte littleEndian = *((const GLubyte *) &ui);
925
926   ASSERT(dstFormat == &_mesa_texformat_argb8888 ||
927          dstFormat == &_mesa_texformat_argb8888_rev);
928   ASSERT(dstFormat->TexelBytes == 4);
929
930   if (!ctx->_ImageTransferState &&
931       !srcPacking->SwapBytes &&
932       dstFormat == &_mesa_texformat_argb8888 &&
933       baseInternalFormat == GL_RGBA &&
934       srcFormat == GL_BGRA &&
935       ((srcType == GL_UNSIGNED_BYTE && littleEndian) ||
936        srcType == GL_UNSIGNED_INT_8_8_8_8_REV)) {
937      /* simple memcpy path (little endian) */
938      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
939                     dstRowStride, dstImageStride,
940                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
941                     srcAddr, srcPacking);
942   }
943   else if (!ctx->_ImageTransferState &&
944       !srcPacking->SwapBytes &&
945       dstFormat == &_mesa_texformat_argb8888_rev &&
946       baseInternalFormat == GL_RGBA &&
947       srcFormat == GL_BGRA &&
948       ((srcType == GL_UNSIGNED_BYTE && !littleEndian) ||
949        srcType == GL_UNSIGNED_INT_8_8_8_8)) {
950      /* simple memcpy path (big endian) */
951      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
952                     dstRowStride, dstImageStride,
953                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
954                     srcAddr, srcPacking);
955   }
956   else {
957      /* general path */
958      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
959                                                 baseInternalFormat,
960                                                 dstFormat->BaseFormat,
961                                                 srcWidth, srcHeight, srcDepth,
962                                                 srcFormat, srcType, srcAddr,
963                                                 srcPacking);
964      const GLchan *src = tempImage;
965      GLubyte *dstImage = (GLubyte *) dstAddr
966                        + dstZoffset * dstImageStride
967                        + dstYoffset * dstRowStride
968                        + dstXoffset * dstFormat->TexelBytes;
969      GLint img, row, col;
970      if (!tempImage)
971         return GL_FALSE;
972      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
973      for (img = 0; img < srcDepth; img++) {
974         GLubyte *dstRow = dstImage;
975         for (row = 0; row < srcHeight; row++) {
976            GLuint *dstUI = (GLuint *) dstRow;
977            for (col = 0; col < srcWidth; col++) {
978               dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[ACOMP]),
979                                             CHAN_TO_UBYTE(src[RCOMP]),
980                                             CHAN_TO_UBYTE(src[GCOMP]),
981                                             CHAN_TO_UBYTE(src[BCOMP]) );
982               src += 4;
983            }
984            if (dstFormat == &_mesa_texformat_argb8888_rev) {
985               _mesa_swap4(dstUI, srcWidth);
986            }
987            dstRow += dstRowStride;
988         }
989         dstImage += dstImageStride;
990      }
991      _mesa_free((void *) tempImage);
992   }
993   return GL_TRUE;
994}
995
996
997GLboolean
998_mesa_texstore_rgb888(STORE_PARAMS)
999{
1000   const GLuint ui = 1;
1001   const GLubyte littleEndian = *((const GLubyte *) &ui);
1002
1003   ASSERT(dstFormat == &_mesa_texformat_rgb888);
1004   ASSERT(dstFormat->TexelBytes == 3);
1005
1006   if (!ctx->_ImageTransferState &&
1007       !srcPacking->SwapBytes &&
1008       baseInternalFormat == GL_RGB &&
1009       srcFormat == GL_BGR &&
1010       srcType == GL_UNSIGNED_BYTE &&
1011       littleEndian) {
1012      /* simple memcpy path */
1013      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1014                     dstRowStride, dstImageStride,
1015                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1016                     srcAddr, srcPacking);
1017   }
1018   else if (!ctx->_ImageTransferState &&
1019            !srcPacking->SwapBytes &&
1020            srcFormat == GL_RGBA &&
1021            srcType == GL_UNSIGNED_BYTE) {
1022      /* extract RGB from RGBA */
1023      int img, row, col;
1024      GLubyte *dstImage = (GLubyte *) dstAddr
1025                        + dstZoffset * dstImageStride
1026                        + dstYoffset * dstRowStride
1027                        + dstXoffset * dstFormat->TexelBytes;
1028      for (img = 0; img < srcDepth; img++) {
1029         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
1030                                                 srcWidth, srcFormat, srcType);
1031         GLubyte *srcRow = (GLubyte *) _mesa_image_address(srcPacking, srcAddr,
1032                           srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
1033         GLubyte *dstRow = dstImage;
1034         for (row = 0; row < srcHeight; row++) {
1035            for (col = 0; col < srcWidth; col++) {
1036               dstRow[col * 3 + 0] = srcRow[col * 4 + BCOMP];
1037               dstRow[col * 3 + 1] = srcRow[col * 4 + GCOMP];
1038               dstRow[col * 3 + 2] = srcRow[col * 4 + RCOMP];
1039            }
1040            dstRow += dstRowStride;
1041            srcRow += srcRowStride;
1042         }
1043         dstImage += dstImageStride;
1044      }
1045   }
1046   else {
1047      /* general path */
1048      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1049                                                 baseInternalFormat,
1050                                                 dstFormat->BaseFormat,
1051                                                 srcWidth, srcHeight, srcDepth,
1052                                                 srcFormat, srcType, srcAddr,
1053                                                 srcPacking);
1054      const GLchan *src = (const GLubyte *) tempImage;
1055      GLubyte *dstImage = (GLubyte *) dstAddr
1056                        + dstZoffset * dstImageStride
1057                        + dstYoffset * dstRowStride
1058                        + dstXoffset * dstFormat->TexelBytes;
1059      GLint img, row, col;
1060      if (!tempImage)
1061         return GL_FALSE;
1062      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1063      for (img = 0; img < srcDepth; img++) {
1064         GLubyte *dstRow = dstImage;
1065         for (row = 0; row < srcHeight; row++) {
1066#if 0
1067            if (littleEndian) {
1068               for (col = 0; col < srcWidth; col++) {
1069                  dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[RCOMP]);
1070                  dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]);
1071                  dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[BCOMP]);
1072                  srcUB += 3;
1073               }
1074            }
1075            else {
1076               for (col = 0; col < srcWidth; col++) {
1077                  dstRow[col * 3 + 0] = srcUB[BCOMP];
1078                  dstRow[col * 3 + 1] = srcUB[GCOMP];
1079                  dstRow[col * 3 + 2] = srcUB[RCOMP];
1080                  srcUB += 3;
1081               }
1082            }
1083#else
1084            for (col = 0; col < srcWidth; col++) {
1085               dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[BCOMP]);
1086               dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]);
1087               dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[RCOMP]);
1088               src += 3;
1089            }
1090#endif
1091            dstRow += dstRowStride;
1092         }
1093         dstImage += dstImageStride;
1094      }
1095      _mesa_free((void *) tempImage);
1096   }
1097   return GL_TRUE;
1098}
1099
1100
1101GLboolean
1102_mesa_texstore_bgr888(STORE_PARAMS)
1103{
1104   const GLuint ui = 1;
1105   const GLubyte littleEndian = *((const GLubyte *) &ui);
1106
1107   ASSERT(dstFormat == &_mesa_texformat_bgr888);
1108   ASSERT(dstFormat->TexelBytes == 3);
1109
1110   if (!ctx->_ImageTransferState &&
1111       !srcPacking->SwapBytes &&
1112       baseInternalFormat == GL_RGB &&
1113       srcFormat == GL_RGB &&
1114       srcType == GL_UNSIGNED_BYTE &&
1115       littleEndian) {
1116      /* simple memcpy path */
1117      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1118                     dstRowStride, dstImageStride,
1119                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1120                     srcAddr, srcPacking);
1121   }
1122   else if (!ctx->_ImageTransferState &&
1123            !srcPacking->SwapBytes &&
1124            srcFormat == GL_RGBA &&
1125            srcType == GL_UNSIGNED_BYTE) {
1126      /* extract BGR from RGBA */
1127      int img, row, col;
1128      GLubyte *dstImage = (GLubyte *) dstAddr
1129                        + dstZoffset * dstImageStride
1130                        + dstYoffset * dstRowStride
1131                        + dstXoffset * dstFormat->TexelBytes;
1132      for (img = 0; img < srcDepth; img++) {
1133         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
1134                                                 srcWidth, srcFormat, srcType);
1135         GLubyte *srcRow = (GLubyte *) _mesa_image_address(srcPacking, srcAddr,
1136                           srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
1137         GLubyte *dstRow = dstImage;
1138         for (row = 0; row < srcHeight; row++) {
1139            for (col = 0; col < srcWidth; col++) {
1140               dstRow[col * 3 + 0] = srcRow[col * 4 + RCOMP];
1141               dstRow[col * 3 + 1] = srcRow[col * 4 + GCOMP];
1142               dstRow[col * 3 + 2] = srcRow[col * 4 + BCOMP];
1143            }
1144            dstRow += dstRowStride;
1145            srcRow += srcRowStride;
1146         }
1147         dstImage += dstImageStride;
1148      }
1149   }
1150   else {
1151      /* general path */
1152      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1153                                                 baseInternalFormat,
1154                                                 dstFormat->BaseFormat,
1155                                                 srcWidth, srcHeight, srcDepth,
1156                                                 srcFormat, srcType, srcAddr,
1157                                                 srcPacking);
1158      const GLchan *src = (const GLubyte *) tempImage;
1159      GLubyte *dstImage = (GLubyte *) dstAddr
1160                        + dstZoffset * dstImageStride
1161                        + dstYoffset * dstRowStride
1162                        + dstXoffset * dstFormat->TexelBytes;
1163      GLint img, row, col;
1164      if (!tempImage)
1165         return GL_FALSE;
1166      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1167      for (img = 0; img < srcDepth; img++) {
1168         GLubyte *dstRow = dstImage;
1169         for (row = 0; row < srcHeight; row++) {
1170            for (col = 0; col < srcWidth; col++) {
1171               dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[RCOMP]);
1172               dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]);
1173               dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[BCOMP]);
1174               src += 3;
1175            }
1176            dstRow += dstRowStride;
1177         }
1178         dstImage += dstImageStride;
1179      }
1180      _mesa_free((void *) tempImage);
1181   }
1182   return GL_TRUE;
1183}
1184
1185
1186GLboolean
1187_mesa_texstore_argb4444(STORE_PARAMS)
1188{
1189   ASSERT(dstFormat == &_mesa_texformat_argb4444 ||
1190          dstFormat == &_mesa_texformat_argb4444_rev);
1191   ASSERT(dstFormat->TexelBytes == 2);
1192
1193   if (!ctx->_ImageTransferState &&
1194       !srcPacking->SwapBytes &&
1195       dstFormat == &_mesa_texformat_argb4444 &&
1196       baseInternalFormat == GL_RGBA &&
1197       srcFormat == GL_BGRA &&
1198       srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV) {
1199      /* simple memcpy path */
1200      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1201                     dstRowStride, dstImageStride,
1202                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1203                     srcAddr, srcPacking);
1204   }
1205   else {
1206      /* general path */
1207      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1208                                                 baseInternalFormat,
1209                                                 dstFormat->BaseFormat,
1210                                                 srcWidth, srcHeight, srcDepth,
1211                                                 srcFormat, srcType, srcAddr,
1212                                                 srcPacking);
1213      const GLchan *src = tempImage;
1214      GLubyte *dstImage = (GLubyte *) dstAddr
1215                        + dstZoffset * dstImageStride
1216                        + dstYoffset * dstRowStride
1217                        + dstXoffset * dstFormat->TexelBytes;
1218      GLint img, row, col;
1219      if (!tempImage)
1220         return GL_FALSE;
1221      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1222      for (img = 0; img < srcDepth; img++) {
1223         GLubyte *dstRow = dstImage;
1224         for (row = 0; row < srcHeight; row++) {
1225            GLushort *dstUS = (GLushort *) dstRow;
1226            for (col = 0; col < srcWidth; col++) {
1227               dstUS[col] = PACK_COLOR_4444( CHAN_TO_UBYTE(src[ACOMP]),
1228                                             CHAN_TO_UBYTE(src[RCOMP]),
1229                                             CHAN_TO_UBYTE(src[GCOMP]),
1230                                             CHAN_TO_UBYTE(src[BCOMP]) );
1231               src += 4;
1232            }
1233            if (dstFormat == &_mesa_texformat_argb4444_rev) {
1234               _mesa_swap2(dstUS, srcWidth);
1235            }
1236            dstRow += dstRowStride;
1237         }
1238         dstImage += dstImageStride;
1239      }
1240      _mesa_free((void *) tempImage);
1241   }
1242   return GL_TRUE;
1243}
1244
1245
1246
1247GLboolean
1248_mesa_texstore_argb1555(STORE_PARAMS)
1249{
1250   ASSERT(dstFormat == &_mesa_texformat_argb1555 ||
1251          dstFormat == &_mesa_texformat_argb1555_rev);
1252   ASSERT(dstFormat->TexelBytes == 2);
1253
1254   if (!ctx->_ImageTransferState &&
1255       !srcPacking->SwapBytes &&
1256       dstFormat == &_mesa_texformat_argb1555 &&
1257       baseInternalFormat == GL_RGBA &&
1258       srcFormat == GL_BGRA &&
1259       srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV) {
1260      /* simple memcpy path */
1261      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1262                     dstRowStride, dstImageStride,
1263                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1264                     srcAddr, srcPacking);
1265   }
1266   else {
1267      /* general path */
1268      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1269                                                 baseInternalFormat,
1270                                                 dstFormat->BaseFormat,
1271                                                 srcWidth, srcHeight, srcDepth,
1272                                                 srcFormat, srcType, srcAddr,
1273                                                 srcPacking);
1274      const GLchan *src =tempImage;
1275      GLubyte *dstImage = (GLubyte *) dstAddr
1276                        + dstZoffset * dstImageStride
1277                        + dstYoffset * dstRowStride
1278                        + dstXoffset * dstFormat->TexelBytes;
1279      GLint img, row, col;
1280      if (!tempImage)
1281         return GL_FALSE;
1282      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1283      for (img = 0; img < srcDepth; img++) {
1284         GLubyte *dstRow = dstImage;
1285         for (row = 0; row < srcHeight; row++) {
1286            GLushort *dstUS = (GLushort *) dstRow;
1287            for (col = 0; col < srcWidth; col++) {
1288               dstUS[col] = PACK_COLOR_1555( CHAN_TO_UBYTE(src[ACOMP]),
1289                                             CHAN_TO_UBYTE(src[RCOMP]),
1290                                             CHAN_TO_UBYTE(src[GCOMP]),
1291                                             CHAN_TO_UBYTE(src[BCOMP]) );
1292               src += 4;
1293            }
1294            if (dstFormat == &_mesa_texformat_argb1555_rev) {
1295               _mesa_swap2(dstUS, srcWidth);
1296            }
1297            dstRow += dstRowStride;
1298         }
1299         dstImage += dstImageStride;
1300      }
1301      _mesa_free((void *) tempImage);
1302   }
1303   return GL_TRUE;
1304}
1305
1306
1307GLboolean
1308_mesa_texstore_al88(STORE_PARAMS)
1309{
1310   const GLuint ui = 1;
1311   const GLubyte littleEndian = *((const GLubyte *) &ui);
1312
1313   ASSERT(dstFormat == &_mesa_texformat_al88 ||
1314          dstFormat == &_mesa_texformat_al88_rev);
1315   ASSERT(dstFormat->TexelBytes == 2);
1316
1317   if (!ctx->_ImageTransferState &&
1318       !srcPacking->SwapBytes &&
1319       dstFormat == &_mesa_texformat_al88 &&
1320       baseInternalFormat == GL_LUMINANCE_ALPHA &&
1321       srcFormat == GL_LUMINANCE_ALPHA &&
1322       srcType == GL_UNSIGNED_BYTE &&
1323       littleEndian) {
1324      /* simple memcpy path */
1325      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1326                     dstRowStride, dstImageStride,
1327                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1328                     srcAddr, srcPacking);
1329   }
1330   else {
1331      /* general path */
1332      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1333                                                 baseInternalFormat,
1334                                                 dstFormat->BaseFormat,
1335                                                 srcWidth, srcHeight, srcDepth,
1336                                                 srcFormat, srcType, srcAddr,
1337                                                 srcPacking);
1338      const GLchan *src = tempImage;
1339      GLubyte *dstImage = (GLubyte *) dstAddr
1340                        + dstZoffset * dstImageStride
1341                        + dstYoffset * dstRowStride
1342                        + dstXoffset * dstFormat->TexelBytes;
1343      GLint img, row, col;
1344      if (!tempImage)
1345         return GL_FALSE;
1346      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1347      for (img = 0; img < srcDepth; img++) {
1348         GLubyte *dstRow = dstImage;
1349         for (row = 0; row < srcHeight; row++) {
1350            GLushort *dstUS = (GLushort *) dstRow;
1351            for (col = 0; col < srcWidth; col++) {
1352               dstUS[col] = PACK_COLOR_88( CHAN_TO_UBYTE(src[ACOMP]),
1353                                           CHAN_TO_UBYTE(src[RCOMP]) );
1354               src += 2;
1355            }
1356            if (dstFormat == &_mesa_texformat_al88_rev) {
1357               _mesa_swap2(dstUS, srcWidth);
1358            }
1359            dstRow += dstRowStride;
1360         }
1361         dstImage += dstImageStride;
1362      }
1363      _mesa_free((void *) tempImage);
1364   }
1365   return GL_TRUE;
1366}
1367
1368
1369GLboolean
1370_mesa_texstore_rgb332(STORE_PARAMS)
1371{
1372   ASSERT(dstFormat == &_mesa_texformat_rgb332);
1373   ASSERT(dstFormat->TexelBytes == 1);
1374
1375   if (!ctx->_ImageTransferState &&
1376       !srcPacking->SwapBytes &&
1377       baseInternalFormat == GL_RGB &&
1378       srcFormat == GL_RGB && srcType == GL_UNSIGNED_BYTE_3_3_2) {
1379      /* simple memcpy path */
1380      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1381                     dstRowStride, dstImageStride,
1382                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1383                     srcAddr, srcPacking);
1384   }
1385   else {
1386      /* general path */
1387      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1388                                                 baseInternalFormat,
1389                                                 dstFormat->BaseFormat,
1390                                                 srcWidth, srcHeight, srcDepth,
1391                                                 srcFormat, srcType, srcAddr,
1392                                                 srcPacking);
1393      const GLchan *src = tempImage;
1394      GLubyte *dstImage = (GLubyte *) dstAddr
1395                        + dstZoffset * dstImageStride
1396                        + dstYoffset * dstRowStride
1397                        + dstXoffset * dstFormat->TexelBytes;
1398      GLint img, row, col;
1399      if (!tempImage)
1400         return GL_FALSE;
1401      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1402      for (img = 0; img < srcDepth; img++) {
1403         GLubyte *dstRow = dstImage;
1404         for (row = 0; row < srcHeight; row++) {
1405            for (col = 0; col < srcWidth; col++) {
1406               dstRow[col] = PACK_COLOR_332( CHAN_TO_UBYTE(src[RCOMP]),
1407                                             CHAN_TO_UBYTE(src[GCOMP]),
1408                                             CHAN_TO_UBYTE(src[BCOMP]) );
1409               src += 3;
1410            }
1411            dstRow += dstRowStride;
1412         }
1413         dstImage += dstImageStride;
1414      }
1415      _mesa_free((void *) tempImage);
1416   }
1417   return GL_TRUE;
1418}
1419
1420
1421/**
1422 * Texstore for _mesa_texformat_a8, _mesa_texformat_l8, _mesa_texformat_i8.
1423 */
1424GLboolean
1425_mesa_texstore_a8(STORE_PARAMS)
1426{
1427   ASSERT(dstFormat == &_mesa_texformat_a8 ||
1428          dstFormat == &_mesa_texformat_l8 ||
1429          dstFormat == &_mesa_texformat_i8);
1430   ASSERT(dstFormat->TexelBytes == 1);
1431
1432   if (!ctx->_ImageTransferState &&
1433       !srcPacking->SwapBytes &&
1434       baseInternalFormat == srcFormat &&
1435       srcType == GL_UNSIGNED_BYTE) {
1436      /* simple memcpy path */
1437      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1438                     dstRowStride, dstImageStride,
1439                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1440                     srcAddr, srcPacking);
1441   }
1442   else {
1443      /* general path */
1444      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1445                                                 baseInternalFormat,
1446                                                 dstFormat->BaseFormat,
1447                                                 srcWidth, srcHeight, srcDepth,
1448                                                 srcFormat, srcType, srcAddr,
1449                                                 srcPacking);
1450      const GLchan *src = tempImage;
1451      GLubyte *dstImage = (GLubyte *) dstAddr
1452                        + dstZoffset * dstImageStride
1453                        + dstYoffset * dstRowStride
1454                        + dstXoffset * dstFormat->TexelBytes;
1455      GLint img, row, col;
1456      if (!tempImage)
1457         return GL_FALSE;
1458      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1459      for (img = 0; img < srcDepth; img++) {
1460         GLubyte *dstRow = dstImage;
1461         for (row = 0; row < srcHeight; row++) {
1462            for (col = 0; col < srcWidth; col++) {
1463               dstRow[col] = CHAN_TO_UBYTE(src[col]);
1464            }
1465            dstRow += dstRowStride;
1466            src += srcWidth;
1467         }
1468         dstImage += dstImageStride;
1469      }
1470      _mesa_free((void *) tempImage);
1471   }
1472   return GL_TRUE;
1473}
1474
1475
1476
1477GLboolean
1478_mesa_texstore_ci8(STORE_PARAMS)
1479{
1480   ASSERT(dstFormat == &_mesa_texformat_ci8);
1481   ASSERT(dstFormat->TexelBytes == 1);
1482   ASSERT(baseInternalFormat == GL_COLOR_INDEX);
1483
1484   if (!ctx->_ImageTransferState &&
1485       !srcPacking->SwapBytes &&
1486       srcFormat == GL_COLOR_INDEX &&
1487       srcType == GL_UNSIGNED_BYTE) {
1488      /* simple memcpy path */
1489      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1490                     dstRowStride, dstImageStride,
1491                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1492                     srcAddr, srcPacking);
1493   }
1494   else {
1495      /* general path */
1496      GLubyte *dstImage = (GLubyte *) dstAddr
1497                        + dstZoffset * dstImageStride
1498                        + dstYoffset * dstRowStride
1499                        + dstXoffset * dstFormat->TexelBytes;
1500      GLint img, row;
1501      for (img = 0; img < srcDepth; img++) {
1502         GLubyte *dstRow = dstImage;
1503         for (row = 0; row < srcHeight; row++) {
1504            const GLvoid *src = _mesa_image_address(srcPacking,
1505                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
1506            _mesa_unpack_index_span(ctx, srcWidth, GL_UNSIGNED_BYTE, dstRow,
1507                                    srcType, src, srcPacking,
1508                                    ctx->_ImageTransferState);
1509            dstRow += dstRowStride;
1510         }
1511         dstImage += dstImageStride;
1512      }
1513   }
1514   return GL_TRUE;
1515}
1516
1517
1518/**
1519 * Texstore for _mesa_texformat_ycbcr or _mesa_texformat_ycbcr_rev.
1520 */
1521GLboolean
1522_mesa_texstore_ycbcr(STORE_PARAMS)
1523{
1524   const GLuint ui = 1;
1525   const GLubyte littleEndian = *((const GLubyte *) &ui);
1526
1527   ASSERT((dstFormat == &_mesa_texformat_ycbcr) ||
1528          (dstFormat == &_mesa_texformat_ycbcr_rev));
1529   ASSERT(dstFormat->TexelBytes == 2);
1530   ASSERT(ctx->Extensions.MESA_ycbcr_texture);
1531   ASSERT(srcFormat == GL_YCBCR_MESA);
1532   ASSERT((srcType == GL_UNSIGNED_SHORT_8_8_MESA) ||
1533          (srcType == GL_UNSIGNED_SHORT_8_8_REV_MESA));
1534   ASSERT(baseInternalFormat == GL_YCBCR_MESA);
1535
1536   /* always just memcpy since no pixel transfer ops apply */
1537   memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1538                  dstRowStride, dstImageStride,
1539                  srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1540                  srcAddr, srcPacking);
1541
1542   /* Check if we need byte swapping */
1543   /* XXX the logic here _might_ be wrong */
1544   if (srcPacking->SwapBytes ^
1545       (srcType == GL_UNSIGNED_SHORT_8_8_REV_MESA) ^
1546       (dstFormat == &_mesa_texformat_ycbcr_rev) ^
1547       !littleEndian) {
1548      GLushort *pImage = (GLushort *) ((GLubyte *) dstAddr
1549                                       + dstZoffset * dstImageStride
1550                                       + dstYoffset * dstRowStride
1551                                       + dstXoffset * dstFormat->TexelBytes);
1552      GLint img, row;
1553      for (img = 0; img < srcDepth; img++) {
1554         GLushort *pRow = pImage;
1555         for (row = 0; row < srcHeight; row++) {
1556            _mesa_swap2(pRow, srcWidth);
1557            pRow += dstRowStride;
1558         }
1559         pImage += dstImageStride;
1560      }
1561   }
1562   return GL_TRUE;
1563}
1564
1565
1566
1567
1568/**
1569 * Store an image in any of the formats:
1570 *   _mesa_texformat_rgba_float32
1571 *   _mesa_texformat_rgb_float32
1572 *   _mesa_texformat_alpha_float32
1573 *   _mesa_texformat_luminance_float32
1574 *   _mesa_texformat_luminance_alpha_float32
1575 *   _mesa_texformat_intensity_float32
1576 */
1577GLboolean
1578_mesa_texstore_rgba_float32(STORE_PARAMS)
1579{
1580   const GLint components = _mesa_components_in_format(baseInternalFormat);
1581
1582   ASSERT(dstFormat == &_mesa_texformat_rgba_float32 ||
1583          dstFormat == &_mesa_texformat_rgb_float32 ||
1584          dstFormat == &_mesa_texformat_alpha_float32 ||
1585          dstFormat == &_mesa_texformat_luminance_float32 ||
1586          dstFormat == &_mesa_texformat_luminance_alpha_float32 ||
1587          dstFormat == &_mesa_texformat_intensity_float32);
1588   ASSERT(baseInternalFormat == GL_RGBA ||
1589          baseInternalFormat == GL_RGB ||
1590          baseInternalFormat == GL_ALPHA ||
1591          baseInternalFormat == GL_LUMINANCE ||
1592          baseInternalFormat == GL_LUMINANCE_ALPHA ||
1593          baseInternalFormat == GL_INTENSITY);
1594   ASSERT(dstFormat->TexelBytes == components * sizeof(GLfloat));
1595
1596   if (!ctx->_ImageTransferState &&
1597       !srcPacking->SwapBytes &&
1598       baseInternalFormat == srcFormat &&
1599       srcType == GL_FLOAT) {
1600      /* simple memcpy path */
1601      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1602                     dstRowStride, dstImageStride,
1603                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1604                     srcAddr, srcPacking);
1605   }
1606   else {
1607      /* general path */
1608      const GLfloat *tempImage = make_temp_float_image(ctx, dims,
1609                                                 baseInternalFormat,
1610                                                 dstFormat->BaseFormat,
1611                                                 srcWidth, srcHeight, srcDepth,
1612                                                 srcFormat, srcType, srcAddr,
1613                                                 srcPacking);
1614      const GLfloat *src = tempImage;
1615      GLint bytesPerRow;
1616      GLubyte *dstImage = (GLubyte *) dstAddr
1617                        + dstZoffset * dstImageStride
1618                        + dstYoffset * dstRowStride
1619                        + dstXoffset * dstFormat->TexelBytes;
1620      GLint img, row;
1621      if (!tempImage)
1622         return GL_FALSE;
1623      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1624      bytesPerRow = srcWidth * components * sizeof(GLfloat);
1625      for (img = 0; img < srcDepth; img++) {
1626         GLubyte *dst = dstImage;
1627         for (row = 0; row < srcHeight; row++) {
1628            _mesa_memcpy(dst, src, bytesPerRow);
1629            dst += dstRowStride;
1630            src += srcWidth * components;
1631         }
1632         dstImage += dstImageStride;
1633      }
1634
1635      _mesa_free((void *) tempImage);
1636   }
1637   return GL_TRUE;
1638}
1639
1640
1641/**
1642 * As above, but store 16-bit floats.
1643 */
1644GLboolean
1645_mesa_texstore_rgba_float16(STORE_PARAMS)
1646{
1647   const GLint components = _mesa_components_in_format(baseInternalFormat);
1648
1649   ASSERT(dstFormat == &_mesa_texformat_rgba_float16 ||
1650          dstFormat == &_mesa_texformat_rgb_float16 ||
1651          dstFormat == &_mesa_texformat_alpha_float16 ||
1652          dstFormat == &_mesa_texformat_luminance_float16 ||
1653          dstFormat == &_mesa_texformat_luminance_alpha_float16 ||
1654          dstFormat == &_mesa_texformat_intensity_float16);
1655   ASSERT(baseInternalFormat == GL_RGBA ||
1656          baseInternalFormat == GL_RGB ||
1657          baseInternalFormat == GL_ALPHA ||
1658          baseInternalFormat == GL_LUMINANCE ||
1659          baseInternalFormat == GL_LUMINANCE_ALPHA ||
1660          baseInternalFormat == GL_INTENSITY);
1661   ASSERT(dstFormat->TexelBytes == components * sizeof(GLhalfARB));
1662
1663   if (!ctx->_ImageTransferState &&
1664       !srcPacking->SwapBytes &&
1665       baseInternalFormat == srcFormat &&
1666       srcType == GL_HALF_FLOAT_ARB) {
1667      /* simple memcpy path */
1668      memcpy_texture(dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1669                     dstRowStride, dstImageStride,
1670                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1671                     srcAddr, srcPacking);
1672   }
1673   else {
1674      /* general path */
1675      const GLfloat *tempImage = make_temp_float_image(ctx, dims,
1676                                                 baseInternalFormat,
1677                                                 dstFormat->BaseFormat,
1678                                                 srcWidth, srcHeight, srcDepth,
1679                                                 srcFormat, srcType, srcAddr,
1680                                                 srcPacking);
1681      const GLfloat *src = tempImage;
1682      GLubyte *dstImage = (GLubyte *) dstAddr
1683                        + dstZoffset * dstImageStride
1684                        + dstYoffset * dstRowStride
1685                        + dstXoffset * dstFormat->TexelBytes;
1686      GLint img, row;
1687      if (!tempImage)
1688         return GL_FALSE;
1689      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1690      for (img = 0; img < srcDepth; img++) {
1691         GLubyte *dstRow = dstImage;
1692         for (row = 0; row < srcHeight; row++) {
1693            GLhalfARB *dstTexel = (GLhalfARB *) dstRow;
1694            GLint i;
1695            for (i = 0; i < srcWidth * components; i++) {
1696               dstTexel[i] = _mesa_float_to_half(src[i]);
1697            }
1698            dstRow += dstRowStride;
1699            src += srcWidth * components;
1700         }
1701         dstImage += dstImageStride;
1702      }
1703
1704      _mesa_free((void *) tempImage);
1705   }
1706   return GL_TRUE;
1707}
1708
1709
1710
1711/**
1712 * Validate acces to a PBO for texture data.
1713 *
1714 * \todo If the PBO is really resident in VRAM, this won't work; the
1715 * device driver should check for that and do the right thing.
1716 */
1717static const GLvoid *
1718validate_pbo_teximage( GLsizei width, GLsizei height, GLsizei depth,
1719                       GLenum format, GLenum type, const GLvoid *pixels,
1720                       const struct gl_pixelstore_attrib *unpack )
1721{
1722   if (unpack->BufferObj->Name == 0) {
1723      /* no PBO */
1724      return pixels;
1725   }
1726   else if (_mesa_validate_pbo_access(unpack, width, height, depth, format,
1727                                      type, pixels)) {
1728      return ADD_POINTERS(unpack->BufferObj->Data, pixels);
1729   }
1730   /* bad access! */
1731   return NULL;
1732}
1733
1734
1735/**
1736 * Validate that unpacking compressed texture image data from a PBO
1737 * won't go out of bounds.
1738 *
1739 * \todo If the PBO is really resident in VRAM, this won't work; the
1740 * device driver should check for that and do the right thing.
1741 */
1742static const GLvoid *
1743validate_pbo_compressed_teximage(GLsizei imageSize, const GLvoid *pixels,
1744                               const struct gl_pixelstore_attrib *packing)
1745{
1746   if (packing->BufferObj->Name == 0) {
1747      /* not using a PBO - return pointer unchanged */
1748      return pixels;
1749   }
1750   else {
1751      /* using a PBO */
1752      if ((const GLubyte *) pixels + imageSize >
1753          (const GLubyte *) packing->BufferObj->Size) {
1754         /* out of bounds read! */
1755         return NULL;
1756      }
1757      /* OK! */
1758      return ADD_POINTERS(packing->BufferObj->Data, pixels);
1759   }
1760}
1761
1762
1763
1764/*
1765 * This is the software fallback for Driver.TexImage1D()
1766 * and Driver.CopyTexImage1D().
1767 */
1768void
1769_mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
1770                       GLint internalFormat,
1771                       GLint width, GLint border,
1772                       GLenum format, GLenum type, const GLvoid *pixels,
1773                       const struct gl_pixelstore_attrib *packing,
1774                       struct gl_texture_object *texObj,
1775                       struct gl_texture_image *texImage)
1776{
1777   GLint postConvWidth = width;
1778   GLint sizeInBytes;
1779
1780   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
1781      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
1782   }
1783
1784   /* choose the texture format */
1785   assert(ctx->Driver.ChooseTextureFormat);
1786   texImage->TexFormat = ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
1787                                                         format, type);
1788   assert(texImage->TexFormat);
1789   texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D;
1790   texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df;
1791
1792   /* allocate memory */
1793   if (texImage->IsCompressed)
1794      sizeInBytes = texImage->CompressedSize;
1795   else
1796      sizeInBytes = postConvWidth * texImage->TexFormat->TexelBytes;
1797   texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
1798   if (!texImage->Data) {
1799      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
1800      return;
1801   }
1802
1803   pixels = validate_pbo_teximage(width, 1, 1, format, type, pixels, packing);
1804   if (!pixels)
1805      return;
1806
1807   {
1808      const GLint dstRowStride = 0, dstImageStride = 0;
1809      GLboolean success;
1810      ASSERT(texImage->TexFormat->StoreImage);
1811      success = texImage->TexFormat->StoreImage(ctx, 1, texImage->Format,
1812                                                texImage->TexFormat,
1813                                                texImage->Data,
1814                                                0, 0, 0,  /* dstX/Y/Zoffset */
1815                                                dstRowStride, dstImageStride,
1816                                                width, 1, 1,
1817                                                format, type, pixels, packing);
1818      if (!success) {
1819         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
1820         return;
1821      }
1822   }
1823
1824   /* GL_SGIS_generate_mipmap */
1825   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1826      _mesa_generate_mipmap(ctx, target,
1827                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1828                            texObj);
1829   }
1830}
1831
1832
1833/*
1834 * This is the software fallback for Driver.TexImage2D()
1835 * and Driver.CopyTexImage2D().
1836 * Reasons why a driver might override this function:
1837 *  - Special memory allocation needs
1838 *  - Unusual row/image strides
1839 *  - Special housekeeping
1840 */
1841void
1842_mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
1843                       GLint internalFormat,
1844                       GLint width, GLint height, GLint border,
1845                       GLenum format, GLenum type, const void *pixels,
1846                       const struct gl_pixelstore_attrib *packing,
1847                       struct gl_texture_object *texObj,
1848                       struct gl_texture_image *texImage)
1849{
1850   GLint postConvWidth = width, postConvHeight = height;
1851   GLint texelBytes, sizeInBytes;
1852
1853   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
1854      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
1855                                         &postConvHeight);
1856   }
1857
1858   /* choose the texture format */
1859   assert(ctx->Driver.ChooseTextureFormat);
1860   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1861                                          internalFormat, format, type);
1862   assert(texImage->TexFormat);
1863   texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
1864   texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
1865
1866   texelBytes = texImage->TexFormat->TexelBytes;
1867
1868   /* allocate memory */
1869   if (texImage->IsCompressed)
1870      sizeInBytes = texImage->CompressedSize;
1871   else
1872      sizeInBytes = postConvWidth * postConvHeight * texelBytes;
1873   texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
1874   if (!texImage->Data) {
1875      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1876      return;
1877   }
1878
1879   pixels = validate_pbo_teximage(width, height, 1,
1880                                  format, type, pixels, packing);
1881   if (!pixels)
1882      return;
1883
1884   {
1885      GLint dstRowStride, dstImageStride = 0;
1886      GLboolean success;
1887      if (texImage->IsCompressed) {
1888         dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,width);
1889      }
1890      else {
1891         dstRowStride = postConvWidth * texImage->TexFormat->TexelBytes;
1892      }
1893      ASSERT(texImage->TexFormat->StoreImage);
1894      success = texImage->TexFormat->StoreImage(ctx, 2, texImage->Format,
1895                                                texImage->TexFormat,
1896                                                texImage->Data,
1897                                                0, 0, 0,  /* dstX/Y/Zoffset */
1898                                                dstRowStride, dstImageStride,
1899                                                width, height, 1,
1900                                                format, type, pixels, packing);
1901      if (!success) {
1902         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1903         return;
1904      }
1905   }
1906
1907   /* GL_SGIS_generate_mipmap */
1908   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1909      _mesa_generate_mipmap(ctx, target,
1910                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1911                            texObj);
1912   }
1913}
1914
1915
1916
1917/*
1918 * This is the software fallback for Driver.TexImage3D()
1919 * and Driver.CopyTexImage3D().
1920 */
1921void
1922_mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
1923                       GLint internalFormat,
1924                       GLint width, GLint height, GLint depth, GLint border,
1925                       GLenum format, GLenum type, const void *pixels,
1926                       const struct gl_pixelstore_attrib *packing,
1927                       struct gl_texture_object *texObj,
1928                       struct gl_texture_image *texImage)
1929{
1930   GLint texelBytes, sizeInBytes;
1931
1932   /* choose the texture format */
1933   assert(ctx->Driver.ChooseTextureFormat);
1934   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1935                                          internalFormat, format, type);
1936   assert(texImage->TexFormat);
1937   texImage->FetchTexelc = texImage->TexFormat->FetchTexel3D;
1938   texImage->FetchTexelf = texImage->TexFormat->FetchTexel3Df;
1939
1940   texelBytes = texImage->TexFormat->TexelBytes;
1941
1942   /* allocate memory */
1943   if (texImage->IsCompressed)
1944      sizeInBytes = texImage->CompressedSize;
1945   else
1946      sizeInBytes = width * height * depth * texelBytes;
1947   texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
1948   if (!texImage->Data) {
1949      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
1950      return;
1951   }
1952
1953   pixels = validate_pbo_teximage(width, height, depth,
1954                                  format, type, pixels, packing);
1955   if (!pixels)
1956      return;
1957
1958   /* unpack image, apply transfer ops and store in texImage->Data */
1959   {
1960      GLint dstRowStride, dstImageStride;
1961      GLboolean success;
1962      if (texImage->IsCompressed) {
1963         dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,width);
1964         dstImageStride = 0;
1965      }
1966      else {
1967         dstRowStride = width * texImage->TexFormat->TexelBytes;
1968         dstImageStride = dstRowStride * height;
1969      }
1970      ASSERT(texImage->TexFormat->StoreImage);
1971      success = texImage->TexFormat->StoreImage(ctx, 3, texImage->Format,
1972                                                texImage->TexFormat,
1973                                                texImage->Data,
1974                                                0, 0, 0,  /* dstX/Y/Zoffset */
1975                                                dstRowStride, dstImageStride,
1976                                                width, height, depth,
1977                                                format, type, pixels, packing);
1978      if (!success) {
1979         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
1980         return;
1981      }
1982   }
1983
1984   /* GL_SGIS_generate_mipmap */
1985   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1986      _mesa_generate_mipmap(ctx, target,
1987                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1988                            texObj);
1989   }
1990}
1991
1992
1993
1994
1995/*
1996 * This is the software fallback for Driver.TexSubImage1D()
1997 * and Driver.CopyTexSubImage1D().
1998 */
1999void
2000_mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
2001                          GLint xoffset, GLint width,
2002                          GLenum format, GLenum type, const void *pixels,
2003                          const struct gl_pixelstore_attrib *packing,
2004                          struct gl_texture_object *texObj,
2005                          struct gl_texture_image *texImage)
2006{
2007   pixels = validate_pbo_teximage(width, 1, 1,
2008                                  format, type, pixels, packing);
2009   if (!pixels)
2010      return;
2011
2012   {
2013      const GLint dstRowStride = 0, dstImageStride = 0;
2014      GLboolean success;
2015      ASSERT(texImage->TexFormat->StoreImage);
2016      success = texImage->TexFormat->StoreImage(ctx, 1, texImage->Format,
2017                                                texImage->TexFormat,
2018                                                texImage->Data,
2019                                                xoffset, 0, 0,  /* offsets */
2020                                                dstRowStride, dstImageStride,
2021                                                width, 1, 1,
2022                                                format, type, pixels, packing);
2023      if (!success) {
2024         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
2025         return;
2026      }
2027   }
2028
2029   /* GL_SGIS_generate_mipmap */
2030   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2031      _mesa_generate_mipmap(ctx, target,
2032                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2033                            texObj);
2034   }
2035}
2036
2037
2038
2039/**
2040 * This is the software fallback for Driver.TexSubImage2D()
2041 * and Driver.CopyTexSubImage2D().
2042 */
2043void
2044_mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
2045                          GLint xoffset, GLint yoffset,
2046                          GLint width, GLint height,
2047                          GLenum format, GLenum type, const void *pixels,
2048                          const struct gl_pixelstore_attrib *packing,
2049                          struct gl_texture_object *texObj,
2050                          struct gl_texture_image *texImage)
2051{
2052   pixels = validate_pbo_teximage(width, height, 1,
2053                                  format, type, pixels, packing);
2054   if (!pixels)
2055      return;
2056
2057   {
2058      GLint dstRowStride = 0, dstImageStride = 0;
2059      GLboolean success;
2060      if (texImage->IsCompressed) {
2061         dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
2062                                                    texImage->Width);
2063      }
2064      else {
2065         dstRowStride = texImage->Width * texImage->TexFormat->TexelBytes;
2066      }
2067      ASSERT(texImage->TexFormat->StoreImage);
2068      success = texImage->TexFormat->StoreImage(ctx, 2, texImage->Format,
2069                                                texImage->TexFormat,
2070                                                texImage->Data,
2071                                                xoffset, yoffset, 0,
2072                                                dstRowStride, dstImageStride,
2073                                                width, height, 1,
2074                                                format, type, pixels, packing);
2075      if (!success) {
2076         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
2077         return;
2078      }
2079   }
2080
2081   /* GL_SGIS_generate_mipmap */
2082   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2083      _mesa_generate_mipmap(ctx, target,
2084                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2085                            texObj);
2086   }
2087}
2088
2089
2090/*
2091 * This is the software fallback for Driver.TexSubImage3D().
2092 * and Driver.CopyTexSubImage3D().
2093 */
2094void
2095_mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
2096                          GLint xoffset, GLint yoffset, GLint zoffset,
2097                          GLint width, GLint height, GLint depth,
2098                          GLenum format, GLenum type, const void *pixels,
2099                          const struct gl_pixelstore_attrib *packing,
2100                          struct gl_texture_object *texObj,
2101                          struct gl_texture_image *texImage)
2102{
2103   pixels = validate_pbo_teximage(width, height, depth,
2104                                  format, type, pixels, packing);
2105   if (!pixels)
2106      return;
2107
2108   {
2109      GLint dstRowStride, dstImageStride;
2110      GLboolean success;
2111      if (texImage->IsCompressed) {
2112         dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
2113                                                    texImage->Width);
2114         dstImageStride = 0; /* XXX fix */
2115      }
2116      else {
2117         dstRowStride = texImage->Width * texImage->TexFormat->TexelBytes;
2118         dstImageStride = dstRowStride * texImage->Height;
2119      }
2120      ASSERT(texImage->TexFormat->StoreImage);
2121      success = texImage->TexFormat->StoreImage(ctx, 3, texImage->Format,
2122                                                texImage->TexFormat,
2123                                                texImage->Data,
2124                                                xoffset, yoffset, zoffset,
2125                                                dstRowStride, dstImageStride,
2126                                                width, height, depth,
2127                                                format, type, pixels, packing);
2128      if (!success) {
2129         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage3D");
2130         return;
2131      }
2132   }
2133
2134   /* GL_SGIS_generate_mipmap */
2135   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2136      _mesa_generate_mipmap(ctx, target,
2137                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2138                            texObj);
2139   }
2140}
2141
2142
2143/*
2144 * Fallback for Driver.CompressedTexImage1D()
2145 */
2146void
2147_mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level,
2148                                  GLint internalFormat,
2149                                  GLint width, GLint border,
2150                                  GLsizei imageSize, const GLvoid *data,
2151                                  struct gl_texture_object *texObj,
2152                                  struct gl_texture_image *texImage)
2153{
2154   /* this space intentionally left blank */
2155}
2156
2157
2158
2159/*
2160 * Fallback for Driver.CompressedTexImage2D()
2161 */
2162void
2163_mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level,
2164                                  GLint internalFormat,
2165                                  GLint width, GLint height, GLint border,
2166                                  GLsizei imageSize, const GLvoid *data,
2167                                  struct gl_texture_object *texObj,
2168                                  struct gl_texture_image *texImage)
2169{
2170   /* This is pretty simple, basically just do a memcpy without worrying
2171    * about the usual image unpacking or image transfer operations.
2172    */
2173   ASSERT(texObj);
2174   ASSERT(texImage);
2175   ASSERT(texImage->Width > 0);
2176   ASSERT(texImage->Height > 0);
2177   ASSERT(texImage->Depth == 1);
2178   ASSERT(texImage->Data == NULL); /* was freed in glCompressedTexImage2DARB */
2179
2180   /* choose the texture format */
2181   assert(ctx->Driver.ChooseTextureFormat);
2182   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
2183                                          internalFormat, 0, 0);
2184   assert(texImage->TexFormat);
2185   texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
2186   texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
2187
2188   /* allocate storage */
2189   texImage->Data = MESA_PBUFFER_ALLOC(imageSize);
2190   if (!texImage->Data) {
2191      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2DARB");
2192      return;
2193   }
2194
2195   data = validate_pbo_compressed_teximage(imageSize, data, &ctx->Unpack);
2196   if (!data)
2197      return;
2198
2199   /* copy the data */
2200   ASSERT(texImage->CompressedSize == (GLuint) imageSize);
2201   MEMCPY(texImage->Data, data, imageSize);
2202
2203   /* GL_SGIS_generate_mipmap */
2204   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2205      _mesa_generate_mipmap(ctx, target,
2206                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2207                            texObj);
2208   }
2209}
2210
2211
2212
2213/*
2214 * Fallback for Driver.CompressedTexImage3D()
2215 */
2216void
2217_mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
2218                                  GLint internalFormat,
2219                                  GLint width, GLint height, GLint depth,
2220                                  GLint border,
2221                                  GLsizei imageSize, const GLvoid *data,
2222                                  struct gl_texture_object *texObj,
2223                                  struct gl_texture_image *texImage)
2224{
2225   /* this space intentionally left blank */
2226}
2227
2228
2229
2230/**
2231 * Fallback for Driver.CompressedTexSubImage1D()
2232 */
2233void
2234_mesa_store_compressed_texsubimage1d(GLcontext *ctx, GLenum target,
2235                                     GLint level,
2236                                     GLint xoffset, GLsizei width,
2237                                     GLenum format,
2238                                     GLsizei imageSize, const GLvoid *data,
2239                                     struct gl_texture_object *texObj,
2240                                     struct gl_texture_image *texImage)
2241{
2242   /* this space intentionally left blank */
2243}
2244
2245
2246/**
2247 * Fallback for Driver.CompressedTexSubImage2D()
2248 */
2249void
2250_mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target,
2251                                     GLint level,
2252                                     GLint xoffset, GLint yoffset,
2253                                     GLsizei width, GLsizei height,
2254                                     GLenum format,
2255                                     GLsizei imageSize, const GLvoid *data,
2256                                     struct gl_texture_object *texObj,
2257                                     struct gl_texture_image *texImage)
2258{
2259   GLint bytesPerRow, destRowStride, srcRowStride;
2260   GLint i, rows;
2261   GLubyte *dest;
2262   const GLubyte *src;
2263
2264   /* these should have been caught sooner */
2265   ASSERT((width & 3) == 0 || width == 2 || width == 1);
2266   ASSERT((height & 3) == 0 || height == 2 || height == 1);
2267   ASSERT((xoffset & 3) == 0);
2268   ASSERT((yoffset & 3) == 0);
2269
2270   data = validate_pbo_compressed_teximage(imageSize, data, &ctx->Unpack);
2271   if (!data)
2272      return;
2273
2274   srcRowStride = _mesa_compressed_row_stride(texImage->IntFormat, width);
2275   src = (const GLubyte *) data;
2276
2277   destRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
2278                                               texImage->Width);
2279   dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
2280                                         texImage->IntFormat,
2281                                         texImage->Width,
2282                              (GLubyte*) texImage->Data);
2283
2284   bytesPerRow = srcRowStride;
2285   rows = height / 4;
2286
2287   for (i = 0; i < rows; i++) {
2288      MEMCPY(dest, src, bytesPerRow);
2289      dest += destRowStride;
2290      src += srcRowStride;
2291   }
2292
2293   /* GL_SGIS_generate_mipmap */
2294   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2295      _mesa_generate_mipmap(ctx, target,
2296                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2297                            texObj);
2298   }
2299}
2300
2301
2302/**
2303 * Fallback for Driver.CompressedTexSubImage3D()
2304 */
2305void
2306_mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target,
2307                                GLint level,
2308                                GLint xoffset, GLint yoffset, GLint zoffset,
2309                                GLsizei width, GLsizei height, GLsizei depth,
2310                                GLenum format,
2311                                GLsizei imageSize, const GLvoid *data,
2312                                struct gl_texture_object *texObj,
2313                                struct gl_texture_image *texImage)
2314{
2315   /* this space intentionally left blank */
2316}
2317
2318
2319/*
2320 * Average together two rows of a source image to produce a single new
2321 * row in the dest image.  It's legal for the two source rows to point
2322 * to the same data.  The source width must be equal to either the
2323 * dest width or two times the dest width.
2324 */
2325static void
2326do_row(const struct gl_texture_format *format, GLint srcWidth,
2327       const GLvoid *srcRowA, const GLvoid *srcRowB,
2328       GLint dstWidth, GLvoid *dstRow)
2329{
2330   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
2331   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
2332
2333   /* This assertion is no longer valid with non-power-of-2 textures
2334   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
2335   */
2336
2337   switch (format->MesaFormat) {
2338   case MESA_FORMAT_RGBA:
2339      {
2340         GLuint i, j, k;
2341         const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
2342         const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
2343         GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
2344         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2345              i++, j += colStride, k += colStride) {
2346            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2347                         rowB[j][0] + rowB[k][0]) / 4;
2348            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2349                         rowB[j][1] + rowB[k][1]) / 4;
2350            dst[i][2] = (rowA[j][2] + rowA[k][2] +
2351                         rowB[j][2] + rowB[k][2]) / 4;
2352            dst[i][3] = (rowA[j][3] + rowA[k][3] +
2353                         rowB[j][3] + rowB[k][3]) / 4;
2354         }
2355      }
2356      return;
2357   case MESA_FORMAT_RGB:
2358      {
2359         GLuint i, j, k;
2360         const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
2361         const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
2362         GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
2363         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2364              i++, j += colStride, k += colStride) {
2365            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2366                         rowB[j][0] + rowB[k][0]) / 4;
2367            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2368                         rowB[j][1] + rowB[k][1]) / 4;
2369            dst[i][2] = (rowA[j][2] + rowA[k][2] +
2370                         rowB[j][2] + rowB[k][2]) / 4;
2371         }
2372      }
2373      return;
2374   case MESA_FORMAT_ALPHA:
2375   case MESA_FORMAT_LUMINANCE:
2376   case MESA_FORMAT_INTENSITY:
2377      {
2378         GLuint i, j, k;
2379         const GLchan *rowA = (const GLchan *) srcRowA;
2380         const GLchan *rowB = (const GLchan *) srcRowB;
2381         GLchan *dst = (GLchan *) dstRow;
2382         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2383              i++, j += colStride, k += colStride) {
2384            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
2385         }
2386      }
2387      return;
2388   case MESA_FORMAT_LUMINANCE_ALPHA:
2389      {
2390         GLuint i, j, k;
2391         const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
2392         const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
2393         GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
2394         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2395              i++, j += colStride, k += colStride) {
2396            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2397                         rowB[j][0] + rowB[k][0]) / 4;
2398            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2399                         rowB[j][1] + rowB[k][1]) / 4;
2400         }
2401      }
2402      return;
2403   case MESA_FORMAT_DEPTH_COMPONENT_FLOAT32:
2404      {
2405         GLuint i, j, k;
2406         const GLfloat *rowA = (const GLfloat *) srcRowA;
2407         const GLfloat *rowB = (const GLfloat *) srcRowB;
2408         GLfloat *dst = (GLfloat *) dstRow;
2409         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2410              i++, j += colStride, k += colStride) {
2411            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
2412         }
2413      }
2414      return;
2415   case MESA_FORMAT_DEPTH_COMPONENT16:
2416      {
2417         GLuint i, j, k;
2418         const GLushort *rowA = (const GLushort *) srcRowA;
2419         const GLushort *rowB = (const GLushort *) srcRowB;
2420         GLushort *dst = (GLushort *) dstRow;
2421         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2422              i++, j += colStride, k += colStride) {
2423            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
2424         }
2425      }
2426      return;
2427   /* Begin hardware formats */
2428   case MESA_FORMAT_RGBA8888:
2429   case MESA_FORMAT_RGBA8888_REV:
2430   case MESA_FORMAT_ARGB8888:
2431   case MESA_FORMAT_ARGB8888_REV:
2432      {
2433         GLuint i, j, k;
2434         const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
2435         const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
2436         GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
2437         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2438              i++, j += colStride, k += colStride) {
2439            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2440                         rowB[j][0] + rowB[k][0]) / 4;
2441            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2442                         rowB[j][1] + rowB[k][1]) / 4;
2443            dst[i][2] = (rowA[j][2] + rowA[k][2] +
2444                         rowB[j][2] + rowB[k][2]) / 4;
2445            dst[i][3] = (rowA[j][3] + rowA[k][3] +
2446                         rowB[j][3] + rowB[k][3]) / 4;
2447         }
2448      }
2449      return;
2450   case MESA_FORMAT_RGB888:
2451   case MESA_FORMAT_BGR888:
2452      {
2453         GLuint i, j, k;
2454         const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
2455         const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
2456         GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
2457         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2458              i++, j += colStride, k += colStride) {
2459            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2460                         rowB[j][0] + rowB[k][0]) / 4;
2461            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2462                         rowB[j][1] + rowB[k][1]) / 4;
2463            dst[i][2] = (rowA[j][2] + rowA[k][2] +
2464                         rowB[j][2] + rowB[k][2]) / 4;
2465         }
2466      }
2467      return;
2468   case MESA_FORMAT_RGB565:
2469   case MESA_FORMAT_RGB565_REV:
2470      {
2471         GLuint i, j, k;
2472         const GLushort *rowA = (const GLushort *) srcRowA;
2473         const GLushort *rowB = (const GLushort *) srcRowB;
2474         GLushort *dst = (GLushort *) dstRow;
2475         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2476              i++, j += colStride, k += colStride) {
2477            const GLint rowAr0 = rowA[j] & 0x1f;
2478            const GLint rowAr1 = rowA[k] & 0x1f;
2479            const GLint rowBr0 = rowB[j] & 0x1f;
2480            const GLint rowBr1 = rowB[k] & 0x1f;
2481            const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
2482            const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
2483            const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
2484            const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
2485            const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
2486            const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
2487            const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
2488            const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
2489            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
2490            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
2491            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
2492            dst[i] = (blue << 11) | (green << 5) | red;
2493         }
2494      }
2495      return;
2496   case MESA_FORMAT_ARGB4444:
2497   case MESA_FORMAT_ARGB4444_REV:
2498      {
2499         GLuint i, j, k;
2500         const GLushort *rowA = (const GLushort *) srcRowA;
2501         const GLushort *rowB = (const GLushort *) srcRowB;
2502         GLushort *dst = (GLushort *) dstRow;
2503         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2504              i++, j += colStride, k += colStride) {
2505            const GLint rowAr0 = rowA[j] & 0xf;
2506            const GLint rowAr1 = rowA[k] & 0xf;
2507            const GLint rowBr0 = rowB[j] & 0xf;
2508            const GLint rowBr1 = rowB[k] & 0xf;
2509            const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
2510            const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
2511            const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
2512            const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
2513            const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
2514            const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
2515            const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
2516            const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
2517            const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
2518            const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
2519            const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
2520            const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
2521            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
2522            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
2523            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
2524            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
2525            dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
2526         }
2527      }
2528      return;
2529   case MESA_FORMAT_ARGB1555:
2530   case MESA_FORMAT_ARGB1555_REV: /* XXX broken? */
2531      {
2532         GLuint i, j, k;
2533         const GLushort *rowA = (const GLushort *) srcRowA;
2534         const GLushort *rowB = (const GLushort *) srcRowB;
2535         GLushort *dst = (GLushort *) dstRow;
2536         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2537              i++, j += colStride, k += colStride) {
2538            const GLint rowAr0 = rowA[j] & 0x1f;
2539            const GLint rowAr1 = rowA[k] & 0x1f;
2540            const GLint rowBr0 = rowB[j] & 0x1f;
2541            const GLint rowBr1 = rowB[k] & 0xf;
2542            const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
2543            const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
2544            const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
2545            const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
2546            const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
2547            const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
2548            const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
2549            const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
2550            const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
2551            const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
2552            const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
2553            const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
2554            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
2555            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
2556            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
2557            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
2558            dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
2559         }
2560      }
2561      return;
2562   case MESA_FORMAT_AL88:
2563   case MESA_FORMAT_AL88_REV:
2564      {
2565         GLuint i, j, k;
2566         const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
2567         const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
2568         GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
2569         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2570              i++, j += colStride, k += colStride) {
2571            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2572                         rowB[j][0] + rowB[k][0]) >> 2;
2573            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2574                         rowB[j][1] + rowB[k][1]) >> 2;
2575         }
2576      }
2577      return;
2578   case MESA_FORMAT_RGB332:
2579      {
2580         GLuint i, j, k;
2581         const GLubyte *rowA = (const GLubyte *) srcRowA;
2582         const GLubyte *rowB = (const GLubyte *) srcRowB;
2583         GLubyte *dst = (GLubyte *) dstRow;
2584         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2585              i++, j += colStride, k += colStride) {
2586            const GLint rowAr0 = rowA[j] & 0x3;
2587            const GLint rowAr1 = rowA[k] & 0x3;
2588            const GLint rowBr0 = rowB[j] & 0x3;
2589            const GLint rowBr1 = rowB[k] & 0x3;
2590            const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
2591            const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
2592            const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
2593            const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
2594            const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
2595            const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
2596            const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
2597            const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
2598            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
2599            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
2600            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
2601            dst[i] = (blue << 5) | (green << 2) | red;
2602         }
2603      }
2604      return;
2605   case MESA_FORMAT_A8:
2606   case MESA_FORMAT_L8:
2607   case MESA_FORMAT_I8:
2608   case MESA_FORMAT_CI8:
2609      {
2610         GLuint i, j, k;
2611         const GLubyte *rowA = (const GLubyte *) srcRowA;
2612         const GLubyte *rowB = (const GLubyte *) srcRowB;
2613         GLubyte *dst = (GLubyte *) dstRow;
2614         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2615              i++, j += colStride, k += colStride) {
2616            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
2617         }
2618      }
2619      return;
2620   case MESA_FORMAT_RGBA_FLOAT32:
2621      {
2622         GLuint i, j, k;
2623         const GLfloat (*rowA)[4] = (const GLfloat (*)[4]) srcRowA;
2624         const GLfloat (*rowB)[4] = (const GLfloat (*)[4]) srcRowB;
2625         GLfloat (*dst)[4] = (GLfloat (*)[4]) dstRow;
2626         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2627              i++, j += colStride, k += colStride) {
2628            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2629                         rowB[j][0] + rowB[k][0]) * 0.25F;
2630            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2631                         rowB[j][1] + rowB[k][1]) * 0.25F;
2632            dst[i][2] = (rowA[j][2] + rowA[k][2] +
2633                         rowB[j][2] + rowB[k][2]) * 0.25F;
2634            dst[i][3] = (rowA[j][3] + rowA[k][3] +
2635                         rowB[j][3] + rowB[k][3]) * 0.25F;
2636         }
2637      }
2638      return;
2639   case MESA_FORMAT_RGBA_FLOAT16:
2640      {
2641         GLuint i, j, k, comp;
2642         const GLhalfARB (*rowA)[4] = (const GLhalfARB (*)[4]) srcRowA;
2643         const GLhalfARB (*rowB)[4] = (const GLhalfARB (*)[4]) srcRowB;
2644         GLhalfARB (*dst)[4] = (GLhalfARB (*)[4]) dstRow;
2645         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2646              i++, j += colStride, k += colStride) {
2647            for (comp = 0; comp < 4; comp++) {
2648               GLfloat aj, ak, bj, bk;
2649               aj = _mesa_half_to_float(rowA[j][comp]);
2650               ak = _mesa_half_to_float(rowA[k][comp]);
2651               bj = _mesa_half_to_float(rowB[j][comp]);
2652               bk = _mesa_half_to_float(rowB[k][comp]);
2653               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
2654            }
2655         }
2656      }
2657      return;
2658   case MESA_FORMAT_RGB_FLOAT32:
2659      {
2660         GLuint i, j, k;
2661         const GLfloat (*rowA)[3] = (const GLfloat (*)[3]) srcRowA;
2662         const GLfloat (*rowB)[3] = (const GLfloat (*)[3]) srcRowB;
2663         GLfloat (*dst)[3] = (GLfloat (*)[3]) dstRow;
2664         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2665              i++, j += colStride, k += colStride) {
2666            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2667                         rowB[j][0] + rowB[k][0]) * 0.25F;
2668            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2669                         rowB[j][1] + rowB[k][1]) * 0.25F;
2670            dst[i][2] = (rowA[j][2] + rowA[k][2] +
2671                         rowB[j][2] + rowB[k][2]) * 0.25F;
2672         }
2673      }
2674      return;
2675   case MESA_FORMAT_RGB_FLOAT16:
2676      {
2677         GLuint i, j, k, comp;
2678         const GLhalfARB (*rowA)[3] = (const GLhalfARB (*)[3]) srcRowA;
2679         const GLhalfARB (*rowB)[3] = (const GLhalfARB (*)[3]) srcRowB;
2680         GLhalfARB (*dst)[3] = (GLhalfARB (*)[3]) dstRow;
2681         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2682              i++, j += colStride, k += colStride) {
2683            for (comp = 0; comp < 3; comp++) {
2684               GLfloat aj, ak, bj, bk;
2685               aj = _mesa_half_to_float(rowA[j][comp]);
2686               ak = _mesa_half_to_float(rowA[k][comp]);
2687               bj = _mesa_half_to_float(rowB[j][comp]);
2688               bk = _mesa_half_to_float(rowB[k][comp]);
2689               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
2690            }
2691         }
2692      }
2693      return;
2694   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32:
2695      {
2696         GLuint i, j, k;
2697         const GLfloat (*rowA)[2] = (const GLfloat (*)[2]) srcRowA;
2698         const GLfloat (*rowB)[2] = (const GLfloat (*)[2]) srcRowB;
2699         GLfloat (*dst)[2] = (GLfloat (*)[2]) dstRow;
2700         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2701              i++, j += colStride, k += colStride) {
2702            dst[i][0] = (rowA[j][0] + rowA[k][0] +
2703                         rowB[j][0] + rowB[k][0]) * 0.25F;
2704            dst[i][1] = (rowA[j][1] + rowA[k][1] +
2705                         rowB[j][1] + rowB[k][1]) * 0.25F;
2706         }
2707      }
2708      return;
2709   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16:
2710      {
2711         GLuint i, j, k, comp;
2712         const GLhalfARB (*rowA)[2] = (const GLhalfARB (*)[2]) srcRowA;
2713         const GLhalfARB (*rowB)[2] = (const GLhalfARB (*)[2]) srcRowB;
2714         GLhalfARB (*dst)[2] = (GLhalfARB (*)[2]) dstRow;
2715         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2716              i++, j += colStride, k += colStride) {
2717            for (comp = 0; comp < 2; comp++) {
2718               GLfloat aj, ak, bj, bk;
2719               aj = _mesa_half_to_float(rowA[j][comp]);
2720               ak = _mesa_half_to_float(rowA[k][comp]);
2721               bj = _mesa_half_to_float(rowB[j][comp]);
2722               bk = _mesa_half_to_float(rowB[k][comp]);
2723               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
2724            }
2725         }
2726      }
2727      return;
2728   case MESA_FORMAT_ALPHA_FLOAT32:
2729   case MESA_FORMAT_LUMINANCE_FLOAT32:
2730   case MESA_FORMAT_INTENSITY_FLOAT32:
2731      {
2732         GLuint i, j, k;
2733         const GLfloat *rowA = (const GLfloat *) srcRowA;
2734         const GLfloat *rowB = (const GLfloat *) srcRowB;
2735         GLfloat *dst = (GLfloat *) dstRow;
2736         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2737              i++, j += colStride, k += colStride) {
2738            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
2739         }
2740      }
2741      return;
2742   case MESA_FORMAT_ALPHA_FLOAT16:
2743   case MESA_FORMAT_LUMINANCE_FLOAT16:
2744   case MESA_FORMAT_INTENSITY_FLOAT16:
2745      {
2746         GLuint i, j, k;
2747         const GLhalfARB *rowA = (const GLhalfARB *) srcRowA;
2748         const GLhalfARB *rowB = (const GLhalfARB *) srcRowB;
2749         GLhalfARB *dst = (GLhalfARB *) dstRow;
2750         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
2751              i++, j += colStride, k += colStride) {
2752            GLfloat aj, ak, bj, bk;
2753            aj = _mesa_half_to_float(rowA[j]);
2754            ak = _mesa_half_to_float(rowA[k]);
2755            bj = _mesa_half_to_float(rowB[j]);
2756            bk = _mesa_half_to_float(rowB[k]);
2757            dst[i] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
2758         }
2759      }
2760      return;
2761
2762   default:
2763      _mesa_problem(NULL, "bad format in do_row()");
2764   }
2765}
2766
2767
2768/*
2769 * These functions generate a 1/2-size mipmap image from a source image.
2770 * Texture borders are handled by copying or averaging the source image's
2771 * border texels, depending on the scale-down factor.
2772 */
2773
2774static void
2775make_1d_mipmap(const struct gl_texture_format *format, GLint border,
2776               GLint srcWidth, const GLubyte *srcPtr,
2777               GLint dstWidth, GLubyte *dstPtr)
2778{
2779   const GLint bpt = format->TexelBytes;
2780   const GLubyte *src;
2781   GLubyte *dst;
2782
2783   /* skip the border pixel, if any */
2784   src = srcPtr + border * bpt;
2785   dst = dstPtr + border * bpt;
2786
2787   /* we just duplicate the input row, kind of hack, saves code */
2788   do_row(format, srcWidth - 2 * border, src, src,
2789          dstWidth - 2 * border, dst);
2790
2791   if (border) {
2792      /* copy left-most pixel from source */
2793      MEMCPY(dstPtr, srcPtr, bpt);
2794      /* copy right-most pixel from source */
2795      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
2796             srcPtr + (srcWidth - 1) * bpt,
2797             bpt);
2798   }
2799}
2800
2801
2802static void
2803make_2d_mipmap(const struct gl_texture_format *format, GLint border,
2804               GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
2805               GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
2806{
2807   const GLint bpt = format->TexelBytes;
2808   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
2809   const GLint dstWidthNB = dstWidth - 2 * border;
2810   const GLint dstHeightNB = dstHeight - 2 * border;
2811   const GLint srcRowStride = bpt * srcWidth;
2812   const GLint dstRowStride = bpt * dstWidth;
2813   const GLubyte *srcA, *srcB;
2814   GLubyte *dst;
2815   GLint row;
2816
2817   /* Compute src and dst pointers, skipping any border */
2818   srcA = srcPtr + border * ((srcWidth + 1) * bpt);
2819   if (srcHeight > 1)
2820      srcB = srcA + srcRowStride;
2821   else
2822      srcB = srcA;
2823   dst = dstPtr + border * ((dstWidth + 1) * bpt);
2824
2825   for (row = 0; row < dstHeightNB; row++) {
2826      do_row(format, srcWidthNB, srcA, srcB,
2827             dstWidthNB, dst);
2828      srcA += 2 * srcRowStride;
2829      srcB += 2 * srcRowStride;
2830      dst += dstRowStride;
2831   }
2832
2833   /* This is ugly but probably won't be used much */
2834   if (border > 0) {
2835      /* fill in dest border */
2836      /* lower-left border pixel */
2837      MEMCPY(dstPtr, srcPtr, bpt);
2838      /* lower-right border pixel */
2839      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
2840             srcPtr + (srcWidth - 1) * bpt, bpt);
2841      /* upper-left border pixel */
2842      MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
2843             srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
2844      /* upper-right border pixel */
2845      MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
2846             srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
2847      /* lower border */
2848      do_row(format, srcWidthNB,
2849             srcPtr + bpt,
2850             srcPtr + bpt,
2851             dstWidthNB, dstPtr + bpt);
2852      /* upper border */
2853      do_row(format, srcWidthNB,
2854             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
2855             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
2856             dstWidthNB,
2857             dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
2858      /* left and right borders */
2859      if (srcHeight == dstHeight) {
2860         /* copy border pixel from src to dst */
2861         for (row = 1; row < srcHeight; row++) {
2862            MEMCPY(dstPtr + dstWidth * row * bpt,
2863                   srcPtr + srcWidth * row * bpt, bpt);
2864            MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
2865                   srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
2866         }
2867      }
2868      else {
2869         /* average two src pixels each dest pixel */
2870         for (row = 0; row < dstHeightNB; row += 2) {
2871            do_row(format, 1,
2872                   srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
2873                   srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
2874                   1, dstPtr + (dstWidth * row + 1) * bpt);
2875            do_row(format, 1,
2876                   srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
2877                   srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
2878                   1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
2879         }
2880      }
2881   }
2882}
2883
2884
2885static void
2886make_3d_mipmap(const struct gl_texture_format *format, GLint border,
2887               GLint srcWidth, GLint srcHeight, GLint srcDepth,
2888               const GLubyte *srcPtr,
2889               GLint dstWidth, GLint dstHeight, GLint dstDepth,
2890               GLubyte *dstPtr)
2891{
2892   const GLint bpt = format->TexelBytes;
2893   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
2894   const GLint srcDepthNB = srcDepth - 2 * border;
2895   const GLint dstWidthNB = dstWidth - 2 * border;
2896   const GLint dstHeightNB = dstHeight - 2 * border;
2897   const GLint dstDepthNB = dstDepth - 2 * border;
2898   GLvoid *tmpRowA, *tmpRowB;
2899   GLint img, row;
2900   GLint bytesPerSrcImage, bytesPerDstImage;
2901   GLint bytesPerSrcRow, bytesPerDstRow;
2902   GLint srcImageOffset, srcRowOffset;
2903
2904   (void) srcDepthNB; /* silence warnings */
2905
2906   /* Need two temporary row buffers */
2907   tmpRowA = MALLOC(srcWidth * bpt);
2908   if (!tmpRowA)
2909      return;
2910   tmpRowB = MALLOC(srcWidth * bpt);
2911   if (!tmpRowB) {
2912      FREE(tmpRowA);
2913      return;
2914   }
2915
2916   bytesPerSrcImage = srcWidth * srcHeight * bpt;
2917   bytesPerDstImage = dstWidth * dstHeight * bpt;
2918
2919   bytesPerSrcRow = srcWidth * bpt;
2920   bytesPerDstRow = dstWidth * bpt;
2921
2922   /* Offset between adjacent src images to be averaged together */
2923   srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
2924
2925   /* Offset between adjacent src rows to be averaged together */
2926   srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
2927
2928   /*
2929    * Need to average together up to 8 src pixels for each dest pixel.
2930    * Break that down into 3 operations:
2931    *   1. take two rows from source image and average them together.
2932    *   2. take two rows from next source image and average them together.
2933    *   3. take the two averaged rows and average them for the final dst row.
2934    */
2935
2936   /*
2937   _mesa_printf("mip3d %d x %d x %d  ->  %d x %d x %d\n",
2938          srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
2939   */
2940
2941   for (img = 0; img < dstDepthNB; img++) {
2942      /* first source image pointer, skipping border */
2943      const GLubyte *imgSrcA = srcPtr
2944         + (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
2945         + img * (bytesPerSrcImage + srcImageOffset);
2946      /* second source image pointer, skipping border */
2947      const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
2948      /* address of the dest image, skipping border */
2949      GLubyte *imgDst = dstPtr
2950         + (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
2951         + img * bytesPerDstImage;
2952
2953      /* setup the four source row pointers and the dest row pointer */
2954      const GLubyte *srcImgARowA = imgSrcA;
2955      const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
2956      const GLubyte *srcImgBRowA = imgSrcB;
2957      const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
2958      GLubyte *dstImgRow = imgDst;
2959
2960      for (row = 0; row < dstHeightNB; row++) {
2961         /* Average together two rows from first src image */
2962         do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
2963                srcWidthNB, tmpRowA);
2964         /* Average together two rows from second src image */
2965         do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
2966                srcWidthNB, tmpRowB);
2967         /* Average together the temp rows to make the final row */
2968         do_row(format, srcWidthNB, tmpRowA, tmpRowB,
2969                dstWidthNB, dstImgRow);
2970         /* advance to next rows */
2971         srcImgARowA += bytesPerSrcRow + srcRowOffset;
2972         srcImgARowB += bytesPerSrcRow + srcRowOffset;
2973         srcImgBRowA += bytesPerSrcRow + srcRowOffset;
2974         srcImgBRowB += bytesPerSrcRow + srcRowOffset;
2975         dstImgRow += bytesPerDstRow;
2976      }
2977   }
2978
2979   FREE(tmpRowA);
2980   FREE(tmpRowB);
2981
2982   /* Luckily we can leverage the make_2d_mipmap() function here! */
2983   if (border > 0) {
2984      /* do front border image */
2985      make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
2986                     dstWidth, dstHeight, dstPtr);
2987      /* do back border image */
2988      make_2d_mipmap(format, 1, srcWidth, srcHeight,
2989                     srcPtr + bytesPerSrcImage * (srcDepth - 1),
2990                     dstWidth, dstHeight,
2991                     dstPtr + bytesPerDstImage * (dstDepth - 1));
2992      /* do four remaining border edges that span the image slices */
2993      if (srcDepth == dstDepth) {
2994         /* just copy border pixels from src to dst */
2995         for (img = 0; img < dstDepthNB; img++) {
2996            const GLubyte *src;
2997            GLubyte *dst;
2998
2999            /* do border along [img][row=0][col=0] */
3000            src = srcPtr + (img + 1) * bytesPerSrcImage;
3001            dst = dstPtr + (img + 1) * bytesPerDstImage;
3002            MEMCPY(dst, src, bpt);
3003
3004            /* do border along [img][row=dstHeight-1][col=0] */
3005            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3006                         + (srcHeight - 1) * bytesPerSrcRow;
3007            dst = dstPtr + (img + 1) * bytesPerDstImage
3008                         + (dstHeight - 1) * bytesPerDstRow;
3009            MEMCPY(dst, src, bpt);
3010
3011            /* do border along [img][row=0][col=dstWidth-1] */
3012            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3013                         + (srcWidth - 1) * bpt;
3014            dst = dstPtr + (img + 1) * bytesPerDstImage
3015                         + (dstWidth - 1) * bpt;
3016            MEMCPY(dst, src, bpt);
3017
3018            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
3019            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3020                         + (bytesPerSrcImage - bpt);
3021            dst = dstPtr + (img + 1) * bytesPerDstImage
3022                         + (bytesPerDstImage - bpt);
3023            MEMCPY(dst, src, bpt);
3024         }
3025      }
3026      else {
3027         /* average border pixels from adjacent src image pairs */
3028         ASSERT(srcDepthNB == 2 * dstDepthNB);
3029         for (img = 0; img < dstDepthNB; img++) {
3030            const GLubyte *src;
3031            GLubyte *dst;
3032
3033            /* do border along [img][row=0][col=0] */
3034            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
3035            dst = dstPtr + (img + 1) * bytesPerDstImage;
3036            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3037
3038            /* do border along [img][row=dstHeight-1][col=0] */
3039            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3040                         + (srcHeight - 1) * bytesPerSrcRow;
3041            dst = dstPtr + (img + 1) * bytesPerDstImage
3042                         + (dstHeight - 1) * bytesPerDstRow;
3043            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3044
3045            /* do border along [img][row=0][col=dstWidth-1] */
3046            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3047                         + (srcWidth - 1) * bpt;
3048            dst = dstPtr + (img + 1) * bytesPerDstImage
3049                         + (dstWidth - 1) * bpt;
3050            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3051
3052            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
3053            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3054                         + (bytesPerSrcImage - bpt);
3055            dst = dstPtr + (img + 1) * bytesPerDstImage
3056                         + (bytesPerDstImage - bpt);
3057            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3058         }
3059      }
3060   }
3061}
3062
3063
3064/*
3065 * For GL_SGIX_generate_mipmap:
3066 * Generate a complete set of mipmaps from texObj's base-level image.
3067 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
3068 */
3069void
3070_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
3071                      const struct gl_texture_unit *texUnit,
3072                      struct gl_texture_object *texObj)
3073{
3074   const struct gl_texture_image *srcImage;
3075   const struct gl_texture_format *convertFormat;
3076   const GLubyte *srcData = NULL;
3077   GLubyte *dstData = NULL;
3078   GLint level, maxLevels;
3079
3080   ASSERT(texObj);
3081   srcImage = texObj->Image[0][texObj->BaseLevel];
3082   ASSERT(srcImage);
3083
3084   maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
3085   ASSERT(maxLevels > 0);  /* bad target */
3086
3087   /* Find convertFormat - the format that do_row() will process */
3088   if (srcImage->IsCompressed) {
3089      /* setup for compressed textures */
3090      GLuint row;
3091      GLint  components, size;
3092      GLchan *dst;
3093
3094      assert(texObj->Target == GL_TEXTURE_2D);
3095
3096      if (srcImage->Format == GL_RGB) {
3097         convertFormat = &_mesa_texformat_rgb;
3098         components = 3;
3099      }
3100      else if (srcImage->Format == GL_RGBA) {
3101         convertFormat = &_mesa_texformat_rgba;
3102         components = 4;
3103      }
3104      else {
3105         _mesa_problem(ctx, "bad srcImage->Format in _mesa_generate_mipmaps");
3106         return;
3107      }
3108
3109      /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
3110      size = _mesa_bytes_per_pixel(srcImage->Format, CHAN_TYPE)
3111         * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
3112      /* 20 extra bytes, just be safe when calling last FetchTexel */
3113      srcData = (GLubyte *) MALLOC(size);
3114      if (!srcData) {
3115         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
3116         return;
3117      }
3118      dstData = (GLubyte *) MALLOC(size / 2);  /* 1/4 would probably be OK */
3119      if (!dstData) {
3120         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
3121         FREE((void *) srcData);
3122         return;
3123      }
3124
3125      /* decompress base image here */
3126      dst = (GLchan *) srcData;
3127      for (row = 0; row < srcImage->Height; row++) {
3128         GLuint col;
3129         for (col = 0; col < srcImage->Width; col++) {
3130            srcImage->FetchTexelc(srcImage, col, row, 0, dst);
3131            dst += components;
3132         }
3133      }
3134   }
3135   else {
3136      /* uncompressed */
3137      convertFormat = srcImage->TexFormat;
3138   }
3139
3140   for (level = texObj->BaseLevel; level < texObj->MaxLevel
3141           && level < maxLevels - 1; level++) {
3142      /* generate image[level+1] from image[level] */
3143      const struct gl_texture_image *srcImage;
3144      struct gl_texture_image *dstImage;
3145      GLint srcWidth, srcHeight, srcDepth;
3146      GLint dstWidth, dstHeight, dstDepth;
3147      GLint border, bytesPerTexel;
3148
3149      /* get src image parameters */
3150      srcImage = _mesa_select_tex_image(ctx, texUnit, target, level);
3151      ASSERT(srcImage);
3152      srcWidth = srcImage->Width;
3153      srcHeight = srcImage->Height;
3154      srcDepth = srcImage->Depth;
3155      border = srcImage->Border;
3156
3157      /* compute next (level+1) image size */
3158      if (srcWidth - 2 * border > 1) {
3159         dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
3160      }
3161      else {
3162         dstWidth = srcWidth; /* can't go smaller */
3163      }
3164      if (srcHeight - 2 * border > 1) {
3165         dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
3166      }
3167      else {
3168         dstHeight = srcHeight; /* can't go smaller */
3169      }
3170      if (srcDepth - 2 * border > 1) {
3171         dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
3172      }
3173      else {
3174         dstDepth = srcDepth; /* can't go smaller */
3175      }
3176
3177      if (dstWidth == srcWidth &&
3178          dstHeight == srcHeight &&
3179          dstDepth == srcDepth) {
3180         /* all done */
3181         if (srcImage->IsCompressed) {
3182            FREE((void *) srcData);
3183            FREE(dstData);
3184         }
3185         return;
3186      }
3187
3188      /* get dest gl_texture_image */
3189      dstImage = _mesa_get_tex_image(ctx, texUnit, target, level + 1);
3190      if (!dstImage) {
3191         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
3192         return;
3193      }
3194
3195      /* Free old image data */
3196      if (dstImage->Data)
3197         MESA_PBUFFER_FREE(dstImage->Data);
3198
3199      /* initialize new image */
3200      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
3201                                 dstDepth, border, srcImage->IntFormat);
3202      dstImage->DriverData = NULL;
3203      dstImage->TexFormat = srcImage->TexFormat;
3204      dstImage->FetchTexelc = srcImage->FetchTexelc;
3205      dstImage->FetchTexelf = srcImage->FetchTexelf;
3206      ASSERT(dstImage->TexFormat);
3207      ASSERT(dstImage->FetchTexelc);
3208      ASSERT(dstImage->FetchTexelf);
3209
3210      /* Alloc new teximage data buffer.
3211       * Setup src and dest data pointers.
3212       */
3213      if (dstImage->IsCompressed) {
3214         ASSERT(dstImage->CompressedSize > 0); /* set by init_teximage_fields*/
3215         dstImage->Data = MESA_PBUFFER_ALLOC(dstImage->CompressedSize);
3216         if (!dstImage->Data) {
3217            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
3218            return;
3219         }
3220         /* srcData and dstData are already set */
3221         ASSERT(srcData);
3222         ASSERT(dstData);
3223      }
3224      else {
3225         bytesPerTexel = srcImage->TexFormat->TexelBytes;
3226         ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
3227         dstImage->Data = MESA_PBUFFER_ALLOC(dstWidth * dstHeight * dstDepth
3228                                             * bytesPerTexel);
3229         if (!dstImage->Data) {
3230            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
3231            return;
3232         }
3233         srcData = (const GLubyte *) srcImage->Data;
3234         dstData = (GLubyte *) dstImage->Data;
3235      }
3236
3237      /*
3238       * We use simple 2x2 averaging to compute the next mipmap level.
3239       */
3240      switch (target) {
3241         case GL_TEXTURE_1D:
3242            make_1d_mipmap(convertFormat, border,
3243                           srcWidth, srcData,
3244                           dstWidth, dstData);
3245            break;
3246         case GL_TEXTURE_2D:
3247         case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
3248         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
3249         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
3250         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
3251         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
3252         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
3253            make_2d_mipmap(convertFormat, border,
3254                           srcWidth, srcHeight, srcData,
3255                           dstWidth, dstHeight, dstData);
3256            break;
3257         case GL_TEXTURE_3D:
3258            make_3d_mipmap(convertFormat, border,
3259                           srcWidth, srcHeight, srcDepth, srcData,
3260                           dstWidth, dstHeight, dstDepth, dstData);
3261            break;
3262         case GL_TEXTURE_RECTANGLE_NV:
3263            /* no mipmaps, do nothing */
3264            break;
3265         default:
3266            _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
3267            return;
3268      }
3269
3270      if (dstImage->IsCompressed) {
3271         GLubyte *temp;
3272         /* compress image from dstData into dstImage->Data */
3273         const GLenum srcFormat = convertFormat->BaseFormat;
3274         GLint dstRowStride = _mesa_compressed_row_stride(srcImage->IntFormat,
3275                                                          dstWidth);
3276         ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
3277         dstImage->TexFormat->StoreImage(ctx, 2, dstImage->Format,
3278                                         dstImage->TexFormat,
3279                                         dstImage->Data,
3280                                         0, 0, 0, /* dstX/Y/Zoffset */
3281                                         dstRowStride, 0, /* strides */
3282                                         dstWidth, dstHeight, 1, /* size */
3283                                         srcFormat, CHAN_TYPE,
3284                                         dstData, /* src data, actually */
3285                                         &ctx->DefaultPacking);
3286         /* swap src and dest pointers */
3287         temp = (GLubyte *) srcData;
3288         srcData = dstData;
3289         dstData = temp;
3290      }
3291
3292   } /* loop over mipmap levels */
3293}
3294
3295
3296/**
3297 * Helper function for drivers which need to rescale texture images to
3298 * certain aspect ratios.
3299 * Nearest filtering only (for broken hardware that can't support
3300 * all aspect ratios).  This can be made a lot faster, but I don't
3301 * really care enough...
3302 */
3303void _mesa_rescale_teximage2d( GLuint bytesPerPixel, GLuint dstRowStride,
3304			       GLint srcWidth, GLint srcHeight,
3305			       GLint dstWidth, GLint dstHeight,
3306			       const GLvoid *srcImage, GLvoid *dstImage )
3307{
3308   GLint row, col;
3309
3310#define INNER_LOOP( TYPE, HOP, WOP )					\
3311   for ( row = 0 ; row < dstHeight ; row++ ) {				\
3312      GLint srcRow = row HOP hScale;					\
3313      for ( col = 0 ; col < dstWidth ; col++ ) {			\
3314	 GLint srcCol = col WOP wScale;					\
3315	 dst[col] = src[srcRow * srcWidth + srcCol];			\
3316      }									\
3317      dst = (TYPE *) ((GLubyte *) dst + dstRowStride);			\
3318   }									\
3319
3320#define RESCALE_IMAGE( TYPE )						\
3321do {									\
3322   const TYPE *src = (const TYPE *)srcImage;				\
3323   TYPE *dst = (TYPE *)dstImage;					\
3324									\
3325   if ( srcHeight <= dstHeight ) {					\
3326      const GLint hScale = dstHeight / srcHeight;			\
3327      if ( srcWidth <= dstWidth ) {					\
3328	 const GLint wScale = dstWidth / srcWidth;			\
3329	 INNER_LOOP( TYPE, /, / );					\
3330      }									\
3331      else {								\
3332	 const GLint wScale = srcWidth / dstWidth;			\
3333	 INNER_LOOP( TYPE, /, * );					\
3334      }									\
3335   }									\
3336   else {								\
3337      const GLint hScale = srcHeight / dstHeight;			\
3338      if ( srcWidth <= dstWidth ) {					\
3339	 const GLint wScale = dstWidth / srcWidth;			\
3340	 INNER_LOOP( TYPE, *, / );					\
3341      }									\
3342      else {								\
3343	 const GLint wScale = srcWidth / dstWidth;			\
3344	 INNER_LOOP( TYPE, *, * );					\
3345      }									\
3346   }									\
3347} while (0)
3348
3349   switch ( bytesPerPixel ) {
3350   case 4:
3351      RESCALE_IMAGE( GLuint );
3352      break;
3353
3354   case 2:
3355      RESCALE_IMAGE( GLushort );
3356      break;
3357
3358   case 1:
3359      RESCALE_IMAGE( GLubyte );
3360      break;
3361   default:
3362      _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
3363   }
3364}
3365
3366
3367/**
3368 * Upscale an image by replication, not (typical) stretching.
3369 * We use this when the image width or height is less than a
3370 * certain size (4, 8) and we need to upscale an image.
3371 */
3372void
3373_mesa_upscale_teximage2d (GLsizei inWidth, GLsizei inHeight,
3374                          GLsizei outWidth, GLsizei outHeight,
3375                          GLint comps, const GLchan *src, GLint srcRowStride,
3376                          GLchan *dest )
3377{
3378   GLint i, j, k;
3379
3380   ASSERT(outWidth >= inWidth);
3381   ASSERT(outHeight >= inHeight);
3382   ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
3383#if 0
3384   ASSERT((outWidth & 3) == 0);
3385   ASSERT((outHeight & 3) == 0);
3386#endif
3387
3388   for (i = 0; i < outHeight; i++) {
3389      const GLint ii = i % inHeight;
3390      for (j = 0; j < outWidth; j++) {
3391         const GLint jj = j % inWidth;
3392         for (k = 0; k < comps; k++) {
3393            dest[(i * outWidth + j) * comps + k]
3394               = src[ii * srcRowStride + jj * comps + k];
3395         }
3396      }
3397   }
3398}
3399