texstore.c revision 2e2a9813355993ba79eeb8070391e45aabb84f94
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5.1
4 *
5 * Copyright (C) 1999-2006  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 = 4, ONE = 5;
69
70static GLboolean can_swizzle(GLenum logicalBaseFormat)
71{
72   switch (logicalBaseFormat) {
73   case GL_RGBA:
74   case GL_RGB:
75   case GL_LUMINANCE_ALPHA:
76   case GL_INTENSITY:
77   case GL_ALPHA:
78   case GL_LUMINANCE:
79      return GL_TRUE;
80   default:
81      return GL_FALSE;
82   }
83}
84
85
86/**
87 * When promoting texture formats (see below) we need to compute the
88 * mapping of dest components back to source components.
89 * This function does that.
90 * \param logicalBaseFormat  the logical format of the texture
91 * \param textureBaseFormat  the final texture format
92 * \return map[4]  the four mapping values
93 */
94static void
95compute_component_mapping(GLenum logicalBaseFormat, GLenum textureBaseFormat,
96                          GLubyte map[6])
97{
98   map[ZERO] = ZERO;
99   map[ONE] = ONE;
100
101   /* compute mapping from dest components back to src components */
102   switch (textureBaseFormat) {
103   case GL_RGB:
104   case GL_RGBA:
105      switch (logicalBaseFormat) {
106      case GL_LUMINANCE:
107         map[0] = map[1] = map[2] = 0;
108         if (textureBaseFormat == GL_RGBA)
109            map[3] = ONE;
110         break;
111      case GL_ALPHA:
112         ASSERT(textureBaseFormat == GL_RGBA);
113         map[0] = map[1] = map[2] = ZERO;
114         map[3] = 0;
115         break;
116      case GL_INTENSITY:
117         map[0] = map[1] = map[2] = 0;
118         if (textureBaseFormat == GL_RGBA)
119            map[3] = 0;
120         break;
121      case GL_LUMINANCE_ALPHA:
122         ASSERT(textureBaseFormat == GL_RGBA);
123         map[0] = map[1] = map[2] = 0;
124         map[3] = 1;
125         break;
126      case GL_RGB:
127         ASSERT(textureBaseFormat == GL_RGBA);
128         map[0] = 0;
129         map[1] = 1;
130         map[2] = 2;
131         map[3] = ONE;
132         break;
133      case GL_RGBA:
134         ASSERT(textureBaseFormat == GL_RGBA);
135         map[0] = 0;
136         map[1] = 1;
137         map[2] = 2;
138         map[3] = 3;
139         break;
140      default:
141         _mesa_problem(NULL, "Unexpected logicalBaseFormat");
142         map[0] = map[1] = map[2] = map[3] = 0;
143      }
144      break;
145   case GL_LUMINANCE_ALPHA:
146      switch (logicalBaseFormat) {
147      case GL_LUMINANCE:
148         map[0] = 0;
149         map[1] = ONE;
150         break;
151      case GL_ALPHA:
152         map[0] = ZERO;
153         map[1] = 0;
154         break;
155      case GL_INTENSITY:
156         map[0] = 0;
157         map[1] = 0;
158         break;
159      default:
160         _mesa_problem(NULL, "Unexpected logicalBaseFormat");
161         map[0] = map[1] = 0;
162      }
163      break;
164   default:
165      _mesa_problem(NULL, "Unexpected textureBaseFormat");
166      map[0] = map[1] = 0;
167      break;
168   }
169}
170
171
172/**
173 * Make a temporary (color) texture image with GLfloat components.
174 * Apply all needed pixel unpacking and pixel transfer operations.
175 * Note that there are both logicalBaseFormat and textureBaseFormat parameters.
176 * Suppose the user specifies GL_LUMINANCE as the internal texture format
177 * but the graphics hardware doesn't support luminance textures.  So, might
178 * use an RGB hardware format instead.
179 * If logicalBaseFormat != textureBaseFormat we have some extra work to do.
180 *
181 * \param ctx  the rendering context
182 * \param dims  image dimensions: 1, 2 or 3
183 * \param logicalBaseFormat  basic texture derived from the user's
184 *    internal texture format value
185 * \param textureBaseFormat  the actual basic format of the texture
186 * \param srcWidth  source image width
187 * \param srcHeight  source image height
188 * \param srcDepth  source image depth
189 * \param srcFormat  source image format
190 * \param srcType  source image type
191 * \param srcAddr  source image address
192 * \param srcPacking  source image pixel packing
193 * \return resulting image with format = textureBaseFormat and type = GLfloat.
194 */
195static GLfloat *
196make_temp_float_image(GLcontext *ctx, GLuint dims,
197                      GLenum logicalBaseFormat,
198                      GLenum textureBaseFormat,
199                      GLint srcWidth, GLint srcHeight, GLint srcDepth,
200                      GLenum srcFormat, GLenum srcType,
201                      const GLvoid *srcAddr,
202                      const struct gl_pixelstore_attrib *srcPacking)
203{
204   GLuint transferOps = ctx->_ImageTransferState;
205   GLfloat *tempImage;
206
207   ASSERT(dims >= 1 && dims <= 3);
208
209   ASSERT(logicalBaseFormat == GL_RGBA ||
210          logicalBaseFormat == GL_RGB ||
211          logicalBaseFormat == GL_LUMINANCE_ALPHA ||
212          logicalBaseFormat == GL_LUMINANCE ||
213          logicalBaseFormat == GL_ALPHA ||
214          logicalBaseFormat == GL_INTENSITY ||
215          logicalBaseFormat == GL_COLOR_INDEX ||
216          logicalBaseFormat == GL_DEPTH_COMPONENT);
217
218   ASSERT(textureBaseFormat == GL_RGBA ||
219          textureBaseFormat == GL_RGB ||
220          textureBaseFormat == GL_LUMINANCE_ALPHA ||
221          textureBaseFormat == GL_LUMINANCE ||
222          textureBaseFormat == GL_ALPHA ||
223          textureBaseFormat == GL_INTENSITY ||
224          textureBaseFormat == GL_COLOR_INDEX ||
225          textureBaseFormat == GL_DEPTH_COMPONENT);
226
227   /* conventional color image */
228
229   if ((dims == 1 && ctx->Pixel.Convolution1DEnabled) ||
230       (dims >= 2 && ctx->Pixel.Convolution2DEnabled) ||
231       (dims >= 2 && ctx->Pixel.Separable2DEnabled)) {
232      /* need image convolution */
233      const GLuint preConvTransferOps
234         = (transferOps & IMAGE_PRE_CONVOLUTION_BITS) | IMAGE_CLAMP_BIT;
235      const GLuint postConvTransferOps
236         = (transferOps & IMAGE_POST_CONVOLUTION_BITS) | IMAGE_CLAMP_BIT;
237      GLint img, row;
238      GLint convWidth, convHeight;
239      GLfloat *convImage;
240
241      /* pre-convolution image buffer (3D) */
242      tempImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth
243                                           * 4 * sizeof(GLfloat));
244      if (!tempImage)
245         return NULL;
246
247      /* post-convolution image buffer (2D) */
248      convImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight
249                                           * 4 * sizeof(GLfloat));
250      if (!convImage) {
251         _mesa_free(tempImage);
252         return NULL;
253      }
254
255      /* loop over 3D image slices */
256      for (img = 0; img < srcDepth; img++) {
257         GLfloat *dst = tempImage + img * (srcWidth * srcHeight * 4);
258
259         /* unpack and do transfer ops up to convolution */
260         for (row = 0; row < srcHeight; row++) {
261            const GLvoid *src = _mesa_image_address(dims, srcPacking,
262                                              srcAddr, srcWidth, srcHeight,
263                                              srcFormat, srcType, img, row, 0);
264            _mesa_unpack_color_span_float(ctx, srcWidth, GL_RGBA, dst,
265                                          srcFormat, srcType, src,
266                                          srcPacking,
267                                          preConvTransferOps);
268            dst += srcWidth * 4;
269         }
270
271         /* do convolution */
272         {
273            GLfloat *src = tempImage + img * (srcWidth * srcHeight * 4);
274            convWidth = srcWidth;
275            convHeight = srcHeight;
276            if (dims == 1) {
277               ASSERT(ctx->Pixel.Convolution1DEnabled);
278               _mesa_convolve_1d_image(ctx, &convWidth, src, convImage);
279            }
280            else {
281               if (ctx->Pixel.Convolution2DEnabled) {
282                  _mesa_convolve_2d_image(ctx, &convWidth, &convHeight,
283                                          src, convImage);
284               }
285               else {
286                  ASSERT(ctx->Pixel.Separable2DEnabled);
287                  _mesa_convolve_sep_image(ctx, &convWidth, &convHeight,
288                                           src, convImage);
289               }
290            }
291         }
292
293         /* do post-convolution transfer and pack into tempImage */
294         {
295            const GLint logComponents
296               = _mesa_components_in_format(logicalBaseFormat);
297            const GLfloat *src = convImage;
298            GLfloat *dst = tempImage + img * (convWidth * convHeight * 4);
299            for (row = 0; row < convHeight; row++) {
300               _mesa_pack_rgba_span_float(ctx, convWidth,
301                                          (const GLfloat (*)[4]) src,
302                                          logicalBaseFormat, GL_FLOAT,
303                                          dst, &ctx->DefaultPacking,
304                                          postConvTransferOps);
305               src += convWidth * 4;
306               dst += convWidth * logComponents;
307            }
308         }
309      } /* loop over 3D image slices */
310
311      _mesa_free(convImage);
312
313      /* might need these below */
314      srcWidth = convWidth;
315      srcHeight = convHeight;
316   }
317   else {
318      /* no convolution */
319      const GLint components = _mesa_components_in_format(logicalBaseFormat);
320      const GLint srcStride = _mesa_image_row_stride(srcPacking,
321                                                 srcWidth, srcFormat, srcType);
322      GLfloat *dst;
323      GLint img, row;
324
325      tempImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth
326                                           * components * sizeof(GLfloat));
327      if (!tempImage)
328         return NULL;
329
330      dst = tempImage;
331      for (img = 0; img < srcDepth; img++) {
332         const GLubyte *src
333            = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr,
334                                                    srcWidth, srcHeight,
335                                                    srcFormat, srcType,
336                                                    img, 0, 0);
337         for (row = 0; row < srcHeight; row++) {
338            _mesa_unpack_color_span_float(ctx, srcWidth, logicalBaseFormat,
339                                          dst, srcFormat, srcType, src,
340                                          srcPacking, transferOps);
341            dst += srcWidth * components;
342            src += srcStride;
343         }
344      }
345   }
346
347   if (logicalBaseFormat != textureBaseFormat) {
348      /* more work */
349      GLint texComponents = _mesa_components_in_format(textureBaseFormat);
350      GLint logComponents = _mesa_components_in_format(logicalBaseFormat);
351      GLfloat *newImage;
352      GLint i, n;
353      GLubyte map[6];
354
355      /* we only promote up to RGB, RGBA and LUMINANCE_ALPHA formats for now */
356      ASSERT(textureBaseFormat == GL_RGB || textureBaseFormat == GL_RGBA ||
357             textureBaseFormat == GL_LUMINANCE_ALPHA);
358
359      /* The actual texture format should have at least as many components
360       * as the logical texture format.
361       */
362      ASSERT(texComponents >= logComponents);
363
364      newImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth
365                                          * texComponents * sizeof(GLfloat));
366      if (!newImage) {
367         _mesa_free(tempImage);
368         return NULL;
369      }
370
371      compute_component_mapping(logicalBaseFormat, textureBaseFormat, map);
372
373      n = srcWidth * srcHeight * srcDepth;
374      for (i = 0; i < n; i++) {
375         GLint k;
376         for (k = 0; k < texComponents; k++) {
377            GLint j = map[k];
378            if (j == ZERO)
379               newImage[i * texComponents + k] = 0.0F;
380            else if (j == ONE)
381               newImage[i * texComponents + k] = 1.0F;
382            else
383               newImage[i * texComponents + k] = tempImage[i * logComponents + j];
384         }
385      }
386
387      _mesa_free(tempImage);
388      tempImage = newImage;
389   }
390
391   return tempImage;
392}
393
394
395/**
396 * Make a temporary (color) texture image with GLchan components.
397 * Apply all needed pixel unpacking and pixel transfer operations.
398 * Note that there are both logicalBaseFormat and textureBaseFormat parameters.
399 * Suppose the user specifies GL_LUMINANCE as the internal texture format
400 * but the graphics hardware doesn't support luminance textures.  So, might
401 * use an RGB hardware format instead.
402 * If logicalBaseFormat != textureBaseFormat we have some extra work to do.
403 *
404 * \param ctx  the rendering context
405 * \param dims  image dimensions: 1, 2 or 3
406 * \param logicalBaseFormat  basic texture derived from the user's
407 *    internal texture format value
408 * \param textureBaseFormat  the actual basic format of the texture
409 * \param srcWidth  source image width
410 * \param srcHeight  source image height
411 * \param srcDepth  source image depth
412 * \param srcFormat  source image format
413 * \param srcType  source image type
414 * \param srcAddr  source image address
415 * \param srcPacking  source image pixel packing
416 * \return resulting image with format = textureBaseFormat and type = GLchan.
417 */
418GLchan *
419_mesa_make_temp_chan_image(GLcontext *ctx, GLuint dims,
420                           GLenum logicalBaseFormat,
421                           GLenum textureBaseFormat,
422                           GLint srcWidth, GLint srcHeight, GLint srcDepth,
423                           GLenum srcFormat, GLenum srcType,
424                           const GLvoid *srcAddr,
425                           const struct gl_pixelstore_attrib *srcPacking)
426{
427   GLuint transferOps = ctx->_ImageTransferState;
428   const GLint components = _mesa_components_in_format(logicalBaseFormat);
429   GLboolean freeSrcImage = GL_FALSE;
430   GLint img, row;
431   GLchan *tempImage, *dst;
432
433   ASSERT(dims >= 1 && dims <= 3);
434
435   ASSERT(logicalBaseFormat == GL_RGBA ||
436          logicalBaseFormat == GL_RGB ||
437          logicalBaseFormat == GL_LUMINANCE_ALPHA ||
438          logicalBaseFormat == GL_LUMINANCE ||
439          logicalBaseFormat == GL_ALPHA ||
440          logicalBaseFormat == GL_INTENSITY);
441
442   ASSERT(textureBaseFormat == GL_RGBA ||
443          textureBaseFormat == GL_RGB ||
444          textureBaseFormat == GL_LUMINANCE_ALPHA ||
445          textureBaseFormat == GL_LUMINANCE ||
446          textureBaseFormat == GL_ALPHA ||
447          textureBaseFormat == GL_INTENSITY);
448
449   if ((dims == 1 && ctx->Pixel.Convolution1DEnabled) ||
450       (dims >= 2 && ctx->Pixel.Convolution2DEnabled) ||
451       (dims >= 2 && ctx->Pixel.Separable2DEnabled)) {
452      /* get convolved image */
453      GLfloat *convImage = make_temp_float_image(ctx, dims,
454                                                 logicalBaseFormat,
455                                                 logicalBaseFormat,
456                                                 srcWidth, srcHeight, srcDepth,
457                                                 srcFormat, srcType,
458                                                 srcAddr, srcPacking);
459      if (!convImage)
460         return NULL;
461      /* the convolved image is our new source image */
462      srcAddr = convImage;
463      srcFormat = logicalBaseFormat;
464      srcType = GL_FLOAT;
465      srcPacking = &ctx->DefaultPacking;
466      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
467      transferOps = 0;
468      freeSrcImage = GL_TRUE;
469   }
470
471   /* unpack and transfer the source image */
472   tempImage = (GLchan *) _mesa_malloc(srcWidth * srcHeight * srcDepth
473                                       * components * sizeof(GLchan));
474   if (!tempImage)
475      return NULL;
476
477   dst = tempImage;
478   for (img = 0; img < srcDepth; img++) {
479      const GLint srcStride = _mesa_image_row_stride(srcPacking,
480                                                     srcWidth, srcFormat,
481                                                     srcType);
482      const GLubyte *src
483         = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr,
484                                                 srcWidth, srcHeight,
485                                                 srcFormat, srcType,
486                                                 img, 0, 0);
487      for (row = 0; row < srcHeight; row++) {
488         _mesa_unpack_color_span_chan(ctx, srcWidth, logicalBaseFormat, dst,
489                                      srcFormat, srcType, src, srcPacking,
490                                      transferOps);
491         dst += srcWidth * components;
492         src += srcStride;
493      }
494   }
495
496   /* If we made a temporary image for convolution, free it here */
497   if (freeSrcImage) {
498      _mesa_free((void *) srcAddr);
499   }
500
501   if (logicalBaseFormat != textureBaseFormat) {
502      /* one more conversion step */
503      GLint texComponents = _mesa_components_in_format(textureBaseFormat);
504      GLint logComponents = _mesa_components_in_format(logicalBaseFormat);
505      GLchan *newImage;
506      GLint i, n;
507      GLubyte map[6];
508
509      /* we only promote up to RGB, RGBA and LUMINANCE_ALPHA formats for now */
510      ASSERT(textureBaseFormat == GL_RGB || textureBaseFormat == GL_RGBA ||
511             textureBaseFormat == GL_LUMINANCE_ALPHA);
512
513      /* The actual texture format should have at least as many components
514       * as the logical texture format.
515       */
516      ASSERT(texComponents >= logComponents);
517
518      newImage = (GLchan *) _mesa_malloc(srcWidth * srcHeight * srcDepth
519                                         * texComponents * sizeof(GLchan));
520      if (!newImage) {
521         _mesa_free(tempImage);
522         return NULL;
523      }
524
525      compute_component_mapping(logicalBaseFormat, textureBaseFormat, map);
526
527      n = srcWidth * srcHeight * srcDepth;
528      for (i = 0; i < n; i++) {
529         GLint k;
530         for (k = 0; k < texComponents; k++) {
531            GLint j = map[k];
532            if (j == ZERO)
533               newImage[i * texComponents + k] = 0;
534            else if (j == ONE)
535               newImage[i * texComponents + k] = CHAN_MAX;
536            else
537               newImage[i * texComponents + k] = tempImage[i * logComponents + j];
538         }
539      }
540
541      _mesa_free(tempImage);
542      tempImage = newImage;
543   }
544
545   return tempImage;
546}
547
548
549/**
550 * Copy GLubyte pixels from <src> to <dst> with swizzling.
551 * \param dst  destination pixels
552 * \param dstComponents  number of color components in destination pixels
553 * \param src  source pixels
554 * \param srcComponents  number of color components in source pixels
555 * \param map  the swizzle mapping
556 * \param count  number of pixels to copy/swizzle.
557 */
558static void
559swizzle_copy(GLubyte *dst, GLuint dstComponents, const GLubyte *src,
560             GLuint srcComponents, const GLubyte *map, GLuint count)
561{
562   GLubyte tmp[8];
563   GLuint i;
564
565   tmp[ZERO] = 0x0;
566   tmp[ONE] = 0xff;
567
568   switch (dstComponents) {
569   case 4:
570      for (i = 0; i < count; i++) {
571 	 COPY_4UBV(tmp, src);
572	 src += srcComponents;
573	 dst[0] = tmp[map[0]];
574	 dst[1] = tmp[map[1]];
575	 dst[2] = tmp[map[2]];
576	 dst[3] = tmp[map[3]];
577	 dst += 4;
578      }
579      break;
580   case 3:
581      for (i = 0; i < count; i++) {
582 	 COPY_4UBV(tmp, src);
583	 src += srcComponents;
584	 dst[0] = tmp[map[0]];
585	 dst[1] = tmp[map[1]];
586	 dst[2] = tmp[map[2]];
587	 dst += 3;
588      }
589      break;
590   case 2:
591      for (i = 0; i < count; i++) {
592 	 COPY_4UBV(tmp, src);
593	 src += srcComponents;
594	 dst[0] = tmp[map[0]];
595	 dst[1] = tmp[map[1]];
596	 dst += 2;
597      }
598      break;
599   }
600}
601
602
603/**
604 * Transfer a GLubyte texture image with component swizzling.
605 */
606static void
607_mesa_swizzle_ubyte_image(GLcontext *ctx,
608			  GLuint dimensions,
609			  GLenum srcFormat,
610			  const GLubyte *dstmap, GLint dstComponents,
611
612			  GLvoid *dstAddr,
613			  GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
614			  GLint dstRowStride,
615                          const GLuint *dstImageOffsets,
616
617			  GLint srcWidth, GLint srcHeight, GLint srcDepth,
618			  const GLvoid *srcAddr,
619			  const struct gl_pixelstore_attrib *srcPacking )
620{
621   GLint srcComponents = _mesa_components_in_format(srcFormat);
622   GLubyte srcmap[6], map[4];
623   GLint i;
624
625   const GLint srcRowStride =
626      _mesa_image_row_stride(srcPacking, srcWidth,
627                             srcFormat, GL_UNSIGNED_BYTE);
628   const GLint srcImageStride
629      = _mesa_image_image_stride(srcPacking, srcWidth, srcHeight, srcFormat,
630                                 GL_UNSIGNED_BYTE);
631   const GLubyte *srcImage
632      = (const GLubyte *) _mesa_image_address(dimensions, srcPacking, srcAddr,
633                                              srcWidth, srcHeight, srcFormat,
634                                              GL_UNSIGNED_BYTE, 0, 0, 0);
635
636   (void) ctx;
637
638   compute_component_mapping(srcFormat, GL_RGBA, srcmap);
639
640   for (i = 0; i < 4; i++)
641      map[i] = srcmap[dstmap[i]];
642
643   if (srcRowStride == srcWidth * srcComponents &&
644       dimensions < 3) {
645      /* 1 and 2D images only */
646      GLubyte *dstImage = (GLubyte *) dstAddr
647         + dstYoffset * dstRowStride
648         + dstXoffset * dstComponents;
649      swizzle_copy(dstImage, dstComponents, srcImage, srcComponents, map,
650		   srcWidth * srcHeight);
651   }
652   else {
653      GLint img, row;
654      for (img = 0; img < srcDepth; img++) {
655         const GLubyte *srcRow = srcImage;
656         GLubyte *dstRow = (GLubyte *) dstAddr
657            + dstImageOffsets[dstZoffset + img] * dstComponents
658            + dstYoffset * dstRowStride
659            + dstXoffset * dstComponents;
660         for (row = 0; row < srcHeight; row++) {
661	    swizzle_copy(dstRow, dstComponents, srcRow, srcComponents, map, srcWidth);
662            dstRow += dstRowStride;
663            srcRow += srcRowStride;
664         }
665         srcImage += srcImageStride;
666      }
667   }
668}
669
670
671/**
672 * Teximage storage routine for when a simple memcpy will do.
673 * No pixel transfer operations or special texel encodings allowed.
674 * 1D, 2D and 3D images supported.
675 */
676static void
677memcpy_texture(GLcontext *ctx,
678	       GLuint dimensions,
679               const struct gl_texture_format *dstFormat,
680               GLvoid *dstAddr,
681               GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
682               GLint dstRowStride,
683               const GLuint *dstImageOffsets,
684               GLint srcWidth, GLint srcHeight, GLint srcDepth,
685               GLenum srcFormat, GLenum srcType,
686               const GLvoid *srcAddr,
687               const struct gl_pixelstore_attrib *srcPacking)
688{
689   const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth,
690                                                     srcFormat, srcType);
691   const GLint srcImageStride = _mesa_image_image_stride(srcPacking,
692                                      srcWidth, srcHeight, srcFormat, srcType);
693   const GLubyte *srcImage = (const GLubyte *) _mesa_image_address(dimensions,
694        srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0);
695   const GLint bytesPerRow = srcWidth * dstFormat->TexelBytes;
696
697#if 0
698   /* XXX update/re-enable for dstImageOffsets array */
699   const GLint bytesPerImage = srcHeight * bytesPerRow;
700   const GLint bytesPerTexture = srcDepth * bytesPerImage;
701   GLubyte *dstImage = (GLubyte *) dstAddr
702                     + dstZoffset * dstImageStride
703                     + dstYoffset * dstRowStride
704                     + dstXoffset * dstFormat->TexelBytes;
705
706   if (dstRowStride == srcRowStride &&
707       dstRowStride == bytesPerRow &&
708       ((dstImageStride == srcImageStride &&
709         dstImageStride == bytesPerImage) ||
710        (srcDepth == 1))) {
711      /* one big memcpy */
712      ctx->Driver.TextureMemCpy(dstImage, srcImage, bytesPerTexture);
713   }
714   else
715   {
716      GLint img, row;
717      for (img = 0; img < srcDepth; img++) {
718         const GLubyte *srcRow = srcImage;
719         GLubyte *dstRow = dstImage;
720         for (row = 0; row < srcHeight; row++) {
721            ctx->Driver.TextureMemCpy(dstRow, srcRow, bytesPerRow);
722            dstRow += dstRowStride;
723            srcRow += srcRowStride;
724         }
725         srcImage += srcImageStride;
726         dstImage += dstImageStride;
727      }
728   }
729#endif
730
731   GLint img, row;
732   for (img = 0; img < srcDepth; img++) {
733      const GLubyte *srcRow = srcImage;
734      GLubyte *dstRow = (GLubyte *) dstAddr
735         + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
736         + dstYoffset * dstRowStride
737         + dstXoffset * dstFormat->TexelBytes;
738      for (row = 0; row < srcHeight; row++) {
739         ctx->Driver.TextureMemCpy(dstRow, srcRow, bytesPerRow);
740         dstRow += dstRowStride;
741         srcRow += srcRowStride;
742      }
743      srcImage += srcImageStride;
744   }
745}
746
747
748
749/**
750 * Store an image in any of the formats:
751 *   _mesa_texformat_rgba
752 *   _mesa_texformat_rgb
753 *   _mesa_texformat_alpha
754 *   _mesa_texformat_luminance
755 *   _mesa_texformat_luminance_alpha
756 *   _mesa_texformat_intensity
757 *
758 */
759GLboolean
760_mesa_texstore_rgba(TEXSTORE_PARAMS)
761{
762   const GLint components = _mesa_components_in_format(baseInternalFormat);
763
764   ASSERT(dstFormat == &_mesa_texformat_rgba ||
765          dstFormat == &_mesa_texformat_rgb ||
766          dstFormat == &_mesa_texformat_alpha ||
767          dstFormat == &_mesa_texformat_luminance ||
768          dstFormat == &_mesa_texformat_luminance_alpha ||
769          dstFormat == &_mesa_texformat_intensity);
770   ASSERT(baseInternalFormat == GL_RGBA ||
771          baseInternalFormat == GL_RGB ||
772          baseInternalFormat == GL_ALPHA ||
773          baseInternalFormat == GL_LUMINANCE ||
774          baseInternalFormat == GL_LUMINANCE_ALPHA ||
775          baseInternalFormat == GL_INTENSITY);
776   ASSERT(dstFormat->TexelBytes == components * sizeof(GLchan));
777
778   if (!ctx->_ImageTransferState &&
779       !srcPacking->SwapBytes &&
780       baseInternalFormat == srcFormat &&
781       srcType == CHAN_TYPE) {
782      /* simple memcpy path */
783      memcpy_texture(ctx, dims,
784                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
785                     dstRowStride,
786                     dstImageOffsets,
787                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
788                     srcAddr, srcPacking);
789   }
790   else if (!ctx->_ImageTransferState &&
791            !srcPacking->SwapBytes &&
792            dstFormat == &_mesa_texformat_rgb &&
793            srcFormat == GL_RGBA &&
794            srcType == CHAN_TYPE) {
795      /* extract RGB from RGBA */
796      GLint img, row, col;
797      for (img = 0; img < srcDepth; img++) {
798         GLchan *dstImage = (GLchan *)
799            ((GLubyte *) dstAddr
800             + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
801             + dstYoffset * dstRowStride
802             + dstXoffset * dstFormat->TexelBytes);
803
804         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
805                                                 srcWidth, srcFormat, srcType);
806         GLchan *srcRow = (GLchan *) _mesa_image_address(dims, srcPacking,
807                  srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
808         GLchan *dstRow = dstImage;
809         for (row = 0; row < srcHeight; row++) {
810            for (col = 0; col < srcWidth; col++) {
811               dstRow[col * 3 + RCOMP] = srcRow[col * 4 + RCOMP];
812               dstRow[col * 3 + GCOMP] = srcRow[col * 4 + GCOMP];
813               dstRow[col * 3 + BCOMP] = srcRow[col * 4 + BCOMP];
814            }
815            dstRow += dstRowStride / sizeof(GLchan);
816            srcRow = (GLchan *) ((GLubyte *) srcRow + srcRowStride);
817         }
818      }
819   }
820   else {
821      /* general path */
822      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
823                                                 baseInternalFormat,
824                                                 dstFormat->BaseFormat,
825                                                 srcWidth, srcHeight, srcDepth,
826                                                 srcFormat, srcType, srcAddr,
827                                                 srcPacking);
828      const GLchan *src = tempImage;
829      GLint bytesPerRow;
830      GLint img, row;
831      if (!tempImage)
832         return GL_FALSE;
833      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
834      bytesPerRow = srcWidth * components * sizeof(GLchan);
835      for (img = 0; img < srcDepth; img++) {
836         GLubyte *dstRow = (GLubyte *) dstAddr
837            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
838            + dstYoffset * dstRowStride
839            + dstXoffset * dstFormat->TexelBytes;
840         for (row = 0; row < srcHeight; row++) {
841            _mesa_memcpy(dstRow, src, bytesPerRow);
842            dstRow += dstRowStride;
843            src += srcWidth * components;
844         }
845      }
846
847      _mesa_free((void *) tempImage);
848   }
849   return GL_TRUE;
850}
851
852
853/**
854 * Store a 32-bit integer depth component texture image.
855 */
856GLboolean
857_mesa_texstore_z32(TEXSTORE_PARAMS)
858{
859   const GLfloat depthScale = (GLfloat) 0xffffffff;
860   (void) dims;
861   ASSERT(dstFormat == &_mesa_texformat_z32);
862   ASSERT(dstFormat->TexelBytes == sizeof(GLuint));
863
864   if (!ctx->_ImageTransferState &&
865       !srcPacking->SwapBytes &&
866       baseInternalFormat == GL_DEPTH_COMPONENT &&
867       srcFormat == GL_DEPTH_COMPONENT &&
868       srcType == GL_UNSIGNED_INT) {
869      /* simple memcpy path */
870      memcpy_texture(ctx, dims,
871                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
872                     dstRowStride,
873                     dstImageOffsets,
874                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
875                     srcAddr, srcPacking);
876   }
877   else {
878      /* general path */
879      GLint img, row;
880      for (img = 0; img < srcDepth; img++) {
881         GLubyte *dstRow = (GLubyte *) dstAddr
882            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
883            + dstYoffset * dstRowStride
884            + dstXoffset * dstFormat->TexelBytes;
885         for (row = 0; row < srcHeight; row++) {
886            const GLvoid *src = _mesa_image_address(dims, srcPacking,
887                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
888            _mesa_unpack_depth_span(ctx, srcWidth,
889                                    GL_UNSIGNED_INT, (GLuint *) dstRow,
890                                    depthScale, srcType, src, srcPacking);
891            dstRow += dstRowStride;
892         }
893      }
894   }
895   return GL_TRUE;
896}
897
898#define STRIDE_3D 0
899
900/**
901 * Store a 16-bit integer depth component texture image.
902 */
903GLboolean
904_mesa_texstore_z16(TEXSTORE_PARAMS)
905{
906   const GLfloat depthScale = 65535.0f;
907   (void) dims;
908   ASSERT(dstFormat == &_mesa_texformat_z16);
909   ASSERT(dstFormat->TexelBytes == sizeof(GLushort));
910
911   if (!ctx->_ImageTransferState &&
912       !srcPacking->SwapBytes &&
913       baseInternalFormat == GL_DEPTH_COMPONENT &&
914       srcFormat == GL_DEPTH_COMPONENT &&
915       srcType == GL_UNSIGNED_SHORT) {
916      /* simple memcpy path */
917      memcpy_texture(ctx, dims,
918                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
919                     dstRowStride,
920                     dstImageOffsets,
921                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
922                     srcAddr, srcPacking);
923   }
924   else {
925      /* general path */
926      GLint img, row;
927      for (img = 0; img < srcDepth; img++) {
928         GLubyte *dstRow = (GLubyte *) dstAddr
929            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
930            + dstYoffset * dstRowStride
931            + dstXoffset * dstFormat->TexelBytes;
932         for (row = 0; row < srcHeight; row++) {
933            const GLvoid *src = _mesa_image_address(dims, srcPacking,
934                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
935            GLushort *dst16 = (GLushort *) dstRow;
936            _mesa_unpack_depth_span(ctx, srcWidth,
937                                    GL_UNSIGNED_SHORT, dst16, depthScale,
938                                    srcType, src, srcPacking);
939            dstRow += dstRowStride;
940         }
941      }
942   }
943   return GL_TRUE;
944}
945
946
947/**
948 * Store an rgb565 or rgb565_rev texture image.
949 */
950GLboolean
951_mesa_texstore_rgb565(TEXSTORE_PARAMS)
952{
953   ASSERT(dstFormat == &_mesa_texformat_rgb565 ||
954          dstFormat == &_mesa_texformat_rgb565_rev);
955   ASSERT(dstFormat->TexelBytes == 2);
956
957   if (!ctx->_ImageTransferState &&
958       !srcPacking->SwapBytes &&
959       dstFormat == &_mesa_texformat_rgb565 &&
960       baseInternalFormat == GL_RGB &&
961       srcFormat == GL_RGB &&
962       srcType == GL_UNSIGNED_SHORT_5_6_5) {
963      /* simple memcpy path */
964      memcpy_texture(ctx, dims,
965                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
966                     dstRowStride,
967                     dstImageOffsets,
968                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
969                     srcAddr, srcPacking);
970   }
971   else if (!ctx->_ImageTransferState &&
972            !srcPacking->SwapBytes &&
973            baseInternalFormat == GL_RGB &&
974            srcFormat == GL_RGB &&
975            srcType == GL_UNSIGNED_BYTE &&
976            dims == 2) {
977      /* do optimized tex store */
978      const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth,
979                                                        srcFormat, srcType);
980      const GLubyte *src = (const GLubyte *)
981         _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight,
982                             srcFormat, srcType, 0, 0, 0);
983      GLubyte *dst = (GLubyte *) dstAddr
984                   + dstYoffset * dstRowStride
985                   + dstXoffset * dstFormat->TexelBytes;
986      GLint row, col;
987      for (row = 0; row < srcHeight; row++) {
988         const GLubyte *srcUB = (const GLubyte *) src;
989         GLushort *dstUS = (GLushort *) dst;
990         /* check for byteswapped format */
991         if (dstFormat == &_mesa_texformat_rgb565) {
992            for (col = 0; col < srcWidth; col++) {
993               dstUS[col] = PACK_COLOR_565( srcUB[0], srcUB[1], srcUB[2] );
994               srcUB += 3;
995            }
996         }
997         else {
998            for (col = 0; col < srcWidth; col++) {
999               dstUS[col] = PACK_COLOR_565_REV( srcUB[0], srcUB[1], srcUB[2] );
1000               srcUB += 3;
1001            }
1002         }
1003         dst += dstRowStride;
1004         src += srcRowStride;
1005      }
1006   }
1007   else {
1008      /* general path */
1009      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1010                                                 baseInternalFormat,
1011                                                 dstFormat->BaseFormat,
1012                                                 srcWidth, srcHeight, srcDepth,
1013                                                 srcFormat, srcType, srcAddr,
1014                                                 srcPacking);
1015      const GLchan *src = tempImage;
1016      GLint img, row, col;
1017      if (!tempImage)
1018         return GL_FALSE;
1019      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1020      for (img = 0; img < srcDepth; img++) {
1021         GLubyte *dstRow = (GLubyte *) dstAddr
1022            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1023            + dstYoffset * dstRowStride
1024            + dstXoffset * dstFormat->TexelBytes;
1025         for (row = 0; row < srcHeight; row++) {
1026            GLushort *dstUS = (GLushort *) dstRow;
1027            /* check for byteswapped format */
1028            if (dstFormat == &_mesa_texformat_rgb565) {
1029               for (col = 0; col < srcWidth; col++) {
1030                  dstUS[col] = PACK_COLOR_565( CHAN_TO_UBYTE(src[RCOMP]),
1031                                               CHAN_TO_UBYTE(src[GCOMP]),
1032                                               CHAN_TO_UBYTE(src[BCOMP]) );
1033                  src += 3;
1034               }
1035            }
1036            else {
1037               for (col = 0; col < srcWidth; col++) {
1038                  dstUS[col] = PACK_COLOR_565_REV( CHAN_TO_UBYTE(src[RCOMP]),
1039                                                   CHAN_TO_UBYTE(src[GCOMP]),
1040                                                   CHAN_TO_UBYTE(src[BCOMP]) );
1041                  src += 3;
1042               }
1043            }
1044            dstRow += dstRowStride;
1045         }
1046      }
1047      _mesa_free((void *) tempImage);
1048   }
1049   return GL_TRUE;
1050}
1051
1052
1053GLboolean
1054_mesa_texstore_rgba8888(TEXSTORE_PARAMS)
1055{
1056   const GLuint ui = 1;
1057   const GLubyte littleEndian = *((const GLubyte *) &ui);
1058
1059   (void)littleEndian;
1060   ASSERT(dstFormat == &_mesa_texformat_rgba8888 ||
1061          dstFormat == &_mesa_texformat_rgba8888_rev);
1062   ASSERT(dstFormat->TexelBytes == 4);
1063
1064   if (!ctx->_ImageTransferState &&
1065       !srcPacking->SwapBytes &&
1066       dstFormat == &_mesa_texformat_rgba8888 &&
1067       baseInternalFormat == GL_RGBA &&
1068      ((srcFormat == GL_RGBA && srcType == GL_UNSIGNED_INT_8_8_8_8) ||
1069       (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE && !littleEndian) ||
1070       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_INT_8_8_8_8_REV) ||
1071       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_BYTE && littleEndian))) {
1072       /* simple memcpy path */
1073      memcpy_texture(ctx, dims,
1074                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1075                     dstRowStride,
1076                     dstImageOffsets,
1077                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1078                     srcAddr, srcPacking);
1079   }
1080   else if (!ctx->_ImageTransferState &&
1081       !srcPacking->SwapBytes &&
1082       dstFormat == &_mesa_texformat_rgba8888_rev &&
1083       baseInternalFormat == GL_RGBA &&
1084      ((srcFormat == GL_RGBA && srcType == GL_UNSIGNED_INT_8_8_8_8_REV) ||
1085       (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE && littleEndian) ||
1086       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_INT_8_8_8_8) ||
1087       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_BYTE && !littleEndian))) {
1088      /* simple memcpy path */
1089      memcpy_texture(ctx, dims,
1090                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1091                     dstRowStride,
1092                     dstImageOffsets,
1093                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1094                     srcAddr, srcPacking);
1095   }
1096#if 0
1097   /* broken? */
1098   else if (!ctx->_ImageTransferState &&
1099	    !srcPacking->SwapBytes &&
1100	    srcType == GL_UNSIGNED_BYTE &&
1101	    dstFormat == &_mesa_texformat_rgba8888 &&
1102	    littleEndian &&
1103	    /* Three texture formats involved: srcFormat,
1104	     * baseInternalFormat and destFormat (GL_RGBA). Only two
1105	     * may differ. _mesa_swizzle_ubyte_image can't handle two
1106	     * propagations at once correctly. */
1107	    (srcFormat == baseInternalFormat ||
1108	     baseInternalFormat == GL_RGBA) &&
1109	    can_swizzle(srcFormat)) {
1110      GLubyte dstmap[4];
1111
1112      /* dstmap - how to swizzle from GL_RGBA to dst format:
1113       *
1114       * FIXME - add !litteEndian and _rev varients:
1115       */
1116      dstmap[3] = 0;
1117      dstmap[2] = 1;
1118      dstmap[1] = 2;
1119      dstmap[0] = 3;
1120
1121      _mesa_swizzle_ubyte_image(ctx, dims,
1122				srcFormat,
1123				dstmap, 4,
1124				dstAddr, dstXoffset, dstYoffset, dstZoffset,
1125				dstRowStride, dstImageStride,
1126				srcWidth, srcHeight, srcDepth, srcAddr,
1127				srcPacking);
1128   }
1129#endif
1130   else {
1131      /* general path */
1132      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1133                                                 baseInternalFormat,
1134                                                 dstFormat->BaseFormat,
1135                                                 srcWidth, srcHeight, srcDepth,
1136                                                 srcFormat, srcType, srcAddr,
1137                                                 srcPacking);
1138      const GLchan *src = tempImage;
1139      GLint img, row, col;
1140      if (!tempImage)
1141         return GL_FALSE;
1142      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1143      for (img = 0; img < srcDepth; img++) {
1144         GLubyte *dstRow = (GLubyte *) dstAddr
1145            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1146            + dstYoffset * dstRowStride
1147            + dstXoffset * dstFormat->TexelBytes;
1148         for (row = 0; row < srcHeight; row++) {
1149            GLuint *dstUI = (GLuint *) dstRow;
1150            if (dstFormat == &_mesa_texformat_rgba8888) {
1151               for (col = 0; col < srcWidth; col++) {
1152                  dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[RCOMP]),
1153                                                CHAN_TO_UBYTE(src[GCOMP]),
1154                                                CHAN_TO_UBYTE(src[BCOMP]),
1155                                                CHAN_TO_UBYTE(src[ACOMP]) );
1156                  src += 4;
1157               }
1158            }
1159            else {
1160               for (col = 0; col < srcWidth; col++) {
1161                  dstUI[col] = PACK_COLOR_8888_REV( CHAN_TO_UBYTE(src[RCOMP]),
1162                                                    CHAN_TO_UBYTE(src[GCOMP]),
1163                                                    CHAN_TO_UBYTE(src[BCOMP]),
1164                                                    CHAN_TO_UBYTE(src[ACOMP]) );
1165                  src += 4;
1166               }
1167            }
1168            dstRow += dstRowStride;
1169         }
1170      }
1171      _mesa_free((void *) tempImage);
1172   }
1173   return GL_TRUE;
1174}
1175
1176
1177GLboolean
1178_mesa_texstore_argb8888(TEXSTORE_PARAMS)
1179{
1180   const GLuint ui = 1;
1181   const GLubyte littleEndian = *((const GLubyte *) &ui);
1182
1183   ASSERT(dstFormat == &_mesa_texformat_argb8888 ||
1184          dstFormat == &_mesa_texformat_argb8888_rev);
1185   ASSERT(dstFormat->TexelBytes == 4);
1186
1187   if (!ctx->_ImageTransferState &&
1188       !srcPacking->SwapBytes &&
1189       dstFormat == &_mesa_texformat_argb8888 &&
1190       baseInternalFormat == GL_RGBA &&
1191       srcFormat == GL_BGRA &&
1192       ((srcType == GL_UNSIGNED_BYTE && littleEndian) ||
1193        srcType == GL_UNSIGNED_INT_8_8_8_8_REV)) {
1194      /* simple memcpy path (little endian) */
1195      memcpy_texture(ctx, dims,
1196                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1197                     dstRowStride,
1198                     dstImageOffsets,
1199                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1200                     srcAddr, srcPacking);
1201   }
1202   else if (!ctx->_ImageTransferState &&
1203       !srcPacking->SwapBytes &&
1204       dstFormat == &_mesa_texformat_argb8888_rev &&
1205       baseInternalFormat == GL_RGBA &&
1206       srcFormat == GL_BGRA &&
1207       ((srcType == GL_UNSIGNED_BYTE && !littleEndian) ||
1208        srcType == GL_UNSIGNED_INT_8_8_8_8)) {
1209      /* simple memcpy path (big endian) */
1210      memcpy_texture(ctx, dims,
1211                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1212                     dstRowStride,
1213                     dstImageOffsets,
1214                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1215                     srcAddr, srcPacking);
1216   }
1217   else if (!ctx->_ImageTransferState &&
1218            !srcPacking->SwapBytes &&
1219	    dstFormat == &_mesa_texformat_argb8888 &&
1220            srcFormat == GL_RGB &&
1221            srcType == GL_UNSIGNED_BYTE) {
1222
1223      int img, row, col;
1224      for (img = 0; img < srcDepth; img++) {
1225         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
1226                                                 srcWidth, srcFormat, srcType);
1227         GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking,
1228                  srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
1229         GLubyte *dstRow = (GLubyte *) dstAddr
1230            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1231            + dstYoffset * dstRowStride
1232            + dstXoffset * dstFormat->TexelBytes;
1233         for (row = 0; row < srcHeight; row++) {
1234            for (col = 0; col < srcWidth; col++) {
1235               dstRow[col * 4 + 0] = srcRow[col * 3 + BCOMP];
1236               dstRow[col * 4 + 1] = srcRow[col * 3 + GCOMP];
1237               dstRow[col * 4 + 2] = srcRow[col * 3 + RCOMP];
1238               dstRow[col * 4 + 3] = 0xff;
1239            }
1240            dstRow += dstRowStride;
1241            srcRow += srcRowStride;
1242         }
1243      }
1244   }
1245   else if (!ctx->_ImageTransferState &&
1246            !srcPacking->SwapBytes &&
1247	    dstFormat == &_mesa_texformat_argb8888 &&
1248            srcFormat == GL_RGBA &&
1249            (srcType == GL_UNSIGNED_BYTE && littleEndian)) {
1250      GLint img, row, col;
1251      /* For some reason, streaming copies to write-combined regions
1252       * are extremely sensitive to the characteristics of how the
1253       * source data is retrieved.  By reordering the source reads to
1254       * be in-order, the speed of this operation increases by half.
1255       * Strangely the same isn't required for the RGB path, above.
1256       */
1257      for (img = 0; img < srcDepth; img++) {
1258         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
1259                                                 srcWidth, srcFormat, srcType);
1260         GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking,
1261                  srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
1262         GLubyte *dstRow = (GLubyte *) dstAddr
1263            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1264            + dstYoffset * dstRowStride
1265            + dstXoffset * dstFormat->TexelBytes;
1266
1267         for (row = 0; row < srcHeight; row++) {
1268            for (col = 0; col < srcWidth; col++) {
1269               *(GLuint *)(dstRow + col * 4)  = (srcRow[col * 4 + RCOMP] << 16 |
1270						 srcRow[col * 4 + GCOMP] << 8 |
1271						 srcRow[col * 4 + BCOMP] << 0 |
1272						 srcRow[col * 4 + ACOMP] << 24);
1273            }
1274            dstRow += dstRowStride;
1275            srcRow += srcRowStride;
1276         }
1277      }
1278   }
1279   else if (!ctx->_ImageTransferState &&
1280            !srcPacking->SwapBytes &&
1281	    dstFormat == &_mesa_texformat_argb8888 &&
1282            srcFormat == GL_RGBA &&
1283            srcType == GL_UNSIGNED_BYTE) {
1284
1285      GLint img, row, col;
1286      for (img = 0; img < srcDepth; img++) {
1287         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
1288                                                 srcWidth, srcFormat, srcType);
1289         GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking,
1290                  srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
1291         GLubyte *dstRow = (GLubyte *) dstAddr
1292            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1293            + dstYoffset * dstRowStride
1294            + dstXoffset * dstFormat->TexelBytes;
1295         for (row = 0; row < srcHeight; row++) {
1296            for (col = 0; col < srcWidth; col++) {
1297               dstRow[col * 4 + 0] = srcRow[col * 4 + BCOMP];
1298               dstRow[col * 4 + 1] = srcRow[col * 4 + GCOMP];
1299               dstRow[col * 4 + 2] = srcRow[col * 4 + RCOMP];
1300               dstRow[col * 4 + 3] = srcRow[col * 4 + ACOMP];
1301            }
1302            dstRow += dstRowStride;
1303            srcRow += srcRowStride;
1304         }
1305      }
1306   }
1307   else if (!ctx->_ImageTransferState &&
1308	    !srcPacking->SwapBytes &&
1309	    dstFormat == &_mesa_texformat_argb8888 &&
1310	    srcType == GL_UNSIGNED_BYTE &&
1311	    littleEndian &&
1312	    /* Three texture formats involved: srcFormat,
1313	     * baseInternalFormat and destFormat (GL_RGBA). Only two
1314	     * may differ. _mesa_swizzle_ubyte_image can't handle two
1315	     * propagations at once correctly. */
1316	    (srcFormat == baseInternalFormat ||
1317	     baseInternalFormat == GL_RGBA) &&
1318	    can_swizzle(srcFormat)) {
1319
1320      GLubyte dstmap[4];
1321
1322      /* dstmap - how to swizzle from GL_RGBA to dst format:
1323       */
1324      dstmap[3] = 3;		/* alpha */
1325      dstmap[2] = 0;		/* red */
1326      dstmap[1] = 1;		/* green */
1327      dstmap[0] = 2;		/* blue */
1328
1329      _mesa_swizzle_ubyte_image(ctx, dims,
1330				srcFormat,
1331				dstmap, 4,
1332				dstAddr, dstXoffset, dstYoffset, dstZoffset,
1333				dstRowStride,
1334                                dstImageOffsets,
1335				srcWidth, srcHeight, srcDepth, srcAddr,
1336				srcPacking);
1337   }
1338   else {
1339      /* general path */
1340      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1341                                                 baseInternalFormat,
1342                                                 dstFormat->BaseFormat,
1343                                                 srcWidth, srcHeight, srcDepth,
1344                                                 srcFormat, srcType, srcAddr,
1345                                                 srcPacking);
1346      const GLchan *src = tempImage;
1347      GLint img, row, col;
1348      if (!tempImage)
1349         return GL_FALSE;
1350      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1351      for (img = 0; img < srcDepth; img++) {
1352         GLubyte *dstRow = (GLubyte *) dstAddr
1353            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1354            + dstYoffset * dstRowStride
1355            + dstXoffset * dstFormat->TexelBytes;
1356         for (row = 0; row < srcHeight; row++) {
1357            GLuint *dstUI = (GLuint *) dstRow;
1358            if (dstFormat == &_mesa_texformat_argb8888) {
1359               for (col = 0; col < srcWidth; col++) {
1360                  dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[ACOMP]),
1361                                                CHAN_TO_UBYTE(src[RCOMP]),
1362                                                CHAN_TO_UBYTE(src[GCOMP]),
1363                                                CHAN_TO_UBYTE(src[BCOMP]) );
1364                  src += 4;
1365               }
1366            }
1367            else {
1368               for (col = 0; col < srcWidth; col++) {
1369                  dstUI[col] = PACK_COLOR_8888_REV( CHAN_TO_UBYTE(src[ACOMP]),
1370                                                    CHAN_TO_UBYTE(src[RCOMP]),
1371                                                    CHAN_TO_UBYTE(src[GCOMP]),
1372                                                    CHAN_TO_UBYTE(src[BCOMP]) );
1373                  src += 4;
1374               }
1375            }
1376            dstRow += dstRowStride;
1377         }
1378      }
1379      _mesa_free((void *) tempImage);
1380   }
1381   return GL_TRUE;
1382}
1383
1384
1385GLboolean
1386_mesa_texstore_rgb888(TEXSTORE_PARAMS)
1387{
1388   const GLuint ui = 1;
1389   const GLubyte littleEndian = *((const GLubyte *) &ui);
1390
1391   ASSERT(dstFormat == &_mesa_texformat_rgb888);
1392   ASSERT(dstFormat->TexelBytes == 3);
1393
1394   if (!ctx->_ImageTransferState &&
1395       !srcPacking->SwapBytes &&
1396       baseInternalFormat == GL_RGB &&
1397       srcFormat == GL_BGR &&
1398       srcType == GL_UNSIGNED_BYTE &&
1399       littleEndian) {
1400      /* simple memcpy path */
1401      memcpy_texture(ctx, dims,
1402                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1403                     dstRowStride,
1404                     dstImageOffsets,
1405                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1406                     srcAddr, srcPacking);
1407   }
1408   else if (!ctx->_ImageTransferState &&
1409            !srcPacking->SwapBytes &&
1410            srcFormat == GL_RGBA &&
1411            srcType == GL_UNSIGNED_BYTE) {
1412      /* extract RGB from RGBA */
1413      GLint img, row, col;
1414      for (img = 0; img < srcDepth; img++) {
1415         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
1416                                                 srcWidth, srcFormat, srcType);
1417         GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking,
1418                  srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
1419         GLubyte *dstRow = (GLubyte *) dstAddr
1420            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1421            + dstYoffset * dstRowStride
1422            + dstXoffset * dstFormat->TexelBytes;
1423         for (row = 0; row < srcHeight; row++) {
1424            for (col = 0; col < srcWidth; col++) {
1425               dstRow[col * 3 + 0] = srcRow[col * 4 + BCOMP];
1426               dstRow[col * 3 + 1] = srcRow[col * 4 + GCOMP];
1427               dstRow[col * 3 + 2] = srcRow[col * 4 + RCOMP];
1428            }
1429            dstRow += dstRowStride;
1430            srcRow += srcRowStride;
1431         }
1432      }
1433   }
1434   else {
1435      /* general path */
1436      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1437                                                 baseInternalFormat,
1438                                                 dstFormat->BaseFormat,
1439                                                 srcWidth, srcHeight, srcDepth,
1440                                                 srcFormat, srcType, srcAddr,
1441                                                 srcPacking);
1442      const GLchan *src = (const GLchan *) tempImage;
1443      GLint img, row, col;
1444      if (!tempImage)
1445         return GL_FALSE;
1446      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1447      for (img = 0; img < srcDepth; img++) {
1448         GLubyte *dstRow = (GLubyte *) dstAddr
1449            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1450            + dstYoffset * dstRowStride
1451            + dstXoffset * dstFormat->TexelBytes;
1452         for (row = 0; row < srcHeight; row++) {
1453#if 0
1454            if (littleEndian) {
1455               for (col = 0; col < srcWidth; col++) {
1456                  dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[RCOMP]);
1457                  dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]);
1458                  dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[BCOMP]);
1459                  srcUB += 3;
1460               }
1461            }
1462            else {
1463               for (col = 0; col < srcWidth; col++) {
1464                  dstRow[col * 3 + 0] = srcUB[BCOMP];
1465                  dstRow[col * 3 + 1] = srcUB[GCOMP];
1466                  dstRow[col * 3 + 2] = srcUB[RCOMP];
1467                  srcUB += 3;
1468               }
1469            }
1470#else
1471            for (col = 0; col < srcWidth; col++) {
1472               dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[BCOMP]);
1473               dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]);
1474               dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[RCOMP]);
1475               src += 3;
1476            }
1477#endif
1478            dstRow += dstRowStride;
1479         }
1480      }
1481      _mesa_free((void *) tempImage);
1482   }
1483   return GL_TRUE;
1484}
1485
1486
1487GLboolean
1488_mesa_texstore_bgr888(TEXSTORE_PARAMS)
1489{
1490   const GLuint ui = 1;
1491   const GLubyte littleEndian = *((const GLubyte *) &ui);
1492
1493   ASSERT(dstFormat == &_mesa_texformat_bgr888);
1494   ASSERT(dstFormat->TexelBytes == 3);
1495
1496   if (!ctx->_ImageTransferState &&
1497       !srcPacking->SwapBytes &&
1498       baseInternalFormat == GL_RGB &&
1499       srcFormat == GL_RGB &&
1500       srcType == GL_UNSIGNED_BYTE &&
1501       littleEndian) {
1502      /* simple memcpy path */
1503      memcpy_texture(ctx, dims,
1504                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1505                     dstRowStride,
1506                     dstImageOffsets,
1507                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1508                     srcAddr, srcPacking);
1509   }
1510   else if (!ctx->_ImageTransferState &&
1511            !srcPacking->SwapBytes &&
1512            srcFormat == GL_RGBA &&
1513            srcType == GL_UNSIGNED_BYTE) {
1514      /* extract BGR from RGBA */
1515      int img, row, col;
1516      for (img = 0; img < srcDepth; img++) {
1517         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
1518                                                 srcWidth, srcFormat, srcType);
1519         GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking,
1520                  srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0);
1521         GLubyte *dstRow = (GLubyte *) dstAddr
1522            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1523            + dstYoffset * dstRowStride
1524            + dstXoffset * dstFormat->TexelBytes;
1525         for (row = 0; row < srcHeight; row++) {
1526            for (col = 0; col < srcWidth; col++) {
1527               dstRow[col * 3 + 0] = srcRow[col * 4 + RCOMP];
1528               dstRow[col * 3 + 1] = srcRow[col * 4 + GCOMP];
1529               dstRow[col * 3 + 2] = srcRow[col * 4 + BCOMP];
1530            }
1531            dstRow += dstRowStride;
1532            srcRow += srcRowStride;
1533         }
1534      }
1535   }
1536   else {
1537      /* general path */
1538      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1539                                                 baseInternalFormat,
1540                                                 dstFormat->BaseFormat,
1541                                                 srcWidth, srcHeight, srcDepth,
1542                                                 srcFormat, srcType, srcAddr,
1543                                                 srcPacking);
1544      const GLchan *src = (const GLchan *) tempImage;
1545      GLint img, row, col;
1546      if (!tempImage)
1547         return GL_FALSE;
1548      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1549      for (img = 0; img < srcDepth; img++) {
1550         GLubyte *dstRow = (GLubyte *) dstAddr
1551            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1552            + dstYoffset * dstRowStride
1553            + dstXoffset * dstFormat->TexelBytes;
1554         for (row = 0; row < srcHeight; row++) {
1555            for (col = 0; col < srcWidth; col++) {
1556               dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[RCOMP]);
1557               dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]);
1558               dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[BCOMP]);
1559               src += 3;
1560            }
1561            dstRow += dstRowStride;
1562         }
1563      }
1564      _mesa_free((void *) tempImage);
1565   }
1566   return GL_TRUE;
1567}
1568
1569
1570GLboolean
1571_mesa_texstore_argb4444(TEXSTORE_PARAMS)
1572{
1573   ASSERT(dstFormat == &_mesa_texformat_argb4444 ||
1574          dstFormat == &_mesa_texformat_argb4444_rev);
1575   ASSERT(dstFormat->TexelBytes == 2);
1576
1577   if (!ctx->_ImageTransferState &&
1578       !srcPacking->SwapBytes &&
1579       dstFormat == &_mesa_texformat_argb4444 &&
1580       baseInternalFormat == GL_RGBA &&
1581       srcFormat == GL_BGRA &&
1582       srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV) {
1583      /* simple memcpy path */
1584      memcpy_texture(ctx, dims,
1585                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1586                     dstRowStride,
1587                     dstImageOffsets,
1588                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1589                     srcAddr, srcPacking);
1590   }
1591   else {
1592      /* general path */
1593      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1594                                                 baseInternalFormat,
1595                                                 dstFormat->BaseFormat,
1596                                                 srcWidth, srcHeight, srcDepth,
1597                                                 srcFormat, srcType, srcAddr,
1598                                                 srcPacking);
1599      const GLchan *src = tempImage;
1600      GLint img, row, col;
1601      if (!tempImage)
1602         return GL_FALSE;
1603      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1604      for (img = 0; img < srcDepth; img++) {
1605         GLubyte *dstRow = (GLubyte *) dstAddr
1606            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1607            + dstYoffset * dstRowStride
1608            + dstXoffset * dstFormat->TexelBytes;
1609         for (row = 0; row < srcHeight; row++) {
1610            GLushort *dstUS = (GLushort *) dstRow;
1611            if (dstFormat == &_mesa_texformat_argb4444) {
1612               for (col = 0; col < srcWidth; col++) {
1613                  dstUS[col] = PACK_COLOR_4444( CHAN_TO_UBYTE(src[ACOMP]),
1614                                                CHAN_TO_UBYTE(src[RCOMP]),
1615                                                CHAN_TO_UBYTE(src[GCOMP]),
1616                                                CHAN_TO_UBYTE(src[BCOMP]) );
1617                  src += 4;
1618               }
1619            }
1620            else {
1621               for (col = 0; col < srcWidth; col++) {
1622                  dstUS[col] = PACK_COLOR_4444_REV( CHAN_TO_UBYTE(src[ACOMP]),
1623                                                    CHAN_TO_UBYTE(src[RCOMP]),
1624                                                    CHAN_TO_UBYTE(src[GCOMP]),
1625                                                    CHAN_TO_UBYTE(src[BCOMP]) );
1626                  src += 4;
1627               }
1628            }
1629            dstRow += dstRowStride;
1630         }
1631      }
1632      _mesa_free((void *) tempImage);
1633   }
1634   return GL_TRUE;
1635}
1636
1637
1638
1639GLboolean
1640_mesa_texstore_argb1555(TEXSTORE_PARAMS)
1641{
1642   ASSERT(dstFormat == &_mesa_texformat_argb1555 ||
1643          dstFormat == &_mesa_texformat_argb1555_rev);
1644   ASSERT(dstFormat->TexelBytes == 2);
1645
1646   if (!ctx->_ImageTransferState &&
1647       !srcPacking->SwapBytes &&
1648       dstFormat == &_mesa_texformat_argb1555 &&
1649       baseInternalFormat == GL_RGBA &&
1650       srcFormat == GL_BGRA &&
1651       srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV) {
1652      /* simple memcpy path */
1653      memcpy_texture(ctx, dims,
1654                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1655                     dstRowStride,
1656                     dstImageOffsets,
1657                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1658                     srcAddr, srcPacking);
1659   }
1660   else {
1661      /* general path */
1662      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1663                                                 baseInternalFormat,
1664                                                 dstFormat->BaseFormat,
1665                                                 srcWidth, srcHeight, srcDepth,
1666                                                 srcFormat, srcType, srcAddr,
1667                                                 srcPacking);
1668      const GLchan *src =tempImage;
1669      GLint img, row, col;
1670      if (!tempImage)
1671         return GL_FALSE;
1672      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1673      for (img = 0; img < srcDepth; img++) {
1674         GLubyte *dstRow = (GLubyte *) dstAddr
1675            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1676            + dstYoffset * dstRowStride
1677            + dstXoffset * dstFormat->TexelBytes;
1678         for (row = 0; row < srcHeight; row++) {
1679            GLushort *dstUS = (GLushort *) dstRow;
1680            if (dstFormat == &_mesa_texformat_argb1555) {
1681               for (col = 0; col < srcWidth; col++) {
1682                  dstUS[col] = PACK_COLOR_1555( CHAN_TO_UBYTE(src[ACOMP]),
1683                                                CHAN_TO_UBYTE(src[RCOMP]),
1684                                                CHAN_TO_UBYTE(src[GCOMP]),
1685                                                CHAN_TO_UBYTE(src[BCOMP]) );
1686                  src += 4;
1687               }
1688            }
1689            else {
1690               for (col = 0; col < srcWidth; col++) {
1691                  dstUS[col] = PACK_COLOR_1555_REV( CHAN_TO_UBYTE(src[ACOMP]),
1692                                                    CHAN_TO_UBYTE(src[RCOMP]),
1693                                                    CHAN_TO_UBYTE(src[GCOMP]),
1694                                                    CHAN_TO_UBYTE(src[BCOMP]) );
1695                  src += 4;
1696               }
1697            }
1698            dstRow += dstRowStride;
1699         }
1700      }
1701      _mesa_free((void *) tempImage);
1702   }
1703   return GL_TRUE;
1704}
1705
1706
1707GLboolean
1708_mesa_texstore_al88(TEXSTORE_PARAMS)
1709{
1710   const GLuint ui = 1;
1711   const GLubyte littleEndian = *((const GLubyte *) &ui);
1712
1713   ASSERT(dstFormat == &_mesa_texformat_al88 ||
1714          dstFormat == &_mesa_texformat_al88_rev);
1715   ASSERT(dstFormat->TexelBytes == 2);
1716
1717   if (!ctx->_ImageTransferState &&
1718       !srcPacking->SwapBytes &&
1719       dstFormat == &_mesa_texformat_al88 &&
1720       baseInternalFormat == GL_LUMINANCE_ALPHA &&
1721       srcFormat == GL_LUMINANCE_ALPHA &&
1722       srcType == GL_UNSIGNED_BYTE &&
1723       littleEndian) {
1724      /* simple memcpy path */
1725      memcpy_texture(ctx, dims,
1726                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1727                     dstRowStride,
1728                     dstImageOffsets,
1729                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1730                     srcAddr, srcPacking);
1731   }
1732   else {
1733      /* general path */
1734      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1735                                                 baseInternalFormat,
1736                                                 dstFormat->BaseFormat,
1737                                                 srcWidth, srcHeight, srcDepth,
1738                                                 srcFormat, srcType, srcAddr,
1739                                                 srcPacking);
1740      const GLchan *src = tempImage;
1741      GLint img, row, col;
1742      if (!tempImage)
1743         return GL_FALSE;
1744      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1745      for (img = 0; img < srcDepth; img++) {
1746         GLubyte *dstRow = (GLubyte *) dstAddr
1747            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1748            + dstYoffset * dstRowStride
1749            + dstXoffset * dstFormat->TexelBytes;
1750         for (row = 0; row < srcHeight; row++) {
1751            GLushort *dstUS = (GLushort *) dstRow;
1752            if (dstFormat == &_mesa_texformat_al88) {
1753               for (col = 0; col < srcWidth; col++) {
1754                  /* src[0] is luminance, src[1] is alpha */
1755                 dstUS[col] = PACK_COLOR_88( CHAN_TO_UBYTE(src[1]),
1756                                             CHAN_TO_UBYTE(src[0]) );
1757                 src += 2;
1758               }
1759            }
1760            else {
1761               for (col = 0; col < srcWidth; col++) {
1762                  /* src[0] is luminance, src[1] is alpha */
1763                 dstUS[col] = PACK_COLOR_88_REV( CHAN_TO_UBYTE(src[1]),
1764                                                 CHAN_TO_UBYTE(src[0]) );
1765                 src += 2;
1766               }
1767            }
1768            dstRow += dstRowStride;
1769         }
1770      }
1771      _mesa_free((void *) tempImage);
1772   }
1773   return GL_TRUE;
1774}
1775
1776
1777GLboolean
1778_mesa_texstore_rgb332(TEXSTORE_PARAMS)
1779{
1780   ASSERT(dstFormat == &_mesa_texformat_rgb332);
1781   ASSERT(dstFormat->TexelBytes == 1);
1782
1783   if (!ctx->_ImageTransferState &&
1784       !srcPacking->SwapBytes &&
1785       baseInternalFormat == GL_RGB &&
1786       srcFormat == GL_RGB && srcType == GL_UNSIGNED_BYTE_3_3_2) {
1787      /* simple memcpy path */
1788      memcpy_texture(ctx, dims,
1789                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1790                     dstRowStride,
1791                     dstImageOffsets,
1792                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1793                     srcAddr, srcPacking);
1794   }
1795   else {
1796      /* general path */
1797      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1798                                                 baseInternalFormat,
1799                                                 dstFormat->BaseFormat,
1800                                                 srcWidth, srcHeight, srcDepth,
1801                                                 srcFormat, srcType, srcAddr,
1802                                                 srcPacking);
1803      const GLchan *src = tempImage;
1804      GLint img, row, col;
1805      if (!tempImage)
1806         return GL_FALSE;
1807      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1808      for (img = 0; img < srcDepth; img++) {
1809         GLubyte *dstRow = (GLubyte *) dstAddr
1810            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1811            + dstYoffset * dstRowStride
1812            + dstXoffset * dstFormat->TexelBytes;
1813         for (row = 0; row < srcHeight; row++) {
1814            for (col = 0; col < srcWidth; col++) {
1815               dstRow[col] = PACK_COLOR_332( CHAN_TO_UBYTE(src[RCOMP]),
1816                                             CHAN_TO_UBYTE(src[GCOMP]),
1817                                             CHAN_TO_UBYTE(src[BCOMP]) );
1818               src += 3;
1819            }
1820            dstRow += dstRowStride;
1821         }
1822      }
1823      _mesa_free((void *) tempImage);
1824   }
1825   return GL_TRUE;
1826}
1827
1828
1829/**
1830 * Texstore for _mesa_texformat_a8, _mesa_texformat_l8, _mesa_texformat_i8.
1831 */
1832GLboolean
1833_mesa_texstore_a8(TEXSTORE_PARAMS)
1834{
1835   ASSERT(dstFormat == &_mesa_texformat_a8 ||
1836          dstFormat == &_mesa_texformat_l8 ||
1837          dstFormat == &_mesa_texformat_i8);
1838   ASSERT(dstFormat->TexelBytes == 1);
1839
1840   if (!ctx->_ImageTransferState &&
1841       !srcPacking->SwapBytes &&
1842       baseInternalFormat == srcFormat &&
1843       srcType == GL_UNSIGNED_BYTE) {
1844      /* simple memcpy path */
1845      memcpy_texture(ctx, dims,
1846                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1847                     dstRowStride,
1848                     dstImageOffsets,
1849                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1850                     srcAddr, srcPacking);
1851   }
1852   else {
1853      /* general path */
1854      const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
1855                                                 baseInternalFormat,
1856                                                 dstFormat->BaseFormat,
1857                                                 srcWidth, srcHeight, srcDepth,
1858                                                 srcFormat, srcType, srcAddr,
1859                                                 srcPacking);
1860      const GLchan *src = tempImage;
1861      GLint img, row, col;
1862      if (!tempImage)
1863         return GL_FALSE;
1864      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
1865      for (img = 0; img < srcDepth; img++) {
1866         GLubyte *dstRow = (GLubyte *) dstAddr
1867            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1868            + dstYoffset * dstRowStride
1869            + dstXoffset * dstFormat->TexelBytes;
1870         for (row = 0; row < srcHeight; row++) {
1871            for (col = 0; col < srcWidth; col++) {
1872               dstRow[col] = CHAN_TO_UBYTE(src[col]);
1873            }
1874            dstRow += dstRowStride;
1875            src += srcWidth;
1876         }
1877      }
1878      _mesa_free((void *) tempImage);
1879   }
1880   return GL_TRUE;
1881}
1882
1883
1884
1885GLboolean
1886_mesa_texstore_ci8(TEXSTORE_PARAMS)
1887{
1888   (void) dims; (void) baseInternalFormat;
1889   ASSERT(dstFormat == &_mesa_texformat_ci8);
1890   ASSERT(dstFormat->TexelBytes == 1);
1891   ASSERT(baseInternalFormat == GL_COLOR_INDEX);
1892
1893   if (!ctx->_ImageTransferState &&
1894       !srcPacking->SwapBytes &&
1895       srcFormat == GL_COLOR_INDEX &&
1896       srcType == GL_UNSIGNED_BYTE) {
1897      /* simple memcpy path */
1898      memcpy_texture(ctx, dims,
1899                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1900                     dstRowStride,
1901                     dstImageOffsets,
1902                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1903                     srcAddr, srcPacking);
1904   }
1905   else {
1906      /* general path */
1907      GLint img, row;
1908      for (img = 0; img < srcDepth; img++) {
1909         GLubyte *dstRow = (GLubyte *) dstAddr
1910            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1911            + dstYoffset * dstRowStride
1912            + dstXoffset * dstFormat->TexelBytes;
1913         for (row = 0; row < srcHeight; row++) {
1914            const GLvoid *src = _mesa_image_address(dims, srcPacking,
1915                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
1916            _mesa_unpack_index_span(ctx, srcWidth, GL_UNSIGNED_BYTE, dstRow,
1917                                    srcType, src, srcPacking,
1918                                    ctx->_ImageTransferState);
1919            dstRow += dstRowStride;
1920         }
1921      }
1922   }
1923   return GL_TRUE;
1924}
1925
1926
1927/**
1928 * Texstore for _mesa_texformat_ycbcr or _mesa_texformat_ycbcr_rev.
1929 */
1930GLboolean
1931_mesa_texstore_ycbcr(TEXSTORE_PARAMS)
1932{
1933   const GLuint ui = 1;
1934   const GLubyte littleEndian = *((const GLubyte *) &ui);
1935   (void) ctx; (void) dims; (void) baseInternalFormat;
1936
1937   ASSERT((dstFormat == &_mesa_texformat_ycbcr) ||
1938          (dstFormat == &_mesa_texformat_ycbcr_rev));
1939   ASSERT(dstFormat->TexelBytes == 2);
1940   ASSERT(ctx->Extensions.MESA_ycbcr_texture);
1941   ASSERT(srcFormat == GL_YCBCR_MESA);
1942   ASSERT((srcType == GL_UNSIGNED_SHORT_8_8_MESA) ||
1943          (srcType == GL_UNSIGNED_SHORT_8_8_REV_MESA));
1944   ASSERT(baseInternalFormat == GL_YCBCR_MESA);
1945
1946   /* always just memcpy since no pixel transfer ops apply */
1947   memcpy_texture(ctx, dims,
1948                  dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1949                  dstRowStride,
1950                  dstImageOffsets,
1951                  srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1952                  srcAddr, srcPacking);
1953
1954   /* Check if we need byte swapping */
1955   /* XXX the logic here _might_ be wrong */
1956   if (srcPacking->SwapBytes ^
1957       (srcType == GL_UNSIGNED_SHORT_8_8_REV_MESA) ^
1958       (dstFormat == &_mesa_texformat_ycbcr_rev) ^
1959       !littleEndian) {
1960      GLint img, row;
1961      for (img = 0; img < srcDepth; img++) {
1962         GLubyte *dstRow = (GLubyte *) dstAddr
1963            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
1964            + dstYoffset * dstRowStride
1965            + dstXoffset * dstFormat->TexelBytes;
1966         for (row = 0; row < srcHeight; row++) {
1967            _mesa_swap2((GLushort *) dstRow, srcWidth);
1968            dstRow += dstRowStride;
1969         }
1970      }
1971   }
1972   return GL_TRUE;
1973}
1974
1975
1976
1977/**
1978 * Store a combined depth/stencil texture image.
1979 */
1980GLboolean
1981_mesa_texstore_z24_s8(TEXSTORE_PARAMS)
1982{
1983   ASSERT(dstFormat == &_mesa_texformat_z24_s8);
1984   ASSERT(srcFormat == GL_DEPTH_STENCIL_EXT);
1985   ASSERT(srcType == GL_UNSIGNED_INT_24_8_EXT);
1986
1987   if (!ctx->_ImageTransferState &&
1988       !srcPacking->SwapBytes) {
1989      /* simple path */
1990      memcpy_texture(ctx, dims,
1991                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
1992                     dstRowStride,
1993                     dstImageOffsets,
1994                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
1995                     srcAddr, srcPacking);
1996   }
1997   else {
1998      /* general path */
1999      const GLint srcRowStride
2000         = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType)
2001         / sizeof(GLuint);
2002      GLint img, row;
2003
2004      for (img = 0; img < srcDepth; img++) {
2005         GLuint *dstRow = (GLuint *) dstAddr
2006            + dstImageOffsets[dstZoffset + img]
2007            + dstYoffset * dstRowStride / sizeof(GLuint)
2008            + dstXoffset;
2009         const GLuint *src
2010            = (const GLuint *) _mesa_image_address(dims, srcPacking, srcAddr,
2011                                                   srcWidth, srcHeight,
2012                                                   srcFormat, srcType,
2013                                                   img, 0, 0);
2014         for (row = 0; row < srcHeight; row++) {
2015            GLubyte stencil[MAX_WIDTH];
2016            GLint i;
2017            /* the 24 depth bits will be in the high position: */
2018            _mesa_unpack_depth_span(ctx, srcWidth,
2019                                    GL_UNSIGNED_INT, /* dst type */
2020                                    dstRow, /* dst addr */
2021                                    (GLfloat) 0xffffff, /* depthScale */
2022                                    srcType, src, srcPacking);
2023            /* get the 8-bit stencil values */
2024            _mesa_unpack_stencil_span(ctx, srcWidth,
2025                                      GL_UNSIGNED_BYTE, /* dst type */
2026                                      stencil, /* dst addr */
2027                                      srcType, src, srcPacking,
2028                                      ctx->_ImageTransferState);
2029            /* merge stencil values into depth values */
2030            for (i = 0; i < srcWidth; i++)
2031               dstRow[i] |= stencil[i];
2032
2033            src += srcRowStride;
2034            dstRow += dstRowStride / sizeof(GLuint);
2035         }
2036      }
2037   }
2038   return GL_TRUE;
2039}
2040
2041
2042
2043/**
2044 * Store an image in any of the formats:
2045 *   _mesa_texformat_rgba_float32
2046 *   _mesa_texformat_rgb_float32
2047 *   _mesa_texformat_alpha_float32
2048 *   _mesa_texformat_luminance_float32
2049 *   _mesa_texformat_luminance_alpha_float32
2050 *   _mesa_texformat_intensity_float32
2051 */
2052GLboolean
2053_mesa_texstore_rgba_float32(TEXSTORE_PARAMS)
2054{
2055   const GLint components = _mesa_components_in_format(dstFormat->BaseFormat);
2056
2057   ASSERT(dstFormat == &_mesa_texformat_rgba_float32 ||
2058          dstFormat == &_mesa_texformat_rgb_float32 ||
2059          dstFormat == &_mesa_texformat_alpha_float32 ||
2060          dstFormat == &_mesa_texformat_luminance_float32 ||
2061          dstFormat == &_mesa_texformat_luminance_alpha_float32 ||
2062          dstFormat == &_mesa_texformat_intensity_float32);
2063   ASSERT(baseInternalFormat == GL_RGBA ||
2064          baseInternalFormat == GL_RGB ||
2065          baseInternalFormat == GL_ALPHA ||
2066          baseInternalFormat == GL_LUMINANCE ||
2067          baseInternalFormat == GL_LUMINANCE_ALPHA ||
2068          baseInternalFormat == GL_INTENSITY);
2069   ASSERT(dstFormat->TexelBytes == components * sizeof(GLfloat));
2070
2071   if (!ctx->_ImageTransferState &&
2072       !srcPacking->SwapBytes &&
2073       baseInternalFormat == srcFormat &&
2074       srcType == GL_FLOAT) {
2075      /* simple memcpy path */
2076      memcpy_texture(ctx, dims,
2077                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
2078                     dstRowStride,
2079                     dstImageOffsets,
2080                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
2081                     srcAddr, srcPacking);
2082   }
2083   else {
2084      /* general path */
2085      const GLfloat *tempImage = make_temp_float_image(ctx, dims,
2086                                                 baseInternalFormat,
2087                                                 dstFormat->BaseFormat,
2088                                                 srcWidth, srcHeight, srcDepth,
2089                                                 srcFormat, srcType, srcAddr,
2090                                                 srcPacking);
2091      const GLfloat *srcRow = tempImage;
2092      GLint bytesPerRow;
2093      GLint img, row;
2094      if (!tempImage)
2095         return GL_FALSE;
2096      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
2097      bytesPerRow = srcWidth * components * sizeof(GLfloat);
2098      for (img = 0; img < srcDepth; img++) {
2099         GLubyte *dstRow = (GLubyte *) dstAddr
2100            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
2101            + dstYoffset * dstRowStride
2102            + dstXoffset * dstFormat->TexelBytes;
2103         for (row = 0; row < srcHeight; row++) {
2104            _mesa_memcpy(dstRow, srcRow, bytesPerRow);
2105            dstRow += dstRowStride;
2106            srcRow += srcWidth * components;
2107         }
2108      }
2109
2110      _mesa_free((void *) tempImage);
2111   }
2112   return GL_TRUE;
2113}
2114
2115
2116/**
2117 * As above, but store 16-bit floats.
2118 */
2119GLboolean
2120_mesa_texstore_rgba_float16(TEXSTORE_PARAMS)
2121{
2122   const GLint components = _mesa_components_in_format(dstFormat->BaseFormat);
2123
2124   ASSERT(dstFormat == &_mesa_texformat_rgba_float16 ||
2125          dstFormat == &_mesa_texformat_rgb_float16 ||
2126          dstFormat == &_mesa_texformat_alpha_float16 ||
2127          dstFormat == &_mesa_texformat_luminance_float16 ||
2128          dstFormat == &_mesa_texformat_luminance_alpha_float16 ||
2129          dstFormat == &_mesa_texformat_intensity_float16);
2130   ASSERT(baseInternalFormat == GL_RGBA ||
2131          baseInternalFormat == GL_RGB ||
2132          baseInternalFormat == GL_ALPHA ||
2133          baseInternalFormat == GL_LUMINANCE ||
2134          baseInternalFormat == GL_LUMINANCE_ALPHA ||
2135          baseInternalFormat == GL_INTENSITY);
2136   ASSERT(dstFormat->TexelBytes == components * sizeof(GLhalfARB));
2137
2138   if (!ctx->_ImageTransferState &&
2139       !srcPacking->SwapBytes &&
2140       baseInternalFormat == srcFormat &&
2141       srcType == GL_HALF_FLOAT_ARB) {
2142      /* simple memcpy path */
2143      memcpy_texture(ctx, dims,
2144                     dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset,
2145                     dstRowStride,
2146                     dstImageOffsets,
2147                     srcWidth, srcHeight, srcDepth, srcFormat, srcType,
2148                     srcAddr, srcPacking);
2149   }
2150   else {
2151      /* general path */
2152      const GLfloat *tempImage = make_temp_float_image(ctx, dims,
2153                                                 baseInternalFormat,
2154                                                 dstFormat->BaseFormat,
2155                                                 srcWidth, srcHeight, srcDepth,
2156                                                 srcFormat, srcType, srcAddr,
2157                                                 srcPacking);
2158      const GLfloat *src = tempImage;
2159      GLint img, row;
2160      if (!tempImage)
2161         return GL_FALSE;
2162      _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
2163      for (img = 0; img < srcDepth; img++) {
2164         GLubyte *dstRow = (GLubyte *) dstAddr
2165            + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
2166            + dstYoffset * dstRowStride
2167            + dstXoffset * dstFormat->TexelBytes;
2168         for (row = 0; row < srcHeight; row++) {
2169            GLhalfARB *dstTexel = (GLhalfARB *) dstRow;
2170            GLint i;
2171            for (i = 0; i < srcWidth * components; i++) {
2172               dstTexel[i] = _mesa_float_to_half(src[i]);
2173            }
2174            dstRow += dstRowStride;
2175            src += srcWidth * components;
2176         }
2177      }
2178
2179      _mesa_free((void *) tempImage);
2180   }
2181   return GL_TRUE;
2182}
2183
2184
2185#if FEATURE_EXT_texture_sRGB
2186GLboolean
2187_mesa_texstore_srgb8(TEXSTORE_PARAMS)
2188{
2189   const GLuint ui = 1;
2190   const GLubyte littleEndian = *((const GLubyte *) &ui);
2191   const struct gl_texture_format *newDstFormat;
2192   StoreTexImageFunc store;
2193   GLboolean k;
2194
2195   ASSERT(dstFormat == &_mesa_texformat_srgb8);
2196
2197   /* reuse normal rgb texstore code */
2198   if (littleEndian) {
2199      newDstFormat = &_mesa_texformat_bgr888;
2200      store = _mesa_texstore_bgr888;
2201   }
2202   else {
2203      newDstFormat = &_mesa_texformat_rgb888;
2204      store = _mesa_texstore_rgb888;
2205   }
2206
2207   k = store(ctx, dims, baseInternalFormat,
2208             newDstFormat, dstAddr,
2209             dstXoffset, dstYoffset, dstZoffset,
2210             dstRowStride, dstImageOffsets,
2211             srcWidth, srcHeight, srcDepth,
2212             srcFormat, srcType,
2213             srcAddr, srcPacking);
2214   return k;
2215}
2216
2217
2218GLboolean
2219_mesa_texstore_srgba8(TEXSTORE_PARAMS)
2220{
2221   const GLuint ui = 1;
2222   const GLubyte littleEndian = *((const GLubyte *) &ui);
2223   const struct gl_texture_format *newDstFormat;
2224   GLboolean k;
2225
2226   ASSERT(dstFormat == &_mesa_texformat_srgba8);
2227
2228   /* reuse normal rgba texstore code */
2229   if (littleEndian)
2230      newDstFormat = &_mesa_texformat_rgba8888_rev;
2231   else
2232      newDstFormat = &_mesa_texformat_rgba8888;
2233
2234   k = _mesa_texstore_rgba8888(ctx, dims, baseInternalFormat,
2235                               newDstFormat, dstAddr,
2236                               dstXoffset, dstYoffset, dstZoffset,
2237                               dstRowStride, dstImageOffsets,
2238                               srcWidth, srcHeight, srcDepth,
2239                               srcFormat, srcType,
2240                               srcAddr, srcPacking);
2241   return k;
2242}
2243
2244
2245GLboolean
2246_mesa_texstore_sl8(TEXSTORE_PARAMS)
2247{
2248   const struct gl_texture_format *newDstFormat;
2249   GLboolean k;
2250
2251   ASSERT(dstFormat == &_mesa_texformat_sl8);
2252
2253   newDstFormat = &_mesa_texformat_l8;
2254
2255   /* _mesa_textore_a8 handles luminance8 too */
2256   k = _mesa_texstore_a8(ctx, dims, baseInternalFormat,
2257                         newDstFormat, dstAddr,
2258                         dstXoffset, dstYoffset, dstZoffset,
2259                         dstRowStride, dstImageOffsets,
2260                         srcWidth, srcHeight, srcDepth,
2261                         srcFormat, srcType,
2262                         srcAddr, srcPacking);
2263   return k;
2264}
2265
2266
2267GLboolean
2268_mesa_texstore_sla8(TEXSTORE_PARAMS)
2269{
2270   const GLuint ui = 1;
2271   const GLubyte littleEndian = *((const GLubyte *) &ui);
2272   const struct gl_texture_format *newDstFormat;
2273   GLboolean k;
2274
2275   ASSERT(dstFormat == &_mesa_texformat_sla8);
2276
2277   /* reuse normal luminance/alpha texstore code */
2278   if (littleEndian)
2279      newDstFormat = &_mesa_texformat_al88;
2280   else
2281      newDstFormat = &_mesa_texformat_al88_rev;
2282
2283   k = _mesa_texstore_al88(ctx, dims, baseInternalFormat,
2284                           newDstFormat, dstAddr,
2285                           dstXoffset, dstYoffset, dstZoffset,
2286                           dstRowStride, dstImageOffsets,
2287                           srcWidth, srcHeight, srcDepth,
2288                           srcFormat, srcType,
2289                           srcAddr, srcPacking);
2290   return k;
2291}
2292
2293#endif /* FEATURE_EXT_texture_sRGB */
2294
2295
2296/**
2297 * Check if an unpack PBO is active prior to fetching a texture image.
2298 * If so, do bounds checking and map the buffer into main memory.
2299 * Any errors detected will be recorded.
2300 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
2301 */
2302const GLvoid *
2303_mesa_validate_pbo_teximage(GLcontext *ctx, GLuint dimensions,
2304			    GLsizei width, GLsizei height, GLsizei depth,
2305			    GLenum format, GLenum type, const GLvoid *pixels,
2306			    const struct gl_pixelstore_attrib *unpack,
2307			    const char *funcName)
2308{
2309   GLubyte *buf;
2310
2311   if (unpack->BufferObj->Name == 0) {
2312      /* no PBO */
2313      return pixels;
2314   }
2315   if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth,
2316                                  format, type, pixels)) {
2317      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access");
2318      return NULL;
2319   }
2320
2321   buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
2322                                          GL_READ_ONLY_ARB, unpack->BufferObj);
2323   if (!buf) {
2324      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped");
2325      return NULL;
2326   }
2327
2328   return ADD_POINTERS(buf, pixels);
2329}
2330
2331
2332/**
2333 * Check if an unpack PBO is active prior to fetching a compressed texture
2334 * image.
2335 * If so, do bounds checking and map the buffer into main memory.
2336 * Any errors detected will be recorded.
2337 * The caller _must_ call _mesa_unmap_teximage_pbo() too!
2338 */
2339const GLvoid *
2340_mesa_validate_pbo_compressed_teximage(GLcontext *ctx,
2341                                 GLsizei imageSize, const GLvoid *pixels,
2342                                 const struct gl_pixelstore_attrib *packing,
2343                                 const char *funcName)
2344{
2345   GLubyte *buf;
2346
2347   if (packing->BufferObj->Name == 0) {
2348      /* not using a PBO - return pointer unchanged */
2349      return pixels;
2350   }
2351   if ((const GLubyte *) pixels + imageSize >
2352       ((const GLubyte *) 0) + packing->BufferObj->Size) {
2353      /* out of bounds read! */
2354      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access");
2355      return NULL;
2356   }
2357
2358   buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
2359                                         GL_READ_ONLY_ARB, packing->BufferObj);
2360   if (!buf) {
2361      _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped");
2362      return NULL;
2363   }
2364
2365   return ADD_POINTERS(buf, pixels);
2366}
2367
2368
2369/**
2370 * This function must be called after either of the validate_pbo_*_teximage()
2371 * functions.  It unmaps the PBO buffer if it was mapped earlier.
2372 */
2373void
2374_mesa_unmap_teximage_pbo(GLcontext *ctx,
2375                         const struct gl_pixelstore_attrib *unpack)
2376{
2377   if (unpack->BufferObj->Name) {
2378      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
2379                              unpack->BufferObj);
2380   }
2381}
2382
2383
2384
2385/**
2386 * Adaptor for fetching a GLchan texel from a float-valued texture.
2387 */
2388static void
2389FetchTexelFloatToChan( const struct gl_texture_image *texImage,
2390                       GLint i, GLint j, GLint k, GLchan *texelOut )
2391{
2392   GLfloat temp[4];
2393   ASSERT(texImage->FetchTexelf);
2394   texImage->FetchTexelf(texImage, i, j, k, temp);
2395   if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT ||
2396       texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) {
2397      /* just one channel */
2398      UNCLAMPED_FLOAT_TO_CHAN(texelOut[0], temp[0]);
2399   }
2400   else {
2401      /* four channels */
2402      UNCLAMPED_FLOAT_TO_CHAN(texelOut[0], temp[0]);
2403      UNCLAMPED_FLOAT_TO_CHAN(texelOut[1], temp[1]);
2404      UNCLAMPED_FLOAT_TO_CHAN(texelOut[2], temp[2]);
2405      UNCLAMPED_FLOAT_TO_CHAN(texelOut[3], temp[3]);
2406   }
2407}
2408
2409
2410/**
2411 * Adaptor for fetching a float texel from a GLchan-valued texture.
2412 */
2413static void
2414FetchTexelChanToFloat( const struct gl_texture_image *texImage,
2415                       GLint i, GLint j, GLint k, GLfloat *texelOut )
2416{
2417   GLchan temp[4];
2418   ASSERT(texImage->FetchTexelc);
2419   texImage->FetchTexelc(texImage, i, j, k, temp);
2420   if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT ||
2421       texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) {
2422      /* just one channel */
2423      texelOut[0] = CHAN_TO_FLOAT(temp[0]);
2424   }
2425   else {
2426      /* four channels */
2427      texelOut[0] = CHAN_TO_FLOAT(temp[0]);
2428      texelOut[1] = CHAN_TO_FLOAT(temp[1]);
2429      texelOut[2] = CHAN_TO_FLOAT(temp[2]);
2430      texelOut[3] = CHAN_TO_FLOAT(temp[3]);
2431   }
2432}
2433
2434
2435/**
2436 * Initialize the texture image's FetchTexelc and FetchTexelf methods.
2437 */
2438static void
2439set_fetch_functions(struct gl_texture_image *texImage, GLuint dims)
2440{
2441   ASSERT(dims == 1 || dims == 2 || dims == 3);
2442   ASSERT(texImage->TexFormat);
2443
2444   switch (dims) {
2445   case 1:
2446      texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D;
2447      texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df;
2448      break;
2449   case 2:
2450      texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
2451      texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
2452      break;
2453   case 3:
2454      texImage->FetchTexelc = texImage->TexFormat->FetchTexel3D;
2455      texImage->FetchTexelf = texImage->TexFormat->FetchTexel3Df;
2456      break;
2457   default:
2458      ;
2459   }
2460
2461   /* now check if we need to use a float/chan adaptor */
2462   if (!texImage->FetchTexelc) {
2463      texImage->FetchTexelc = FetchTexelFloatToChan;
2464   }
2465   else if (!texImage->FetchTexelf) {
2466      texImage->FetchTexelf = FetchTexelChanToFloat;
2467   }
2468
2469
2470   ASSERT(texImage->FetchTexelc);
2471   ASSERT(texImage->FetchTexelf);
2472}
2473
2474
2475/**
2476 * Choose the actual storage format for a new texture image.
2477 * Mainly, this is a wrapper for the driver's ChooseTextureFormat() function.
2478 * Also set some other texImage fields related to texture compression, etc.
2479 * \param ctx  rendering context
2480 * \param texImage  the gl_texture_image
2481 * \param dims  texture dimensions (1, 2 or 3)
2482 * \param format  the user-specified format parameter
2483 * \param type  the user-specified type parameter
2484 * \param internalFormat  the user-specified internal format hint
2485 */
2486static void
2487choose_texture_format(GLcontext *ctx, struct gl_texture_image *texImage,
2488                      GLuint dims,
2489                      GLenum format, GLenum type, GLint internalFormat)
2490{
2491   ASSERT(dims == 1 || dims == 2 || dims == 3);
2492   ASSERT(ctx->Driver.ChooseTextureFormat);
2493
2494   texImage->TexFormat
2495      = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, format, type);
2496
2497   ASSERT(texImage->TexFormat);
2498
2499   set_fetch_functions(texImage, dims);
2500
2501   if (texImage->TexFormat->TexelBytes == 0) {
2502      /* must be a compressed format */
2503      texImage->IsCompressed = GL_TRUE;
2504      texImage->CompressedSize =
2505         ctx->Driver.CompressedTextureSize(ctx, texImage->Width,
2506                                           texImage->Height, texImage->Depth,
2507                                           texImage->TexFormat->MesaFormat);
2508   }
2509   else {
2510      /* non-compressed format */
2511      texImage->IsCompressed = GL_FALSE;
2512      texImage->CompressedSize = 0;
2513   }
2514}
2515
2516
2517
2518/*
2519 * This is the software fallback for Driver.TexImage1D()
2520 * and Driver.CopyTexImage1D().
2521 * \sa _mesa_store_teximage2d()
2522 */
2523void
2524_mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
2525                       GLint internalFormat,
2526                       GLint width, GLint border,
2527                       GLenum format, GLenum type, const GLvoid *pixels,
2528                       const struct gl_pixelstore_attrib *packing,
2529                       struct gl_texture_object *texObj,
2530                       struct gl_texture_image *texImage)
2531{
2532   GLint postConvWidth = width;
2533   GLint sizeInBytes;
2534   (void) border;
2535
2536   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
2537      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
2538   }
2539
2540   choose_texture_format(ctx, texImage, 1, format, type, internalFormat);
2541
2542   /* allocate memory */
2543   if (texImage->IsCompressed)
2544      sizeInBytes = texImage->CompressedSize;
2545   else
2546      sizeInBytes = postConvWidth * texImage->TexFormat->TexelBytes;
2547   texImage->Data = _mesa_alloc_texmemory(sizeInBytes);
2548   if (!texImage->Data) {
2549      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
2550      return;
2551   }
2552
2553   pixels = _mesa_validate_pbo_teximage(ctx, 1, width, 1, 1, format, type,
2554                                        pixels, packing, "glTexImage1D");
2555   if (!pixels) {
2556      /* Note: we check for a NULL image pointer here, _after_ we allocated
2557       * memory for the texture.  That's what the GL spec calls for.
2558       */
2559      return;
2560   }
2561   else {
2562      const GLint dstRowStride = 0;
2563      GLboolean success;
2564      ASSERT(texImage->TexFormat->StoreImage);
2565      success = texImage->TexFormat->StoreImage(ctx, 1, texImage->_BaseFormat,
2566                                                texImage->TexFormat,
2567                                                texImage->Data,
2568                                                0, 0, 0,  /* dstX/Y/Zoffset */
2569                                                dstRowStride,
2570                                                texImage->ImageOffsets,
2571                                                width, 1, 1,
2572                                                format, type, pixels, packing);
2573      if (!success) {
2574         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
2575      }
2576   }
2577
2578   /* GL_SGIS_generate_mipmap */
2579   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2580      _mesa_generate_mipmap(ctx, target,
2581                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2582                            texObj);
2583   }
2584
2585   _mesa_unmap_teximage_pbo(ctx, packing);
2586}
2587
2588
2589/**
2590 * This is the software fallback for Driver.TexImage2D()
2591 * and Driver.CopyTexImage2D().
2592 *
2593 * This function is oriented toward storing images in main memory, rather
2594 * than VRAM.  Device driver's can easily plug in their own replacement.
2595 *
2596 * Note: width and height may be pre-convolved dimensions, but
2597 * texImage->Width and texImage->Height will be post-convolved dimensions.
2598 */
2599void
2600_mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
2601                       GLint internalFormat,
2602                       GLint width, GLint height, GLint border,
2603                       GLenum format, GLenum type, const void *pixels,
2604                       const struct gl_pixelstore_attrib *packing,
2605                       struct gl_texture_object *texObj,
2606                       struct gl_texture_image *texImage)
2607{
2608   GLint postConvWidth = width, postConvHeight = height;
2609   GLint texelBytes, sizeInBytes;
2610   (void) border;
2611
2612   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
2613      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
2614                                         &postConvHeight);
2615   }
2616
2617   choose_texture_format(ctx, texImage, 2, format, type, internalFormat);
2618
2619   texelBytes = texImage->TexFormat->TexelBytes;
2620
2621   /* allocate memory */
2622   if (texImage->IsCompressed)
2623      sizeInBytes = texImage->CompressedSize;
2624   else
2625      sizeInBytes = postConvWidth * postConvHeight * texelBytes;
2626   texImage->Data = _mesa_alloc_texmemory(sizeInBytes);
2627   if (!texImage->Data) {
2628      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
2629      return;
2630   }
2631
2632   pixels = _mesa_validate_pbo_teximage(ctx, 2, width, height, 1, format, type,
2633                                        pixels, packing, "glTexImage2D");
2634   if (!pixels) {
2635      /* Note: we check for a NULL image pointer here, _after_ we allocated
2636       * memory for the texture.  That's what the GL spec calls for.
2637       */
2638      return;
2639   }
2640   else {
2641      GLint dstRowStride;
2642      GLboolean success;
2643      if (texImage->IsCompressed) {
2644         dstRowStride
2645            = _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat, width);
2646      }
2647      else {
2648         dstRowStride = texImage->RowStride * texImage->TexFormat->TexelBytes;
2649      }
2650      ASSERT(texImage->TexFormat->StoreImage);
2651      success = texImage->TexFormat->StoreImage(ctx, 2, texImage->_BaseFormat,
2652                                                texImage->TexFormat,
2653                                                texImage->Data,
2654                                                0, 0, 0,  /* dstX/Y/Zoffset */
2655                                                dstRowStride,
2656                                                texImage->ImageOffsets,
2657                                                width, height, 1,
2658                                                format, type, pixels, packing);
2659      if (!success) {
2660         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
2661      }
2662   }
2663
2664   /* GL_SGIS_generate_mipmap */
2665   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2666      _mesa_generate_mipmap(ctx, target,
2667                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2668                            texObj);
2669   }
2670
2671   _mesa_unmap_teximage_pbo(ctx, packing);
2672}
2673
2674
2675
2676/**
2677 * This is the software fallback for Driver.TexImage3D()
2678 * and Driver.CopyTexImage3D().
2679 * \sa _mesa_store_teximage2d()
2680 */
2681void
2682_mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
2683                       GLint internalFormat,
2684                       GLint width, GLint height, GLint depth, GLint border,
2685                       GLenum format, GLenum type, const void *pixels,
2686                       const struct gl_pixelstore_attrib *packing,
2687                       struct gl_texture_object *texObj,
2688                       struct gl_texture_image *texImage)
2689{
2690   GLint texelBytes, sizeInBytes;
2691   (void) border;
2692
2693   choose_texture_format(ctx, texImage, 3, format, type, internalFormat);
2694
2695   texelBytes = texImage->TexFormat->TexelBytes;
2696
2697   /* allocate memory */
2698   if (texImage->IsCompressed)
2699      sizeInBytes = texImage->CompressedSize;
2700   else
2701      sizeInBytes = width * height * depth * texelBytes;
2702   texImage->Data = _mesa_alloc_texmemory(sizeInBytes);
2703   if (!texImage->Data) {
2704      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
2705      return;
2706   }
2707
2708   pixels = _mesa_validate_pbo_teximage(ctx, 3, width, height, depth, format,
2709                                        type, pixels, packing, "glTexImage3D");
2710   if (!pixels) {
2711      /* Note: we check for a NULL image pointer here, _after_ we allocated
2712       * memory for the texture.  That's what the GL spec calls for.
2713       */
2714      return;
2715   }
2716   else {
2717      GLint dstRowStride;
2718      GLboolean success;
2719      if (texImage->IsCompressed) {
2720         dstRowStride
2721            = _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat, width);
2722      }
2723      else {
2724         dstRowStride = texImage->RowStride * texImage->TexFormat->TexelBytes;
2725      }
2726      ASSERT(texImage->TexFormat->StoreImage);
2727      success = texImage->TexFormat->StoreImage(ctx, 3, texImage->_BaseFormat,
2728                                                texImage->TexFormat,
2729                                                texImage->Data,
2730                                                0, 0, 0,  /* dstX/Y/Zoffset */
2731                                                dstRowStride,
2732                                                texImage->ImageOffsets,
2733                                                width, height, depth,
2734                                                format, type, pixels, packing);
2735      if (!success) {
2736         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
2737      }
2738   }
2739
2740   /* GL_SGIS_generate_mipmap */
2741   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2742      _mesa_generate_mipmap(ctx, target,
2743                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2744                            texObj);
2745   }
2746
2747   _mesa_unmap_teximage_pbo(ctx, packing);
2748}
2749
2750
2751
2752
2753/*
2754 * This is the software fallback for Driver.TexSubImage1D()
2755 * and Driver.CopyTexSubImage1D().
2756 */
2757void
2758_mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
2759                          GLint xoffset, GLint width,
2760                          GLenum format, GLenum type, const void *pixels,
2761                          const struct gl_pixelstore_attrib *packing,
2762                          struct gl_texture_object *texObj,
2763                          struct gl_texture_image *texImage)
2764{
2765   /* get pointer to src pixels (may be in a pbo which we'll map here) */
2766   pixels = _mesa_validate_pbo_teximage(ctx, 1, width, 1, 1, format, type,
2767                                        pixels, packing, "glTexSubImage1D");
2768   if (!pixels)
2769      return;
2770
2771   {
2772      const GLint dstRowStride = 0;
2773      GLboolean success;
2774      ASSERT(texImage->TexFormat->StoreImage);
2775      success = texImage->TexFormat->StoreImage(ctx, 1, texImage->_BaseFormat,
2776                                                texImage->TexFormat,
2777                                                texImage->Data,
2778                                                xoffset, 0, 0,  /* offsets */
2779                                                dstRowStride,
2780                                                texImage->ImageOffsets,
2781                                                width, 1, 1,
2782                                                format, type, pixels, packing);
2783      if (!success) {
2784         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
2785      }
2786   }
2787
2788   /* GL_SGIS_generate_mipmap */
2789   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2790      _mesa_generate_mipmap(ctx, target,
2791                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2792                            texObj);
2793   }
2794
2795   _mesa_unmap_teximage_pbo(ctx, packing);
2796}
2797
2798
2799
2800/**
2801 * This is the software fallback for Driver.TexSubImage2D()
2802 * and Driver.CopyTexSubImage2D().
2803 */
2804void
2805_mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
2806                          GLint xoffset, GLint yoffset,
2807                          GLint width, GLint height,
2808                          GLenum format, GLenum type, const void *pixels,
2809                          const struct gl_pixelstore_attrib *packing,
2810                          struct gl_texture_object *texObj,
2811                          struct gl_texture_image *texImage)
2812{
2813   /* get pointer to src pixels (may be in a pbo which we'll map here) */
2814   pixels = _mesa_validate_pbo_teximage(ctx, 2, width, height, 1, format, type,
2815                                        pixels, packing, "glTexSubImage2D");
2816   if (!pixels)
2817      return;
2818
2819   {
2820      GLint dstRowStride = 0;
2821      GLboolean success;
2822      if (texImage->IsCompressed) {
2823         dstRowStride = _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat,
2824                                                    texImage->Width);
2825      }
2826      else {
2827         dstRowStride = texImage->RowStride * texImage->TexFormat->TexelBytes;
2828      }
2829      ASSERT(texImage->TexFormat->StoreImage);
2830      success = texImage->TexFormat->StoreImage(ctx, 2, texImage->_BaseFormat,
2831                                                texImage->TexFormat,
2832                                                texImage->Data,
2833                                                xoffset, yoffset, 0,
2834                                                dstRowStride,
2835                                                texImage->ImageOffsets,
2836                                                width, height, 1,
2837                                                format, type, pixels, packing);
2838      if (!success) {
2839         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
2840      }
2841   }
2842
2843   /* GL_SGIS_generate_mipmap */
2844   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2845      _mesa_generate_mipmap(ctx, target,
2846                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2847                            texObj);
2848   }
2849
2850   _mesa_unmap_teximage_pbo(ctx, packing);
2851}
2852
2853
2854/*
2855 * This is the software fallback for Driver.TexSubImage3D().
2856 * and Driver.CopyTexSubImage3D().
2857 */
2858void
2859_mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
2860                          GLint xoffset, GLint yoffset, GLint zoffset,
2861                          GLint width, GLint height, GLint depth,
2862                          GLenum format, GLenum type, const void *pixels,
2863                          const struct gl_pixelstore_attrib *packing,
2864                          struct gl_texture_object *texObj,
2865                          struct gl_texture_image *texImage)
2866{
2867   /* get pointer to src pixels (may be in a pbo which we'll map here) */
2868   pixels = _mesa_validate_pbo_teximage(ctx, 3, width, height, depth, format,
2869                                        type, pixels, packing,
2870                                        "glTexSubImage3D");
2871   if (!pixels)
2872      return;
2873
2874   {
2875      GLint dstRowStride;
2876      GLboolean success;
2877      if (texImage->IsCompressed) {
2878         dstRowStride = _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat,
2879                                                    texImage->Width);
2880      }
2881      else {
2882         dstRowStride = texImage->RowStride * texImage->TexFormat->TexelBytes;
2883      }
2884      ASSERT(texImage->TexFormat->StoreImage);
2885      success = texImage->TexFormat->StoreImage(ctx, 3, texImage->_BaseFormat,
2886                                                texImage->TexFormat,
2887                                                texImage->Data,
2888                                                xoffset, yoffset, zoffset,
2889                                                dstRowStride,
2890                                                texImage->ImageOffsets,
2891                                                width, height, depth,
2892                                                format, type, pixels, packing);
2893      if (!success) {
2894         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage3D");
2895      }
2896   }
2897
2898   /* GL_SGIS_generate_mipmap */
2899   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2900      _mesa_generate_mipmap(ctx, target,
2901                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2902                            texObj);
2903   }
2904
2905   _mesa_unmap_teximage_pbo(ctx, packing);
2906}
2907
2908
2909/*
2910 * Fallback for Driver.CompressedTexImage1D()
2911 */
2912void
2913_mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level,
2914                                  GLint internalFormat,
2915                                  GLint width, GLint border,
2916                                  GLsizei imageSize, const GLvoid *data,
2917                                  struct gl_texture_object *texObj,
2918                                  struct gl_texture_image *texImage)
2919{
2920   /* this space intentionally left blank */
2921   (void) ctx;
2922   (void) target; (void) level;
2923   (void) internalFormat;
2924   (void) width; (void) border;
2925   (void) imageSize; (void) data;
2926   (void) texObj;
2927   (void) texImage;
2928}
2929
2930
2931
2932/**
2933 * Fallback for Driver.CompressedTexImage2D()
2934 */
2935void
2936_mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level,
2937                                  GLint internalFormat,
2938                                  GLint width, GLint height, GLint border,
2939                                  GLsizei imageSize, const GLvoid *data,
2940                                  struct gl_texture_object *texObj,
2941                                  struct gl_texture_image *texImage)
2942{
2943   (void) width; (void) height; (void) border;
2944
2945   /* This is pretty simple, basically just do a memcpy without worrying
2946    * about the usual image unpacking or image transfer operations.
2947    */
2948   ASSERT(texObj);
2949   ASSERT(texImage);
2950   ASSERT(texImage->Width > 0);
2951   ASSERT(texImage->Height > 0);
2952   ASSERT(texImage->Depth == 1);
2953   ASSERT(texImage->Data == NULL); /* was freed in glCompressedTexImage2DARB */
2954
2955   choose_texture_format(ctx, texImage, 2, 0, 0, internalFormat);
2956
2957   /* allocate storage */
2958   texImage->Data = _mesa_alloc_texmemory(imageSize);
2959   if (!texImage->Data) {
2960      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2DARB");
2961      return;
2962   }
2963
2964   data = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, data,
2965                                                 &ctx->Unpack,
2966                                                 "glCompressedTexImage2D");
2967   if (!data)
2968      return;
2969
2970   /* copy the data */
2971   ASSERT(texImage->CompressedSize == (GLuint) imageSize);
2972   MEMCPY(texImage->Data, data, imageSize);
2973
2974   /* GL_SGIS_generate_mipmap */
2975   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
2976      _mesa_generate_mipmap(ctx, target,
2977                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
2978                            texObj);
2979   }
2980
2981   _mesa_unmap_teximage_pbo(ctx, &ctx->Unpack);
2982}
2983
2984
2985
2986/*
2987 * Fallback for Driver.CompressedTexImage3D()
2988 */
2989void
2990_mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
2991                                  GLint internalFormat,
2992                                  GLint width, GLint height, GLint depth,
2993                                  GLint border,
2994                                  GLsizei imageSize, const GLvoid *data,
2995                                  struct gl_texture_object *texObj,
2996                                  struct gl_texture_image *texImage)
2997{
2998   /* this space intentionally left blank */
2999   (void) ctx;
3000   (void) target; (void) level;
3001   (void) internalFormat;
3002   (void) width; (void) height; (void) depth;
3003   (void) border;
3004   (void) imageSize; (void) data;
3005   (void) texObj;
3006   (void) texImage;
3007}
3008
3009
3010
3011/**
3012 * Fallback for Driver.CompressedTexSubImage1D()
3013 */
3014void
3015_mesa_store_compressed_texsubimage1d(GLcontext *ctx, GLenum target,
3016                                     GLint level,
3017                                     GLint xoffset, GLsizei width,
3018                                     GLenum format,
3019                                     GLsizei imageSize, const GLvoid *data,
3020                                     struct gl_texture_object *texObj,
3021                                     struct gl_texture_image *texImage)
3022{
3023   /* there are no compressed 1D texture formats yet */
3024   (void) ctx;
3025   (void) target; (void) level;
3026   (void) xoffset; (void) width;
3027   (void) format;
3028   (void) imageSize; (void) data;
3029   (void) texObj;
3030   (void) texImage;
3031}
3032
3033
3034/**
3035 * Fallback for Driver.CompressedTexSubImage2D()
3036 */
3037void
3038_mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target,
3039                                     GLint level,
3040                                     GLint xoffset, GLint yoffset,
3041                                     GLsizei width, GLsizei height,
3042                                     GLenum format,
3043                                     GLsizei imageSize, const GLvoid *data,
3044                                     struct gl_texture_object *texObj,
3045                                     struct gl_texture_image *texImage)
3046{
3047   GLint bytesPerRow, destRowStride, srcRowStride;
3048   GLint i, rows;
3049   GLubyte *dest;
3050   const GLubyte *src;
3051   const GLuint mesaFormat = texImage->TexFormat->MesaFormat;
3052
3053   (void) format;
3054
3055   /* these should have been caught sooner */
3056   ASSERT((width & 3) == 0 || width == 2 || width == 1);
3057   ASSERT((height & 3) == 0 || height == 2 || height == 1);
3058   ASSERT((xoffset & 3) == 0);
3059   ASSERT((yoffset & 3) == 0);
3060
3061   /* get pointer to src pixels (may be in a pbo which we'll map here) */
3062   data = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, data,
3063                                                 &ctx->Unpack,
3064                                                 "glCompressedTexSubImage2D");
3065   if (!data)
3066      return;
3067
3068   srcRowStride = _mesa_compressed_row_stride(mesaFormat, width);
3069   src = (const GLubyte *) data;
3070
3071   destRowStride = _mesa_compressed_row_stride(mesaFormat, texImage->Width);
3072   dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
3073                                         texImage->TexFormat->MesaFormat,
3074                                         texImage->Width,
3075                                         (GLubyte *) texImage->Data);
3076
3077   bytesPerRow = srcRowStride;
3078   rows = height / 4;
3079
3080   for (i = 0; i < rows; i++) {
3081      MEMCPY(dest, src, bytesPerRow);
3082      dest += destRowStride;
3083      src += srcRowStride;
3084   }
3085
3086   /* GL_SGIS_generate_mipmap */
3087   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
3088      _mesa_generate_mipmap(ctx, target,
3089                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
3090                            texObj);
3091   }
3092
3093   _mesa_unmap_teximage_pbo(ctx, &ctx->Unpack);
3094}
3095
3096
3097/**
3098 * Fallback for Driver.CompressedTexSubImage3D()
3099 */
3100void
3101_mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target,
3102                                GLint level,
3103                                GLint xoffset, GLint yoffset, GLint zoffset,
3104                                GLsizei width, GLsizei height, GLsizei depth,
3105                                GLenum format,
3106                                GLsizei imageSize, const GLvoid *data,
3107                                struct gl_texture_object *texObj,
3108                                struct gl_texture_image *texImage)
3109{
3110   /* there are no compressed 3D texture formats yet */
3111   (void) ctx;
3112   (void) target; (void) level;
3113   (void) xoffset; (void) yoffset; (void) zoffset;
3114   (void) width; (void) height; (void) depth;
3115   (void) format;
3116   (void) imageSize; (void) data;
3117   (void) texObj;
3118   (void) texImage;
3119}
3120
3121
3122/*
3123 * Average together two rows of a source image to produce a single new
3124 * row in the dest image.  It's legal for the two source rows to point
3125 * to the same data.  The source width must be equal to either the
3126 * dest width or two times the dest width.
3127 */
3128static void
3129do_row(const struct gl_texture_format *format, GLint srcWidth,
3130       const GLvoid *srcRowA, const GLvoid *srcRowB,
3131       GLint dstWidth, GLvoid *dstRow)
3132{
3133   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
3134   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
3135
3136   /* This assertion is no longer valid with non-power-of-2 textures
3137   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
3138   */
3139
3140   switch (format->MesaFormat) {
3141   case MESA_FORMAT_RGBA:
3142      {
3143         GLuint i, j, k;
3144         const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
3145         const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
3146         GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
3147         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3148              i++, j += colStride, k += colStride) {
3149            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3150                         rowB[j][0] + rowB[k][0]) / 4;
3151            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3152                         rowB[j][1] + rowB[k][1]) / 4;
3153            dst[i][2] = (rowA[j][2] + rowA[k][2] +
3154                         rowB[j][2] + rowB[k][2]) / 4;
3155            dst[i][3] = (rowA[j][3] + rowA[k][3] +
3156                         rowB[j][3] + rowB[k][3]) / 4;
3157         }
3158      }
3159      return;
3160   case MESA_FORMAT_RGB:
3161      {
3162         GLuint i, j, k;
3163         const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
3164         const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
3165         GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
3166         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3167              i++, j += colStride, k += colStride) {
3168            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3169                         rowB[j][0] + rowB[k][0]) / 4;
3170            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3171                         rowB[j][1] + rowB[k][1]) / 4;
3172            dst[i][2] = (rowA[j][2] + rowA[k][2] +
3173                         rowB[j][2] + rowB[k][2]) / 4;
3174         }
3175      }
3176      return;
3177   case MESA_FORMAT_ALPHA:
3178   case MESA_FORMAT_LUMINANCE:
3179   case MESA_FORMAT_INTENSITY:
3180      {
3181         GLuint i, j, k;
3182         const GLchan *rowA = (const GLchan *) srcRowA;
3183         const GLchan *rowB = (const GLchan *) srcRowB;
3184         GLchan *dst = (GLchan *) dstRow;
3185         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3186              i++, j += colStride, k += colStride) {
3187            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
3188         }
3189      }
3190      return;
3191   case MESA_FORMAT_LUMINANCE_ALPHA:
3192      {
3193         GLuint i, j, k;
3194         const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
3195         const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
3196         GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
3197         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3198              i++, j += colStride, k += colStride) {
3199            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3200                         rowB[j][0] + rowB[k][0]) / 4;
3201            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3202                         rowB[j][1] + rowB[k][1]) / 4;
3203         }
3204      }
3205      return;
3206   case MESA_FORMAT_Z32:
3207      {
3208         GLuint i, j, k;
3209         const GLuint *rowA = (const GLuint *) srcRowA;
3210         const GLuint *rowB = (const GLuint *) srcRowB;
3211         GLfloat *dst = (GLfloat *) dstRow;
3212         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3213              i++, j += colStride, k += colStride) {
3214            dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
3215         }
3216      }
3217      return;
3218   case MESA_FORMAT_Z16:
3219      {
3220         GLuint i, j, k;
3221         const GLushort *rowA = (const GLushort *) srcRowA;
3222         const GLushort *rowB = (const GLushort *) srcRowB;
3223         GLushort *dst = (GLushort *) dstRow;
3224         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3225              i++, j += colStride, k += colStride) {
3226            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
3227         }
3228      }
3229      return;
3230   /* Begin hardware formats */
3231   case MESA_FORMAT_RGBA8888:
3232   case MESA_FORMAT_RGBA8888_REV:
3233   case MESA_FORMAT_ARGB8888:
3234   case MESA_FORMAT_ARGB8888_REV:
3235#if FEATURE_EXT_texture_sRGB
3236   case MESA_FORMAT_SRGBA8:
3237#endif
3238      {
3239         GLuint i, j, k;
3240         const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
3241         const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
3242         GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
3243         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3244              i++, j += colStride, k += colStride) {
3245            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3246                         rowB[j][0] + rowB[k][0]) / 4;
3247            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3248                         rowB[j][1] + rowB[k][1]) / 4;
3249            dst[i][2] = (rowA[j][2] + rowA[k][2] +
3250                         rowB[j][2] + rowB[k][2]) / 4;
3251            dst[i][3] = (rowA[j][3] + rowA[k][3] +
3252                         rowB[j][3] + rowB[k][3]) / 4;
3253         }
3254      }
3255      return;
3256   case MESA_FORMAT_RGB888:
3257   case MESA_FORMAT_BGR888:
3258#if FEATURE_EXT_texture_sRGB
3259   case MESA_FORMAT_SRGB8:
3260#endif
3261      {
3262         GLuint i, j, k;
3263         const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
3264         const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
3265         GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
3266         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3267              i++, j += colStride, k += colStride) {
3268            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3269                         rowB[j][0] + rowB[k][0]) / 4;
3270            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3271                         rowB[j][1] + rowB[k][1]) / 4;
3272            dst[i][2] = (rowA[j][2] + rowA[k][2] +
3273                         rowB[j][2] + rowB[k][2]) / 4;
3274         }
3275      }
3276      return;
3277   case MESA_FORMAT_RGB565:
3278   case MESA_FORMAT_RGB565_REV:
3279      {
3280         GLuint i, j, k;
3281         const GLushort *rowA = (const GLushort *) srcRowA;
3282         const GLushort *rowB = (const GLushort *) srcRowB;
3283         GLushort *dst = (GLushort *) dstRow;
3284         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3285              i++, j += colStride, k += colStride) {
3286            const GLint rowAr0 = rowA[j] & 0x1f;
3287            const GLint rowAr1 = rowA[k] & 0x1f;
3288            const GLint rowBr0 = rowB[j] & 0x1f;
3289            const GLint rowBr1 = rowB[k] & 0x1f;
3290            const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
3291            const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
3292            const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
3293            const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
3294            const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
3295            const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
3296            const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
3297            const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
3298            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
3299            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
3300            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
3301            dst[i] = (blue << 11) | (green << 5) | red;
3302         }
3303      }
3304      return;
3305   case MESA_FORMAT_ARGB4444:
3306   case MESA_FORMAT_ARGB4444_REV:
3307      {
3308         GLuint i, j, k;
3309         const GLushort *rowA = (const GLushort *) srcRowA;
3310         const GLushort *rowB = (const GLushort *) srcRowB;
3311         GLushort *dst = (GLushort *) dstRow;
3312         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3313              i++, j += colStride, k += colStride) {
3314            const GLint rowAr0 = rowA[j] & 0xf;
3315            const GLint rowAr1 = rowA[k] & 0xf;
3316            const GLint rowBr0 = rowB[j] & 0xf;
3317            const GLint rowBr1 = rowB[k] & 0xf;
3318            const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
3319            const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
3320            const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
3321            const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
3322            const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
3323            const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
3324            const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
3325            const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
3326            const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
3327            const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
3328            const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
3329            const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
3330            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
3331            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
3332            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
3333            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
3334            dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
3335         }
3336      }
3337      return;
3338   case MESA_FORMAT_ARGB1555:
3339   case MESA_FORMAT_ARGB1555_REV: /* XXX broken? */
3340      {
3341         GLuint i, j, k;
3342         const GLushort *rowA = (const GLushort *) srcRowA;
3343         const GLushort *rowB = (const GLushort *) srcRowB;
3344         GLushort *dst = (GLushort *) dstRow;
3345         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3346              i++, j += colStride, k += colStride) {
3347            const GLint rowAr0 = rowA[j] & 0x1f;
3348            const GLint rowAr1 = rowA[k] & 0x1f;
3349            const GLint rowBr0 = rowB[j] & 0x1f;
3350            const GLint rowBr1 = rowB[k] & 0xf;
3351            const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
3352            const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
3353            const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
3354            const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
3355            const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
3356            const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
3357            const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
3358            const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
3359            const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
3360            const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
3361            const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
3362            const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
3363            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
3364            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
3365            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
3366            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
3367            dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
3368         }
3369      }
3370      return;
3371   case MESA_FORMAT_AL88:
3372   case MESA_FORMAT_AL88_REV:
3373#if FEATURE_EXT_texture_sRGB
3374   case MESA_FORMAT_SLA8:
3375#endif
3376      {
3377         GLuint i, j, k;
3378         const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
3379         const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
3380         GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
3381         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3382              i++, j += colStride, k += colStride) {
3383            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3384                         rowB[j][0] + rowB[k][0]) >> 2;
3385            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3386                         rowB[j][1] + rowB[k][1]) >> 2;
3387         }
3388      }
3389      return;
3390   case MESA_FORMAT_RGB332:
3391      {
3392         GLuint i, j, k;
3393         const GLubyte *rowA = (const GLubyte *) srcRowA;
3394         const GLubyte *rowB = (const GLubyte *) srcRowB;
3395         GLubyte *dst = (GLubyte *) dstRow;
3396         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3397              i++, j += colStride, k += colStride) {
3398            const GLint rowAr0 = rowA[j] & 0x3;
3399            const GLint rowAr1 = rowA[k] & 0x3;
3400            const GLint rowBr0 = rowB[j] & 0x3;
3401            const GLint rowBr1 = rowB[k] & 0x3;
3402            const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
3403            const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
3404            const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
3405            const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
3406            const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
3407            const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
3408            const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
3409            const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
3410            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
3411            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
3412            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
3413            dst[i] = (blue << 5) | (green << 2) | red;
3414         }
3415      }
3416      return;
3417   case MESA_FORMAT_A8:
3418   case MESA_FORMAT_L8:
3419   case MESA_FORMAT_I8:
3420   case MESA_FORMAT_CI8:
3421#if FEATURE_EXT_texture_sRGB
3422   case MESA_FORMAT_SL8:
3423#endif
3424      {
3425         GLuint i, j, k;
3426         const GLubyte *rowA = (const GLubyte *) srcRowA;
3427         const GLubyte *rowB = (const GLubyte *) srcRowB;
3428         GLubyte *dst = (GLubyte *) dstRow;
3429         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3430              i++, j += colStride, k += colStride) {
3431            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
3432         }
3433      }
3434      return;
3435   case MESA_FORMAT_RGBA_FLOAT32:
3436      {
3437         GLuint i, j, k;
3438         const GLfloat (*rowA)[4] = (const GLfloat (*)[4]) srcRowA;
3439         const GLfloat (*rowB)[4] = (const GLfloat (*)[4]) srcRowB;
3440         GLfloat (*dst)[4] = (GLfloat (*)[4]) dstRow;
3441         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3442              i++, j += colStride, k += colStride) {
3443            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3444                         rowB[j][0] + rowB[k][0]) * 0.25F;
3445            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3446                         rowB[j][1] + rowB[k][1]) * 0.25F;
3447            dst[i][2] = (rowA[j][2] + rowA[k][2] +
3448                         rowB[j][2] + rowB[k][2]) * 0.25F;
3449            dst[i][3] = (rowA[j][3] + rowA[k][3] +
3450                         rowB[j][3] + rowB[k][3]) * 0.25F;
3451         }
3452      }
3453      return;
3454   case MESA_FORMAT_RGBA_FLOAT16:
3455      {
3456         GLuint i, j, k, comp;
3457         const GLhalfARB (*rowA)[4] = (const GLhalfARB (*)[4]) srcRowA;
3458         const GLhalfARB (*rowB)[4] = (const GLhalfARB (*)[4]) srcRowB;
3459         GLhalfARB (*dst)[4] = (GLhalfARB (*)[4]) dstRow;
3460         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3461              i++, j += colStride, k += colStride) {
3462            for (comp = 0; comp < 4; comp++) {
3463               GLfloat aj, ak, bj, bk;
3464               aj = _mesa_half_to_float(rowA[j][comp]);
3465               ak = _mesa_half_to_float(rowA[k][comp]);
3466               bj = _mesa_half_to_float(rowB[j][comp]);
3467               bk = _mesa_half_to_float(rowB[k][comp]);
3468               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
3469            }
3470         }
3471      }
3472      return;
3473   case MESA_FORMAT_RGB_FLOAT32:
3474      {
3475         GLuint i, j, k;
3476         const GLfloat (*rowA)[3] = (const GLfloat (*)[3]) srcRowA;
3477         const GLfloat (*rowB)[3] = (const GLfloat (*)[3]) srcRowB;
3478         GLfloat (*dst)[3] = (GLfloat (*)[3]) dstRow;
3479         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3480              i++, j += colStride, k += colStride) {
3481            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3482                         rowB[j][0] + rowB[k][0]) * 0.25F;
3483            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3484                         rowB[j][1] + rowB[k][1]) * 0.25F;
3485            dst[i][2] = (rowA[j][2] + rowA[k][2] +
3486                         rowB[j][2] + rowB[k][2]) * 0.25F;
3487         }
3488      }
3489      return;
3490   case MESA_FORMAT_RGB_FLOAT16:
3491      {
3492         GLuint i, j, k, comp;
3493         const GLhalfARB (*rowA)[3] = (const GLhalfARB (*)[3]) srcRowA;
3494         const GLhalfARB (*rowB)[3] = (const GLhalfARB (*)[3]) srcRowB;
3495         GLhalfARB (*dst)[3] = (GLhalfARB (*)[3]) dstRow;
3496         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3497              i++, j += colStride, k += colStride) {
3498            for (comp = 0; comp < 3; comp++) {
3499               GLfloat aj, ak, bj, bk;
3500               aj = _mesa_half_to_float(rowA[j][comp]);
3501               ak = _mesa_half_to_float(rowA[k][comp]);
3502               bj = _mesa_half_to_float(rowB[j][comp]);
3503               bk = _mesa_half_to_float(rowB[k][comp]);
3504               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
3505            }
3506         }
3507      }
3508      return;
3509   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32:
3510      {
3511         GLuint i, j, k;
3512         const GLfloat (*rowA)[2] = (const GLfloat (*)[2]) srcRowA;
3513         const GLfloat (*rowB)[2] = (const GLfloat (*)[2]) srcRowB;
3514         GLfloat (*dst)[2] = (GLfloat (*)[2]) dstRow;
3515         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3516              i++, j += colStride, k += colStride) {
3517            dst[i][0] = (rowA[j][0] + rowA[k][0] +
3518                         rowB[j][0] + rowB[k][0]) * 0.25F;
3519            dst[i][1] = (rowA[j][1] + rowA[k][1] +
3520                         rowB[j][1] + rowB[k][1]) * 0.25F;
3521         }
3522      }
3523      return;
3524   case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16:
3525      {
3526         GLuint i, j, k, comp;
3527         const GLhalfARB (*rowA)[2] = (const GLhalfARB (*)[2]) srcRowA;
3528         const GLhalfARB (*rowB)[2] = (const GLhalfARB (*)[2]) srcRowB;
3529         GLhalfARB (*dst)[2] = (GLhalfARB (*)[2]) dstRow;
3530         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3531              i++, j += colStride, k += colStride) {
3532            for (comp = 0; comp < 2; comp++) {
3533               GLfloat aj, ak, bj, bk;
3534               aj = _mesa_half_to_float(rowA[j][comp]);
3535               ak = _mesa_half_to_float(rowA[k][comp]);
3536               bj = _mesa_half_to_float(rowB[j][comp]);
3537               bk = _mesa_half_to_float(rowB[k][comp]);
3538               dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
3539            }
3540         }
3541      }
3542      return;
3543   case MESA_FORMAT_ALPHA_FLOAT32:
3544   case MESA_FORMAT_LUMINANCE_FLOAT32:
3545   case MESA_FORMAT_INTENSITY_FLOAT32:
3546      {
3547         GLuint i, j, k;
3548         const GLfloat *rowA = (const GLfloat *) srcRowA;
3549         const GLfloat *rowB = (const GLfloat *) srcRowB;
3550         GLfloat *dst = (GLfloat *) dstRow;
3551         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3552              i++, j += colStride, k += colStride) {
3553            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
3554         }
3555      }
3556      return;
3557   case MESA_FORMAT_ALPHA_FLOAT16:
3558   case MESA_FORMAT_LUMINANCE_FLOAT16:
3559   case MESA_FORMAT_INTENSITY_FLOAT16:
3560      {
3561         GLuint i, j, k;
3562         const GLhalfARB *rowA = (const GLhalfARB *) srcRowA;
3563         const GLhalfARB *rowB = (const GLhalfARB *) srcRowB;
3564         GLhalfARB *dst = (GLhalfARB *) dstRow;
3565         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
3566              i++, j += colStride, k += colStride) {
3567            GLfloat aj, ak, bj, bk;
3568            aj = _mesa_half_to_float(rowA[j]);
3569            ak = _mesa_half_to_float(rowA[k]);
3570            bj = _mesa_half_to_float(rowB[j]);
3571            bk = _mesa_half_to_float(rowB[k]);
3572            dst[i] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F);
3573         }
3574      }
3575      return;
3576
3577   default:
3578      _mesa_problem(NULL, "bad format in do_row()");
3579   }
3580}
3581
3582
3583/*
3584 * These functions generate a 1/2-size mipmap image from a source image.
3585 * Texture borders are handled by copying or averaging the source image's
3586 * border texels, depending on the scale-down factor.
3587 */
3588
3589static void
3590make_1d_mipmap(const struct gl_texture_format *format, GLint border,
3591               GLint srcWidth, const GLubyte *srcPtr,
3592               GLint dstWidth, GLubyte *dstPtr)
3593{
3594   const GLint bpt = format->TexelBytes;
3595   const GLubyte *src;
3596   GLubyte *dst;
3597
3598   /* skip the border pixel, if any */
3599   src = srcPtr + border * bpt;
3600   dst = dstPtr + border * bpt;
3601
3602   /* we just duplicate the input row, kind of hack, saves code */
3603   do_row(format, srcWidth - 2 * border, src, src,
3604          dstWidth - 2 * border, dst);
3605
3606   if (border) {
3607      /* copy left-most pixel from source */
3608      MEMCPY(dstPtr, srcPtr, bpt);
3609      /* copy right-most pixel from source */
3610      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
3611             srcPtr + (srcWidth - 1) * bpt,
3612             bpt);
3613   }
3614}
3615
3616
3617/**
3618 * XXX need to use the tex image's row stride!
3619 */
3620static void
3621make_2d_mipmap(const struct gl_texture_format *format, GLint border,
3622               GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
3623               GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
3624{
3625   const GLint bpt = format->TexelBytes;
3626   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
3627   const GLint dstWidthNB = dstWidth - 2 * border;
3628   const GLint dstHeightNB = dstHeight - 2 * border;
3629   const GLint srcRowStride = bpt * srcWidth;
3630   const GLint dstRowStride = bpt * dstWidth;
3631   const GLubyte *srcA, *srcB;
3632   GLubyte *dst;
3633   GLint row;
3634
3635   /* Compute src and dst pointers, skipping any border */
3636   srcA = srcPtr + border * ((srcWidth + 1) * bpt);
3637   if (srcHeight > 1)
3638      srcB = srcA + srcRowStride;
3639   else
3640      srcB = srcA;
3641   dst = dstPtr + border * ((dstWidth + 1) * bpt);
3642
3643   for (row = 0; row < dstHeightNB; row++) {
3644      do_row(format, srcWidthNB, srcA, srcB,
3645             dstWidthNB, dst);
3646      srcA += 2 * srcRowStride;
3647      srcB += 2 * srcRowStride;
3648      dst += dstRowStride;
3649   }
3650
3651   /* This is ugly but probably won't be used much */
3652   if (border > 0) {
3653      /* fill in dest border */
3654      /* lower-left border pixel */
3655      MEMCPY(dstPtr, srcPtr, bpt);
3656      /* lower-right border pixel */
3657      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
3658             srcPtr + (srcWidth - 1) * bpt, bpt);
3659      /* upper-left border pixel */
3660      MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
3661             srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
3662      /* upper-right border pixel */
3663      MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
3664             srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
3665      /* lower border */
3666      do_row(format, srcWidthNB,
3667             srcPtr + bpt,
3668             srcPtr + bpt,
3669             dstWidthNB, dstPtr + bpt);
3670      /* upper border */
3671      do_row(format, srcWidthNB,
3672             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
3673             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
3674             dstWidthNB,
3675             dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
3676      /* left and right borders */
3677      if (srcHeight == dstHeight) {
3678         /* copy border pixel from src to dst */
3679         for (row = 1; row < srcHeight; row++) {
3680            MEMCPY(dstPtr + dstWidth * row * bpt,
3681                   srcPtr + srcWidth * row * bpt, bpt);
3682            MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
3683                   srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
3684         }
3685      }
3686      else {
3687         /* average two src pixels each dest pixel */
3688         for (row = 0; row < dstHeightNB; row += 2) {
3689            do_row(format, 1,
3690                   srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
3691                   srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
3692                   1, dstPtr + (dstWidth * row + 1) * bpt);
3693            do_row(format, 1,
3694                   srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
3695                   srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
3696                   1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
3697         }
3698      }
3699   }
3700}
3701
3702
3703static void
3704make_3d_mipmap(const struct gl_texture_format *format, GLint border,
3705               GLint srcWidth, GLint srcHeight, GLint srcDepth,
3706               const GLubyte *srcPtr,
3707               GLint dstWidth, GLint dstHeight, GLint dstDepth,
3708               GLubyte *dstPtr)
3709{
3710   const GLint bpt = format->TexelBytes;
3711   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
3712   const GLint srcDepthNB = srcDepth - 2 * border;
3713   const GLint dstWidthNB = dstWidth - 2 * border;
3714   const GLint dstHeightNB = dstHeight - 2 * border;
3715   const GLint dstDepthNB = dstDepth - 2 * border;
3716   GLvoid *tmpRowA, *tmpRowB;
3717   GLint img, row;
3718   GLint bytesPerSrcImage, bytesPerDstImage;
3719   GLint bytesPerSrcRow, bytesPerDstRow;
3720   GLint srcImageOffset, srcRowOffset;
3721
3722   (void) srcDepthNB; /* silence warnings */
3723
3724   /* Need two temporary row buffers */
3725   tmpRowA = _mesa_malloc(srcWidth * bpt);
3726   if (!tmpRowA)
3727      return;
3728   tmpRowB = _mesa_malloc(srcWidth * bpt);
3729   if (!tmpRowB) {
3730      _mesa_free(tmpRowA);
3731      return;
3732   }
3733
3734   bytesPerSrcImage = srcWidth * srcHeight * bpt;
3735   bytesPerDstImage = dstWidth * dstHeight * bpt;
3736
3737   bytesPerSrcRow = srcWidth * bpt;
3738   bytesPerDstRow = dstWidth * bpt;
3739
3740   /* Offset between adjacent src images to be averaged together */
3741   srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
3742
3743   /* Offset between adjacent src rows to be averaged together */
3744   srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
3745
3746   /*
3747    * Need to average together up to 8 src pixels for each dest pixel.
3748    * Break that down into 3 operations:
3749    *   1. take two rows from source image and average them together.
3750    *   2. take two rows from next source image and average them together.
3751    *   3. take the two averaged rows and average them for the final dst row.
3752    */
3753
3754   /*
3755   _mesa_printf("mip3d %d x %d x %d  ->  %d x %d x %d\n",
3756          srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
3757   */
3758
3759   for (img = 0; img < dstDepthNB; img++) {
3760      /* first source image pointer, skipping border */
3761      const GLubyte *imgSrcA = srcPtr
3762         + (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
3763         + img * (bytesPerSrcImage + srcImageOffset);
3764      /* second source image pointer, skipping border */
3765      const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
3766      /* address of the dest image, skipping border */
3767      GLubyte *imgDst = dstPtr
3768         + (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
3769         + img * bytesPerDstImage;
3770
3771      /* setup the four source row pointers and the dest row pointer */
3772      const GLubyte *srcImgARowA = imgSrcA;
3773      const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
3774      const GLubyte *srcImgBRowA = imgSrcB;
3775      const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
3776      GLubyte *dstImgRow = imgDst;
3777
3778      for (row = 0; row < dstHeightNB; row++) {
3779         /* Average together two rows from first src image */
3780         do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
3781                srcWidthNB, tmpRowA);
3782         /* Average together two rows from second src image */
3783         do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
3784                srcWidthNB, tmpRowB);
3785         /* Average together the temp rows to make the final row */
3786         do_row(format, srcWidthNB, tmpRowA, tmpRowB,
3787                dstWidthNB, dstImgRow);
3788         /* advance to next rows */
3789         srcImgARowA += bytesPerSrcRow + srcRowOffset;
3790         srcImgARowB += bytesPerSrcRow + srcRowOffset;
3791         srcImgBRowA += bytesPerSrcRow + srcRowOffset;
3792         srcImgBRowB += bytesPerSrcRow + srcRowOffset;
3793         dstImgRow += bytesPerDstRow;
3794      }
3795   }
3796
3797   _mesa_free(tmpRowA);
3798   _mesa_free(tmpRowB);
3799
3800   /* Luckily we can leverage the make_2d_mipmap() function here! */
3801   if (border > 0) {
3802      /* do front border image */
3803      make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
3804                     dstWidth, dstHeight, dstPtr);
3805      /* do back border image */
3806      make_2d_mipmap(format, 1, srcWidth, srcHeight,
3807                     srcPtr + bytesPerSrcImage * (srcDepth - 1),
3808                     dstWidth, dstHeight,
3809                     dstPtr + bytesPerDstImage * (dstDepth - 1));
3810      /* do four remaining border edges that span the image slices */
3811      if (srcDepth == dstDepth) {
3812         /* just copy border pixels from src to dst */
3813         for (img = 0; img < dstDepthNB; img++) {
3814            const GLubyte *src;
3815            GLubyte *dst;
3816
3817            /* do border along [img][row=0][col=0] */
3818            src = srcPtr + (img + 1) * bytesPerSrcImage;
3819            dst = dstPtr + (img + 1) * bytesPerDstImage;
3820            MEMCPY(dst, src, bpt);
3821
3822            /* do border along [img][row=dstHeight-1][col=0] */
3823            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3824                         + (srcHeight - 1) * bytesPerSrcRow;
3825            dst = dstPtr + (img + 1) * bytesPerDstImage
3826                         + (dstHeight - 1) * bytesPerDstRow;
3827            MEMCPY(dst, src, bpt);
3828
3829            /* do border along [img][row=0][col=dstWidth-1] */
3830            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3831                         + (srcWidth - 1) * bpt;
3832            dst = dstPtr + (img + 1) * bytesPerDstImage
3833                         + (dstWidth - 1) * bpt;
3834            MEMCPY(dst, src, bpt);
3835
3836            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
3837            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3838                         + (bytesPerSrcImage - bpt);
3839            dst = dstPtr + (img + 1) * bytesPerDstImage
3840                         + (bytesPerDstImage - bpt);
3841            MEMCPY(dst, src, bpt);
3842         }
3843      }
3844      else {
3845         /* average border pixels from adjacent src image pairs */
3846         ASSERT(srcDepthNB == 2 * dstDepthNB);
3847         for (img = 0; img < dstDepthNB; img++) {
3848            const GLubyte *src;
3849            GLubyte *dst;
3850
3851            /* do border along [img][row=0][col=0] */
3852            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
3853            dst = dstPtr + (img + 1) * bytesPerDstImage;
3854            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3855
3856            /* do border along [img][row=dstHeight-1][col=0] */
3857            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3858                         + (srcHeight - 1) * bytesPerSrcRow;
3859            dst = dstPtr + (img + 1) * bytesPerDstImage
3860                         + (dstHeight - 1) * bytesPerDstRow;
3861            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3862
3863            /* do border along [img][row=0][col=dstWidth-1] */
3864            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3865                         + (srcWidth - 1) * bpt;
3866            dst = dstPtr + (img + 1) * bytesPerDstImage
3867                         + (dstWidth - 1) * bpt;
3868            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3869
3870            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
3871            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
3872                         + (bytesPerSrcImage - bpt);
3873            dst = dstPtr + (img + 1) * bytesPerDstImage
3874                         + (bytesPerDstImage - bpt);
3875            do_row(format, 1, src, src + srcImageOffset, 1, dst);
3876         }
3877      }
3878   }
3879}
3880
3881
3882/**
3883 * For GL_SGIX_generate_mipmap:
3884 * Generate a complete set of mipmaps from texObj's base-level image.
3885 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
3886 */
3887void
3888_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
3889                      const struct gl_texture_unit *texUnit,
3890                      struct gl_texture_object *texObj)
3891{
3892   const struct gl_texture_image *srcImage;
3893   const struct gl_texture_format *convertFormat;
3894   const GLubyte *srcData = NULL;
3895   GLubyte *dstData = NULL;
3896   GLint level, maxLevels;
3897
3898   ASSERT(texObj);
3899   /* XXX choose cube map face here??? */
3900   srcImage = texObj->Image[0][texObj->BaseLevel];
3901   ASSERT(srcImage);
3902
3903   maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
3904   ASSERT(maxLevels > 0);  /* bad target */
3905
3906   /* Find convertFormat - the format that do_row() will process */
3907   if (srcImage->IsCompressed) {
3908      /* setup for compressed textures */
3909      GLuint row;
3910      GLint  components, size;
3911      GLchan *dst;
3912
3913      assert(texObj->Target == GL_TEXTURE_2D);
3914
3915      if (srcImage->_BaseFormat == GL_RGB) {
3916         convertFormat = &_mesa_texformat_rgb;
3917         components = 3;
3918      }
3919      else if (srcImage->_BaseFormat == GL_RGBA) {
3920         convertFormat = &_mesa_texformat_rgba;
3921         components = 4;
3922      }
3923      else {
3924         _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
3925         return;
3926      }
3927
3928      /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
3929      size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE)
3930         * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
3931      /* 20 extra bytes, just be safe when calling last FetchTexel */
3932      srcData = (GLubyte *) _mesa_malloc(size);
3933      if (!srcData) {
3934         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
3935         return;
3936      }
3937      dstData = (GLubyte *) _mesa_malloc(size / 2);  /* 1/4 would probably be OK */
3938      if (!dstData) {
3939         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
3940         _mesa_free((void *) srcData);
3941         return;
3942      }
3943
3944      /* decompress base image here */
3945      dst = (GLchan *) srcData;
3946      for (row = 0; row < srcImage->Height; row++) {
3947         GLuint col;
3948         for (col = 0; col < srcImage->Width; col++) {
3949            srcImage->FetchTexelc(srcImage, col, row, 0, dst);
3950            dst += components;
3951         }
3952      }
3953   }
3954   else {
3955      /* uncompressed */
3956      convertFormat = srcImage->TexFormat;
3957   }
3958
3959   for (level = texObj->BaseLevel; level < texObj->MaxLevel
3960           && level < maxLevels - 1; level++) {
3961      /* generate image[level+1] from image[level] */
3962      const struct gl_texture_image *srcImage;
3963      struct gl_texture_image *dstImage;
3964      GLint srcWidth, srcHeight, srcDepth;
3965      GLint dstWidth, dstHeight, dstDepth;
3966      GLint border, bytesPerTexel;
3967
3968      /* get src image parameters */
3969      srcImage = _mesa_select_tex_image(ctx, texUnit, target, level);
3970      ASSERT(srcImage);
3971      srcWidth = srcImage->Width;
3972      srcHeight = srcImage->Height;
3973      srcDepth = srcImage->Depth;
3974      border = srcImage->Border;
3975
3976      /* compute next (level+1) image size */
3977      if (srcWidth - 2 * border > 1) {
3978         dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
3979      }
3980      else {
3981         dstWidth = srcWidth; /* can't go smaller */
3982      }
3983      if (srcHeight - 2 * border > 1) {
3984         dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
3985      }
3986      else {
3987         dstHeight = srcHeight; /* can't go smaller */
3988      }
3989      if (srcDepth - 2 * border > 1) {
3990         dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
3991      }
3992      else {
3993         dstDepth = srcDepth; /* can't go smaller */
3994      }
3995
3996      if (dstWidth == srcWidth &&
3997          dstHeight == srcHeight &&
3998          dstDepth == srcDepth) {
3999         /* all done */
4000         if (srcImage->IsCompressed) {
4001            _mesa_free((void *) srcData);
4002            _mesa_free(dstData);
4003         }
4004         return;
4005      }
4006
4007      /* get dest gl_texture_image */
4008      dstImage = _mesa_get_tex_image(ctx, texUnit, target, level + 1);
4009      if (!dstImage) {
4010         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
4011         return;
4012      }
4013
4014      /* Free old image data */
4015      if (dstImage->Data)
4016         ctx->Driver.FreeTexImageData(ctx, dstImage);
4017
4018      /* initialize new image */
4019      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
4020                                 dstDepth, border, srcImage->InternalFormat);
4021      dstImage->DriverData = NULL;
4022      dstImage->TexFormat = srcImage->TexFormat;
4023      dstImage->FetchTexelc = srcImage->FetchTexelc;
4024      dstImage->FetchTexelf = srcImage->FetchTexelf;
4025      dstImage->IsCompressed = srcImage->IsCompressed;
4026      if (dstImage->IsCompressed) {
4027         dstImage->CompressedSize
4028            = ctx->Driver.CompressedTextureSize(ctx, dstImage->Width,
4029                                              dstImage->Height,
4030                                              dstImage->Depth,
4031                                              dstImage->TexFormat->MesaFormat);
4032         ASSERT(dstImage->CompressedSize > 0);
4033      }
4034
4035      ASSERT(dstImage->TexFormat);
4036      ASSERT(dstImage->FetchTexelc);
4037      ASSERT(dstImage->FetchTexelf);
4038
4039      /* Alloc new teximage data buffer.
4040       * Setup src and dest data pointers.
4041       */
4042      if (dstImage->IsCompressed) {
4043         dstImage->Data = _mesa_alloc_texmemory(dstImage->CompressedSize);
4044         if (!dstImage->Data) {
4045            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
4046            return;
4047         }
4048         /* srcData and dstData are already set */
4049         ASSERT(srcData);
4050         ASSERT(dstData);
4051      }
4052      else {
4053         bytesPerTexel = dstImage->TexFormat->TexelBytes;
4054         ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
4055         dstImage->Data = _mesa_alloc_texmemory(dstWidth * dstHeight
4056                                                * dstDepth * bytesPerTexel);
4057         if (!dstImage->Data) {
4058            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
4059            return;
4060         }
4061         srcData = (const GLubyte *) srcImage->Data;
4062         dstData = (GLubyte *) dstImage->Data;
4063      }
4064
4065      /*
4066       * We use simple 2x2 averaging to compute the next mipmap level.
4067       */
4068      switch (target) {
4069         case GL_TEXTURE_1D:
4070            make_1d_mipmap(convertFormat, border,
4071                           srcWidth, srcData,
4072                           dstWidth, dstData);
4073            break;
4074         case GL_TEXTURE_2D:
4075         case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
4076         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
4077         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
4078         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
4079         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
4080         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
4081            make_2d_mipmap(convertFormat, border,
4082                           srcWidth, srcHeight, srcData,
4083                           dstWidth, dstHeight, dstData);
4084            break;
4085         case GL_TEXTURE_3D:
4086            make_3d_mipmap(convertFormat, border,
4087                           srcWidth, srcHeight, srcDepth, srcData,
4088                           dstWidth, dstHeight, dstDepth, dstData);
4089            break;
4090         case GL_TEXTURE_RECTANGLE_NV:
4091            /* no mipmaps, do nothing */
4092            break;
4093         default:
4094            _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
4095            return;
4096      }
4097
4098      if (dstImage->IsCompressed) {
4099         GLubyte *temp;
4100         /* compress image from dstData into dstImage->Data */
4101         const GLenum srcFormat = convertFormat->BaseFormat;
4102         GLint dstRowStride
4103            = _mesa_compressed_row_stride(dstImage->TexFormat->MesaFormat, dstWidth);
4104         ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
4105         dstImage->TexFormat->StoreImage(ctx, 2, dstImage->_BaseFormat,
4106                                         dstImage->TexFormat,
4107                                         dstImage->Data,
4108                                         0, 0, 0, /* dstX/Y/Zoffset */
4109                                         dstRowStride, 0, /* strides */
4110                                         dstWidth, dstHeight, 1, /* size */
4111                                         srcFormat, CHAN_TYPE,
4112                                         dstData, /* src data, actually */
4113                                         &ctx->DefaultPacking);
4114         /* swap src and dest pointers */
4115         temp = (GLubyte *) srcData;
4116         srcData = dstData;
4117         dstData = temp;
4118      }
4119
4120   } /* loop over mipmap levels */
4121}
4122
4123
4124/**
4125 * Helper function for drivers which need to rescale texture images to
4126 * certain aspect ratios.
4127 * Nearest filtering only (for broken hardware that can't support
4128 * all aspect ratios).  This can be made a lot faster, but I don't
4129 * really care enough...
4130 */
4131void
4132_mesa_rescale_teximage2d (GLuint bytesPerPixel,
4133			  GLuint srcStrideInPixels,
4134			  GLuint dstRowStride,
4135			  GLint srcWidth, GLint srcHeight,
4136			  GLint dstWidth, GLint dstHeight,
4137			  const GLvoid *srcImage, GLvoid *dstImage)
4138{
4139   GLint row, col;
4140
4141#define INNER_LOOP( TYPE, HOP, WOP )					\
4142   for ( row = 0 ; row < dstHeight ; row++ ) {				\
4143      GLint srcRow = row HOP hScale;					\
4144      for ( col = 0 ; col < dstWidth ; col++ ) {			\
4145	 GLint srcCol = col WOP wScale;					\
4146	 dst[col] = src[srcRow * srcStrideInPixels + srcCol];		\
4147      }									\
4148      dst = (TYPE *) ((GLubyte *) dst + dstRowStride);			\
4149   }									\
4150
4151#define RESCALE_IMAGE( TYPE )						\
4152do {									\
4153   const TYPE *src = (const TYPE *)srcImage;				\
4154   TYPE *dst = (TYPE *)dstImage;					\
4155									\
4156   if ( srcHeight < dstHeight ) {					\
4157      const GLint hScale = dstHeight / srcHeight;			\
4158      if ( srcWidth < dstWidth ) {					\
4159	 const GLint wScale = dstWidth / srcWidth;			\
4160	 INNER_LOOP( TYPE, /, / );					\
4161      }									\
4162      else {								\
4163	 const GLint wScale = srcWidth / dstWidth;			\
4164	 INNER_LOOP( TYPE, /, * );					\
4165      }									\
4166   }									\
4167   else {								\
4168      const GLint hScale = srcHeight / dstHeight;			\
4169      if ( srcWidth < dstWidth ) {					\
4170	 const GLint wScale = dstWidth / srcWidth;			\
4171	 INNER_LOOP( TYPE, *, / );					\
4172      }									\
4173      else {								\
4174	 const GLint wScale = srcWidth / dstWidth;			\
4175	 INNER_LOOP( TYPE, *, * );					\
4176      }									\
4177   }									\
4178} while (0)
4179
4180   switch ( bytesPerPixel ) {
4181   case 4:
4182      RESCALE_IMAGE( GLuint );
4183      break;
4184
4185   case 2:
4186      RESCALE_IMAGE( GLushort );
4187      break;
4188
4189   case 1:
4190      RESCALE_IMAGE( GLubyte );
4191      break;
4192   default:
4193      _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
4194   }
4195}
4196
4197
4198/**
4199 * Upscale an image by replication, not (typical) stretching.
4200 * We use this when the image width or height is less than a
4201 * certain size (4, 8) and we need to upscale an image.
4202 */
4203void
4204_mesa_upscale_teximage2d (GLsizei inWidth, GLsizei inHeight,
4205                          GLsizei outWidth, GLsizei outHeight,
4206                          GLint comps, const GLchan *src, GLint srcRowStride,
4207                          GLchan *dest )
4208{
4209   GLint i, j, k;
4210
4211   ASSERT(outWidth >= inWidth);
4212   ASSERT(outHeight >= inHeight);
4213#if 0
4214   ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
4215   ASSERT((outWidth & 3) == 0);
4216   ASSERT((outHeight & 3) == 0);
4217#endif
4218
4219   for (i = 0; i < outHeight; i++) {
4220      const GLint ii = i % inHeight;
4221      for (j = 0; j < outWidth; j++) {
4222         const GLint jj = j % inWidth;
4223         for (k = 0; k < comps; k++) {
4224            dest[(i * outWidth + j) * comps + k]
4225               = src[ii * srcRowStride + jj * comps + k];
4226         }
4227      }
4228   }
4229}
4230
4231
4232#if FEATURE_EXT_texture_sRGB
4233
4234/**
4235 * Test if given texture image is an sRGB format.
4236 */
4237static GLboolean
4238is_srgb_teximage(const struct gl_texture_image *texImage)
4239{
4240   switch (texImage->TexFormat->MesaFormat) {
4241   case MESA_FORMAT_SRGB8:
4242   case MESA_FORMAT_SRGBA8:
4243   case MESA_FORMAT_SL8:
4244   case MESA_FORMAT_SLA8:
4245      return GL_TRUE;
4246   default:
4247      return GL_FALSE;
4248   }
4249}
4250
4251#endif /* FEATURE_EXT_texture_sRGB */
4252
4253
4254/**
4255 * This is the software fallback for Driver.GetTexImage().
4256 * All error checking will have been done before this routine is called.
4257 */
4258void
4259_mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
4260                   GLenum format, GLenum type, GLvoid *pixels,
4261                   struct gl_texture_object *texObj,
4262                   struct gl_texture_image *texImage)
4263{
4264   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
4265
4266   if (ctx->Pack.BufferObj->Name) {
4267      /* Packing texture image into a PBO.
4268       * Map the (potentially) VRAM-based buffer into our process space so
4269       * we can write into it with the code below.
4270       * A hardware driver might use a sophisticated blit to move the
4271       * texture data to the PBO if the PBO is in VRAM along with the texture.
4272       */
4273      GLubyte *buf = (GLubyte *)
4274         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
4275                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
4276      if (!buf) {
4277         /* buffer is already mapped - that's an error */
4278         _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)");
4279         return;
4280      }
4281      /* <pixels> was an offset into the PBO.
4282       * Now make it a real, client-side pointer inside the mapped region.
4283       */
4284      pixels = ADD_POINTERS(buf, pixels);
4285   }
4286   else if (!pixels) {
4287      /* not an error */
4288      return;
4289   }
4290
4291   {
4292      const GLint width = texImage->Width;
4293      const GLint height = texImage->Height;
4294      const GLint depth = texImage->Depth;
4295      GLint img, row;
4296      for (img = 0; img < depth; img++) {
4297         for (row = 0; row < height; row++) {
4298            /* compute destination address in client memory */
4299            GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels,
4300                                                width, height, format, type,
4301                                                img, row, 0);
4302            assert(dest);
4303
4304            if (format == GL_COLOR_INDEX) {
4305               GLuint indexRow[MAX_WIDTH];
4306               GLint col;
4307               /* Can't use FetchTexel here because that returns RGBA */
4308               if (texImage->TexFormat->IndexBits == 8) {
4309                  const GLubyte *src = (const GLubyte *) texImage->Data;
4310                  src += width * (img * texImage->Height + row);
4311                  for (col = 0; col < width; col++) {
4312                     indexRow[col] = src[col];
4313                  }
4314               }
4315               else if (texImage->TexFormat->IndexBits == 16) {
4316                  const GLushort *src = (const GLushort *) texImage->Data;
4317                  src += width * (img * texImage->Height + row);
4318                  for (col = 0; col < width; col++) {
4319                     indexRow[col] = src[col];
4320                  }
4321               }
4322               else {
4323                  _mesa_problem(ctx,
4324                                "Color index problem in _mesa_GetTexImage");
4325               }
4326               _mesa_pack_index_span(ctx, width, type, dest,
4327                                     indexRow, &ctx->Pack,
4328                                     0 /* no image transfer */);
4329            }
4330            else if (format == GL_DEPTH_COMPONENT) {
4331               GLfloat depthRow[MAX_WIDTH];
4332               GLint col;
4333               for (col = 0; col < width; col++) {
4334                  (*texImage->FetchTexelf)(texImage, col, row, img,
4335                                           depthRow + col);
4336               }
4337               _mesa_pack_depth_span(ctx, width, dest, type,
4338                                     depthRow, &ctx->Pack);
4339            }
4340            else if (format == GL_DEPTH_STENCIL_EXT) {
4341               /* XXX Note: we're bypassing texImage->FetchTexel()! */
4342               const GLuint *src = (const GLuint *) texImage->Data;
4343               src += width * row + width * height * img;
4344               _mesa_memcpy(dest, src, width * sizeof(GLuint));
4345               if (ctx->Pack.SwapBytes) {
4346                  _mesa_swap4((GLuint *) dest, width);
4347               }
4348            }
4349            else if (format == GL_YCBCR_MESA) {
4350               /* No pixel transfer */
4351               const GLint rowstride = texImage->RowStride;
4352               MEMCPY(dest,
4353                      (const GLushort *) texImage->Data + row * rowstride,
4354                      width * sizeof(GLushort));
4355               /* check for byte swapping */
4356               if ((texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR
4357                    && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
4358                   (texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV
4359                    && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
4360                  if (!ctx->Pack.SwapBytes)
4361                     _mesa_swap2((GLushort *) dest, width);
4362               }
4363               else if (ctx->Pack.SwapBytes) {
4364                  _mesa_swap2((GLushort *) dest, width);
4365               }
4366            }
4367#if FEATURE_EXT_texture_sRGB
4368            else if (is_srgb_teximage(texImage)) {
4369               /* no pixel transfer and no non-linear to linear conversion */
4370               const GLint comps = texImage->TexFormat->TexelBytes;
4371               const GLint rowstride = comps * texImage->RowStride;
4372               MEMCPY(dest,
4373                      (const GLubyte *) texImage->Data + row * rowstride,
4374                      comps * width * sizeof(GLubyte));
4375            }
4376#endif /* FEATURE_EXT_texture_sRGB */
4377            else {
4378               /* general case:  convert row to RGBA format */
4379               GLfloat rgba[MAX_WIDTH][4];
4380               GLint col;
4381               for (col = 0; col < width; col++) {
4382                  (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]);
4383               }
4384               _mesa_pack_rgba_span_float(ctx, width,
4385                                          (const GLfloat (*)[4]) rgba,
4386                                          format, type, dest, &ctx->Pack,
4387                                          0 /* no image transfer */);
4388            } /* format */
4389         } /* row */
4390      } /* img */
4391   }
4392
4393   if (ctx->Pack.BufferObj->Name) {
4394      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
4395                              ctx->Pack.BufferObj);
4396   }
4397}
4398
4399
4400
4401/**
4402 * This is the software fallback for Driver.GetCompressedTexImage().
4403 * All error checking will have been done before this routine is called.
4404 */
4405void
4406_mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
4407                              GLvoid *img,
4408                              const struct gl_texture_object *texObj,
4409                              const struct gl_texture_image *texImage)
4410{
4411   GLuint size;
4412
4413   if (ctx->Pack.BufferObj->Name) {
4414      /* pack texture image into a PBO */
4415      GLubyte *buf;
4416      if ((const GLubyte *) img + texImage->CompressedSize >
4417          (const GLubyte *) ctx->Pack.BufferObj->Size) {
4418         _mesa_error(ctx, GL_INVALID_OPERATION,
4419                     "glGetCompressedTexImage(invalid PBO access)");
4420         return;
4421      }
4422      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
4423                                              GL_WRITE_ONLY_ARB,
4424                                              ctx->Pack.BufferObj);
4425      if (!buf) {
4426         /* buffer is already mapped - that's an error */
4427         _mesa_error(ctx, GL_INVALID_OPERATION,
4428                     "glGetCompressedTexImage(PBO is mapped)");
4429         return;
4430      }
4431      img = ADD_POINTERS(buf, img);
4432   }
4433   else if (!img) {
4434      /* not an error */
4435      return;
4436   }
4437
4438   /* don't use texImage->CompressedSize since that may be padded out */
4439   size = _mesa_compressed_texture_size(ctx, texImage->Width, texImage->Height,
4440                                        texImage->Depth,
4441                                        texImage->TexFormat->MesaFormat);
4442
4443   /* just memcpy, no pixelstore or pixel transfer */
4444   _mesa_memcpy(img, texImage->Data, size);
4445
4446   if (ctx->Pack.BufferObj->Name) {
4447      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
4448                              ctx->Pack.BufferObj);
4449   }
4450}
4451