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