Subversion Repositories shark

Rev

Rev 55 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
55 pj 1
/* $Id: texstore.c,v 1.1 2003-02-28 11:42:05 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
 
27
/*
28
 * Authors:
29
 *   Brian Paul
30
 */
31
 
32
/*
33
 * The GL texture image functions in teximage.c basically just do
34
 * error checking and data structure allocation.  They in turn call
35
 * device driver functions which actually copy/convert/store the user's
36
 * texture image data.
37
 *
38
 * However, most device drivers will be able to use the fallback functions
39
 * in this file.  That is, most drivers will have the following bit of
40
 * code:
41
 *   ctx->Driver.TexImage1D = _mesa_store_teximage1d;
42
 *   ctx->Driver.TexImage2D = _mesa_store_teximage2d;
43
 *   ctx->Driver.TexImage3D = _mesa_store_teximage3d;
44
 *   etc...
45
 *
46
 * Texture image processing is actually kind of complicated.  We have to do:
47
 *    Format/type conversions
48
 *    pixel unpacking
49
 *    pixel transfer (scale, bais, lookup, convolution!, etc)
50
 *
51
 * These functions can handle most everything, including processing full
52
 * images and sub-images.
53
 */
54
 
55
 
56
#include "glheader.h"
57
#include "colormac.h"
58
#include "context.h"
59
#include "convolve.h"
60
#include "image.h"
61
#include "macros.h"
62
#include "imports.h"
63
#include "texcompress.h"
64
#include "texformat.h"
65
#include "teximage.h"
66
#include "texstore.h"
67
#include "texutil.h"
68
 
69
 
70
/*
71
 * Given an internal texture format enum or 1, 2, 3, 4 return the
72
 * corresponding _base_ internal format:  GL_ALPHA, GL_LUMINANCE,
73
 * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA.  Return the
74
 * number of components for the format.  Return -1 if invalid enum.
75
 */
76
static GLint
77
components_in_intformat( GLint format )
78
{
79
   switch (format) {
80
      case GL_ALPHA:
81
      case GL_ALPHA4:
82
      case GL_ALPHA8:
83
      case GL_ALPHA12:
84
      case GL_ALPHA16:
85
         return 1;
86
      case 1:
87
      case GL_LUMINANCE:
88
      case GL_LUMINANCE4:
89
      case GL_LUMINANCE8:
90
      case GL_LUMINANCE12:
91
      case GL_LUMINANCE16:
92
         return 1;
93
      case 2:
94
      case GL_LUMINANCE_ALPHA:
95
      case GL_LUMINANCE4_ALPHA4:
96
      case GL_LUMINANCE6_ALPHA2:
97
      case GL_LUMINANCE8_ALPHA8:
98
      case GL_LUMINANCE12_ALPHA4:
99
      case GL_LUMINANCE12_ALPHA12:
100
      case GL_LUMINANCE16_ALPHA16:
101
         return 2;
102
      case GL_INTENSITY:
103
      case GL_INTENSITY4:
104
      case GL_INTENSITY8:
105
      case GL_INTENSITY12:
106
      case GL_INTENSITY16:
107
         return 1;
108
      case 3:
109
      case GL_RGB:
110
      case GL_R3_G3_B2:
111
      case GL_RGB4:
112
      case GL_RGB5:
113
      case GL_RGB8:
114
      case GL_RGB10:
115
      case GL_RGB12:
116
      case GL_RGB16:
117
         return 3;
118
      case 4:
119
      case GL_RGBA:
120
      case GL_RGBA2:
121
      case GL_RGBA4:
122
      case GL_RGB5_A1:
123
      case GL_RGBA8:
124
      case GL_RGB10_A2:
125
      case GL_RGBA12:
126
      case GL_RGBA16:
127
         return 4;
128
      case GL_COLOR_INDEX:
129
      case GL_COLOR_INDEX1_EXT:
130
      case GL_COLOR_INDEX2_EXT:
131
      case GL_COLOR_INDEX4_EXT:
132
      case GL_COLOR_INDEX8_EXT:
133
      case GL_COLOR_INDEX12_EXT:
134
      case GL_COLOR_INDEX16_EXT:
135
         return 1;
136
      case GL_DEPTH_COMPONENT:
137
      case GL_DEPTH_COMPONENT16_SGIX:
138
      case GL_DEPTH_COMPONENT24_SGIX:
139
      case GL_DEPTH_COMPONENT32_SGIX:
140
         return 1;
141
      case GL_YCBCR_MESA:
142
         return 2; /* Y + (Cb or Cr) */
143
      default:
144
         return -1;  /* error */
145
   }
146
}
147
 
148
 
149
/*
150
 * This function is used to transfer the user's image data into a texture
151
 * image buffer.  We handle both full texture images and subtexture images.
152
 * We also take care of all image transfer operations here, including
153
 * convolution, scale/bias, colortables, etc.
154
 *
155
 * The destination texel type is always GLchan.
156
 * The destination texel format is one of the 6 basic types.
157
 *
158
 * A hardware driver may use this as a helper routine to unpack and
159
 * apply pixel transfer ops into a temporary image buffer.  Then,
160
 * convert the temporary image into the special hardware format.
161
 *
162
 * Input:
163
 *   dimensions - 1, 2, or 3
164
 *   texDestFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA,
165
 *                   GL_RGB or GL_RGBA (the destination format)
166
 *   texDestAddr - destination image address
167
 *   srcWidth, srcHeight, srcDepth - size (in pixels) of src and dest images
168
 *   dstXoffset, dstYoffset, dstZoffset - position to store the image within
169
 *      the destination 3D texture
170
 *   dstRowStride, dstImageStride - dest image strides in bytes
171
 *   srcFormat - source image format (GL_ALPHA, GL_RED, GL_RGB, etc)
172
 *   srcType - GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_FLOAT, etc
173
 *   srcPacking - describes packing of incoming image.
174
 *   transferOps - mask of pixel transfer operations
175
 */
176
static void
177
transfer_teximage(GLcontext *ctx, GLuint dimensions,
178
                  GLenum texDestFormat, GLvoid *texDestAddr,
179
                  GLint srcWidth, GLint srcHeight, GLint srcDepth,
180
                  GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
181
                  GLint dstRowStride, GLint dstImageStride,
182
                  GLenum srcFormat, GLenum srcType,
183
                  const GLvoid *srcAddr,
184
                  const struct gl_pixelstore_attrib *srcPacking,
185
                  GLuint transferOps)
186
{
187
   GLint texComponents;
188
 
189
   ASSERT(ctx);
190
   ASSERT(dimensions >= 1 && dimensions <= 3);
191
   ASSERT(texDestFormat == GL_LUMINANCE ||
192
          texDestFormat == GL_INTENSITY ||
193
          texDestFormat == GL_LUMINANCE_ALPHA ||
194
          texDestFormat == GL_ALPHA ||
195
          texDestFormat == GL_RGB ||
196
          texDestFormat == GL_RGBA);
197
   ASSERT(texDestAddr);
198
   ASSERT(srcWidth >= 1);
199
   ASSERT(srcHeight >= 1);
200
   ASSERT(srcDepth >= 1);
201
   ASSERT(dstXoffset >= 0);
202
   ASSERT(dstYoffset >= 0);
203
   ASSERT(dstZoffset >= 0);
204
   ASSERT(dstRowStride >= 0);
205
   ASSERT(dstImageStride >= 0);
206
   ASSERT(srcAddr);
207
   ASSERT(srcPacking);
208
 
209
   texComponents = components_in_intformat(texDestFormat);
210
 
211
   /* try common 2D texture cases first */
212
   if (!transferOps && dimensions == 2 && srcType == CHAN_TYPE) {
213
 
214
      if (srcFormat == texDestFormat) {
215
         /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA,
216
          * GL_LUMINANCE_ALPHA, etc. texture formats.  Use memcpy().
217
          */
218
         const GLchan *src = (const GLchan *) _mesa_image_address(
219
                                   srcPacking, srcAddr, srcWidth, srcHeight,
220
                                   srcFormat, srcType, 0, 0, 0);
221
         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
222
                                               srcWidth, srcFormat, srcType);
223
         const GLint widthInBytes = srcWidth * texComponents * sizeof(GLchan);
224
         GLchan *dst = (GLchan *) texDestAddr
225
                     + dstYoffset * (dstRowStride / sizeof(GLchan))
226
                     + dstXoffset * texComponents;
227
         if (srcRowStride == widthInBytes && dstRowStride == widthInBytes) {
228
            MEMCPY(dst, src, srcHeight * widthInBytes);
229
         }
230
         else {
231
            GLint i;
232
            for (i = 0; i < srcHeight; i++) {
233
               MEMCPY(dst, src, widthInBytes);
234
               src += (srcRowStride / sizeof(GLchan));
235
               dst += (dstRowStride / sizeof(GLchan));
236
            }
237
         }
238
         return;  /* all done */
239
      }
240
      else if (srcFormat == GL_RGBA && texDestFormat == GL_RGB) {
241
         /* commonly used by Quake */
242
         const GLchan *src = (const GLchan *) _mesa_image_address(
243
                                   srcPacking, srcAddr, srcWidth, srcHeight,
244
                                   srcFormat, srcType, 0, 0, 0);
245
         const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
246
                                               srcWidth, srcFormat, srcType);
247
         GLchan *dst = (GLchan *) texDestAddr
248
                     + dstYoffset * (dstRowStride / sizeof(GLchan))
249
                     + dstXoffset * texComponents;
250
         GLint i, j;
251
         for (i = 0; i < srcHeight; i++) {
252
            const GLchan *s = src;
253
            GLchan *d = dst;
254
            for (j = 0; j < srcWidth; j++) {
255
               *d++ = *s++;  /*red*/
256
               *d++ = *s++;  /*green*/
257
               *d++ = *s++;  /*blue*/
258
               s++;          /*alpha*/
259
            }
260
            src += (srcRowStride / sizeof(GLchan));
261
            dst += (dstRowStride / sizeof(GLchan));
262
         }
263
         return;  /* all done */
264
      }
265
   }
266
 
267
   /*
268
    * General case solutions
269
    */
270
   if (texDestFormat == GL_COLOR_INDEX) {
271
      /* color index texture */
272
      const GLenum texType = CHAN_TYPE;
273
      GLint img, row;
274
      GLchan *dest = (GLchan *) texDestAddr
275
                   + dstZoffset * (dstImageStride / sizeof(GLchan))
276
                   + dstYoffset * (dstRowStride / sizeof(GLchan))
277
                   + dstXoffset * texComponents;
278
      for (img = 0; img < srcDepth; img++) {
279
         GLchan *destRow = dest;
280
         for (row = 0; row < srcHeight; row++) {
281
            const GLvoid *src = _mesa_image_address(srcPacking,
282
                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
283
            _mesa_unpack_index_span(ctx, srcWidth, texType, destRow,
284
                                    srcType, src, srcPacking, transferOps);
285
            destRow += (dstRowStride / sizeof(GLchan));
286
         }
287
         dest += dstImageStride;
288
      }
289
   }
290
   else if (texDestFormat == GL_YCBCR_MESA) {
291
      /* YCbCr texture */
292
      GLint img, row;
293
      GLushort *dest = (GLushort *) texDestAddr
294
                     + dstZoffset * (dstImageStride / sizeof(GLushort))
295
                     + dstYoffset * (dstRowStride / sizeof(GLushort))
296
                     + dstXoffset * texComponents;
297
      ASSERT(ctx->Extensions.MESA_ycbcr_texture);
298
      for (img = 0; img < srcDepth; img++) {
299
         GLushort *destRow = dest;
300
         for (row = 0; row < srcHeight; row++) {
301
            const GLvoid *srcRow = _mesa_image_address(srcPacking,
302
                                          srcAddr, srcWidth, srcHeight,
303
                                          srcFormat, srcType, img, row, 0);
304
            MEMCPY(destRow, srcRow, srcWidth * sizeof(GLushort));
305
            destRow += (dstRowStride / sizeof(GLushort));
306
         }
307
         dest += dstImageStride / sizeof(GLushort);
308
      }
309
   }
310
   else if (texDestFormat == GL_DEPTH_COMPONENT) {
311
      /* Depth texture (shadow maps) */
312
      GLint img, row;
313
      GLubyte *dest = (GLubyte *) texDestAddr
314
                    + dstZoffset * dstImageStride
315
                    + dstYoffset * (dstRowStride / sizeof(GLchan))
316
                    + dstXoffset * texComponents;
317
      for (img = 0; img < srcDepth; img++) {
318
         GLubyte *destRow = dest;
319
         for (row = 0; row < srcHeight; row++) {
320
            const GLvoid *src = _mesa_image_address(srcPacking,
321
                srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
322
            _mesa_unpack_depth_span(ctx, srcWidth, (GLfloat *) destRow,
323
                                    srcType, src, srcPacking);
324
            destRow += (dstRowStride / sizeof(GLchan));
325
         }
326
         dest += dstImageStride;
327
      }
328
   }
329
   else {
330
      /* regular, color texture */
331
      if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) ||
332
          (dimensions >= 2 && ctx->Pixel.Convolution2DEnabled) ||
333
          (dimensions >= 2 && ctx->Pixel.Separable2DEnabled)) {
334
         /*
335
          * Fill texture image with convolution
336
          */
337
         GLint img, row;
338
         GLint convWidth = srcWidth, convHeight = srcHeight;
339
         GLfloat *tmpImage, *convImage;
340
         tmpImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
341
         if (!tmpImage) {
342
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
343
            return;
344
         }
345
         convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
346
         if (!convImage) {
347
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
348
            FREE(tmpImage);
349
            return;
350
         }
351
 
352
         for (img = 0; img < srcDepth; img++) {
353
            const GLfloat *srcf;
354
            GLfloat *dstf = tmpImage;
355
            GLchan *dest;
356
 
357
            /* unpack and do transfer ops up to convolution */
358
            for (row = 0; row < srcHeight; row++) {
359
               const GLvoid *src = _mesa_image_address(srcPacking,
360
                                              srcAddr, srcWidth, srcHeight,
361
                                              srcFormat, srcType, img, row, 0);
362
               _mesa_unpack_float_color_span(ctx, srcWidth, GL_RGBA, dstf,
363
                         srcFormat, srcType, src, srcPacking,
364
                         transferOps & IMAGE_PRE_CONVOLUTION_BITS,
365
                         GL_TRUE);
366
               dstf += srcWidth * 4;
367
            }
368
 
369
            /* convolve */
370
            if (dimensions == 1) {
371
               ASSERT(ctx->Pixel.Convolution1DEnabled);
372
               _mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage);
373
            }
374
            else {
375
               if (ctx->Pixel.Convolution2DEnabled) {
376
                  _mesa_convolve_2d_image(ctx, &convWidth, &convHeight,
377
                                          tmpImage, convImage);
378
               }
379
               else {
380
                  ASSERT(ctx->Pixel.Separable2DEnabled);
381
                  _mesa_convolve_sep_image(ctx, &convWidth, &convHeight,
382
                                           tmpImage, convImage);
383
               }
384
            }
385
 
386
            /* packing and transfer ops after convolution */
387
            srcf = convImage;
388
            dest = (GLchan *) texDestAddr
389
                 + (dstZoffset + img) * (dstImageStride / sizeof(GLchan))
390
                 + dstYoffset * (dstRowStride / sizeof(GLchan));
391
            for (row = 0; row < convHeight; row++) {
392
               _mesa_pack_float_rgba_span(ctx, convWidth,
393
                                          (const GLfloat (*)[4]) srcf,
394
                                          texDestFormat, CHAN_TYPE,
395
                                          dest, &_mesa_native_packing,
396
                                          transferOps
397
                                          & IMAGE_POST_CONVOLUTION_BITS);
398
               srcf += convWidth * 4;
399
               dest += (dstRowStride / sizeof(GLchan));
400
            }
401
         }
402
 
403
         FREE(convImage);
404
         FREE(tmpImage);
405
      }
406
      else {
407
         /*
408
          * no convolution
409
          */
410
         GLint img, row;
411
         GLchan *dest = (GLchan *) texDestAddr
412
                      + dstZoffset * (dstImageStride / sizeof(GLchan))
413
                      + dstYoffset * (dstRowStride / sizeof(GLchan))
414
                      + dstXoffset * texComponents;
415
         for (img = 0; img < srcDepth; img++) {
416
            GLchan *destRow = dest;
417
            for (row = 0; row < srcHeight; row++) {
418
               const GLvoid *srcRow = _mesa_image_address(srcPacking,
419
                                              srcAddr, srcWidth, srcHeight,
420
                                              srcFormat, srcType, img, row, 0);
421
               _mesa_unpack_chan_color_span(ctx, srcWidth, texDestFormat,
422
                                       destRow, srcFormat, srcType, srcRow,
423
                                       srcPacking, transferOps);
424
               destRow += (dstRowStride / sizeof(GLchan));
425
            }
426
            dest += dstImageStride / sizeof(GLchan);
427
         }
428
      }
429
   }
430
}
431
 
432
 
433
 
434
/*
435
 * Transfer a texture image from user space to <destAddr> applying all
436
 * needed image transfer operations and storing the result in the format
437
 * specified by <dstFormat>.  <dstFormat> may be any format from texformat.h.
438
 * Input:
439
 *   dimensions - 1, 2 or 3
440
 *   baseInternalFormat - base format of the internal texture format
441
 *       specified by the user.  This is very important, see below.
442
 *   dstFormat - destination image format
443
 *   dstAddr - destination address
444
 *   srcWidth, srcHeight, srcDepth - size of source iamge
445
 *   dstX/Y/Zoffset - as specified by glTexSubImage
446
 *   dstRowStride - stride between dest rows in bytes
447
 *   dstImageStride - stride between dest images in bytes
448
 *   srcFormat, srcType - incoming image format and datatype
449
 *   srcAddr - source image address
450
 *   srcPacking - packing params of source image
451
 *
452
 * XXX this function is a bit more complicated than it should be.  If
453
 * _mesa_convert_texsubimage[123]d could handle any dest/source formats
454
 * or if transfer_teximage() could store in any MESA_FORMAT_* format, we
455
 * could simplify things here.
456
 */
457
void
458
_mesa_transfer_teximage(GLcontext *ctx, GLuint dimensions,
459
                        GLenum baseInternalFormat,
460
                        const struct gl_texture_format *dstFormat,
461
                        GLvoid *dstAddr,
462
                        GLint srcWidth, GLint srcHeight, GLint srcDepth,
463
                        GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
464
                        GLint dstRowStride, GLint dstImageStride,
465
                        GLenum srcFormat, GLenum srcType,
466
                        const GLvoid *srcAddr,
467
                        const struct gl_pixelstore_attrib *srcPacking)
468
{
469
   const GLint dstRowStridePixels = dstRowStride / dstFormat->TexelBytes;
470
   const GLint dstImageStridePixels = dstImageStride / dstFormat->TexelBytes;
471
   GLboolean makeTemp;
472
   GLuint transferOps = ctx->_ImageTransferState;
473
   GLboolean freeSourceData = GL_FALSE;
474
   GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
475
 
476
   assert(baseInternalFormat > 0);
477
   ASSERT(baseInternalFormat == GL_LUMINANCE ||
478
          baseInternalFormat == GL_INTENSITY ||
479
          baseInternalFormat == GL_LUMINANCE_ALPHA ||
480
          baseInternalFormat == GL_ALPHA ||
481
          baseInternalFormat == GL_RGB ||
482
          baseInternalFormat == GL_RGBA);
483
 
484
   if (transferOps & IMAGE_CONVOLUTION_BIT) {
485
      _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
486
                                         &postConvHeight);
487
   }
488
 
489
   /*
490
    * Consider this scenario:  The user's source image is GL_RGB and the
491
    * requested internal format is GL_LUMINANCE.  Now suppose the device
492
    * driver doesn't support GL_LUMINANCE and instead uses RGB16 as the
493
    * texture format.  In that case we still need to do an intermediate
494
    * conversion to luminance format so that the incoming red channel gets
495
    * replicated into the dest red, green and blue channels.  The following
496
    * code takes care of that.
497
    */
498
   if (dstFormat->BaseFormat != baseInternalFormat) {
499
      /* Allocate storage for temporary image in the baseInternalFormat */
500
      const GLint texelSize = _mesa_components_in_format(baseInternalFormat)
501
         * sizeof(GLchan);
502
      const GLint bytes = texelSize * postConvWidth * postConvHeight *srcDepth;
503
      const GLint tmpRowStride = texelSize * postConvWidth;
504
      const GLint tmpImgStride = texelSize * postConvWidth * postConvHeight;
505
      GLvoid *tmpImage = MALLOC(bytes);
506
      if (!tmpImage)
507
         return;
508
      transfer_teximage(ctx, dimensions, baseInternalFormat, tmpImage,
509
                        srcWidth, srcHeight, srcDepth,
510
                        0, 0, 0, /* x/y/zoffset */
511
                        tmpRowStride, tmpImgStride,
512
                        srcFormat, srcType, srcAddr, srcPacking, transferOps);
513
 
514
      /* this is our new source image */
515
      srcWidth = postConvWidth;
516
      srcHeight = postConvHeight;
517
      srcFormat = baseInternalFormat;
518
      srcType = CHAN_TYPE;
519
      srcAddr = tmpImage;
520
      srcPacking = &_mesa_native_packing;
521
      freeSourceData = GL_TRUE;
522
      transferOps = 0;  /* image transfer ops were completed */
523
   }
524
 
525
   /* Let the optimized tex conversion functions take a crack at the
526
    * image conversion if the dest format is a h/w format.
527
    */
528
   if (_mesa_is_hardware_tex_format(dstFormat)) {
529
      if (transferOps) {
530
         makeTemp = GL_TRUE;
531
      }
532
      else {
533
         if (dimensions == 1) {
534
            makeTemp = !_mesa_convert_texsubimage1d(dstFormat->MesaFormat,
535
                                                    dstXoffset,
536
                                                    srcWidth,
537
                                                    srcFormat, srcType,
538
                                                    srcPacking, srcAddr,
539
                                                    dstAddr);
540
         }
541
         else if (dimensions == 2) {
542
            makeTemp = !_mesa_convert_texsubimage2d(dstFormat->MesaFormat,
543
                                                    dstXoffset, dstYoffset,
544
                                                    srcWidth, srcHeight,
545
                                                    dstRowStridePixels,
546
                                                    srcFormat, srcType,
547
                                                    srcPacking, srcAddr,
548
                                                    dstAddr);
549
         }
550
         else {
551
            assert(dimensions == 3);
552
            makeTemp = !_mesa_convert_texsubimage3d(dstFormat->MesaFormat,
553
                                      dstXoffset, dstYoffset, dstZoffset,
554
                                      srcWidth, srcHeight, srcDepth,
555
                                      dstRowStridePixels, dstImageStridePixels,
556
                                      srcFormat, srcType,
557
                                      srcPacking, srcAddr, dstAddr);
558
         }
559
         if (!makeTemp) {
560
            /* all done! */
561
            if (freeSourceData)
562
               FREE((void *) srcAddr);
563
            return;
564
         }
565
      }
566
   }
567
   else {
568
      /* software texture format */
569
      makeTemp = GL_FALSE;
570
   }
571
 
572
   if (makeTemp) {
573
      GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
574
      GLenum tmpFormat;
575
      GLuint tmpComps, tmpTexelSize;
576
      GLint tmpRowStride, tmpImageStride;
577
      GLubyte *tmpImage;
578
 
579
      if (transferOps & IMAGE_CONVOLUTION_BIT) {
580
         _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
581
                                            &postConvHeight);
582
      }
583
 
584
      tmpFormat = dstFormat->BaseFormat;
585
      tmpComps = _mesa_components_in_format(tmpFormat);
586
      tmpTexelSize = tmpComps * sizeof(GLchan);
587
      tmpRowStride = postConvWidth * tmpTexelSize;
588
      tmpImageStride = postConvWidth * postConvHeight * tmpTexelSize;
589
      tmpImage = (GLubyte *) MALLOC(postConvWidth * postConvHeight *
590
                                    srcDepth * tmpTexelSize);
591
      if (!tmpImage) {
592
         if (freeSourceData)
593
            FREE((void *) srcAddr);
594
         return;
595
      }
596
 
597
      transfer_teximage(ctx, dimensions, tmpFormat, tmpImage,
598
                        srcWidth, srcHeight, srcDepth,
599
                        0, 0, 0, /* x/y/zoffset */
600
                        tmpRowStride, tmpImageStride,
601
                        srcFormat, srcType, srcAddr, srcPacking, transferOps);
602
 
603
      if (freeSourceData)
604
         FREE((void *) srcAddr);
605
 
606
      /* the temp image is our new source image */
607
      srcWidth = postConvWidth;
608
      srcHeight = postConvHeight;
609
      srcFormat = tmpFormat;
610
      srcType = CHAN_TYPE;
611
      srcAddr = tmpImage;
612
      srcPacking = &_mesa_native_packing;
613
      freeSourceData = GL_TRUE;
614
   }
615
 
616
   if (_mesa_is_hardware_tex_format(dstFormat)) {
617
      assert(makeTemp);
618
      if (dimensions == 1) {
619
         GLboolean b;
620
         b = _mesa_convert_texsubimage1d(dstFormat->MesaFormat,
621
                                         dstXoffset,
622
                                         srcWidth,
623
                                         srcFormat, srcType,
624
                                         srcPacking, srcAddr,
625
                                         dstAddr);
626
         assert(b);
627
      }
628
      else if (dimensions == 2) {
629
         GLboolean b;
630
         b = _mesa_convert_texsubimage2d(dstFormat->MesaFormat,
631
                                         dstXoffset, dstYoffset,
632
                                         srcWidth, srcHeight,
633
                                         dstRowStridePixels,
634
                                         srcFormat, srcType,
635
                                         srcPacking, srcAddr,
636
                                         dstAddr);
637
         assert(b);
638
      }
639
      else {
640
         GLboolean b;
641
         b = _mesa_convert_texsubimage3d(dstFormat->MesaFormat,
642
                                      dstXoffset, dstYoffset, dstZoffset,
643
                                      srcWidth, srcHeight, srcDepth,
644
                                      dstRowStridePixels, dstImageStridePixels,
645
                                      srcFormat, srcType,
646
                                      srcPacking, srcAddr, dstAddr);
647
         assert(b);
648
      }
649
   }
650
   else {
651
      /* software format */
652
      assert(!makeTemp);
653
      transfer_teximage(ctx, dimensions, dstFormat->BaseFormat, dstAddr,
654
                        srcWidth, srcHeight, srcDepth,
655
                        dstXoffset, dstYoffset, dstZoffset,
656
                        dstRowStride, dstImageStride,
657
                        srcFormat, srcType, srcAddr, srcPacking, transferOps);
658
   }
659
 
660
   if (freeSourceData)
661
      FREE((void *) srcAddr);  /* the temp image */
662
}
663
 
664
 
665
 
666
/**
667
 * Given a user's uncompressed texture image, this function takes care of
668
 * pixel unpacking, pixel transfer, format conversion and compression.
669
 */
670
static void
671
transfer_compressed_teximage(GLcontext *ctx, GLuint dimensions,
672
                             GLsizei width, GLsizei height, GLsizei depth,
673
                             GLenum srcFormat, GLenum srcType,
674
                             const struct gl_pixelstore_attrib *unpacking,
675
                             const GLvoid *source,
676
                             const struct gl_texture_format *dstFormat,
677
                             GLubyte *dest,
678
                             GLint dstRowStride)
679
{
680
   GLchan *tempImage = NULL;
681
   GLint srcRowStride;
682
   GLenum baseFormat;
683
 
684
   ASSERT(dimensions == 2);
685
   /* TexelBytes is zero if and only if it's a compressed format */
686
   ASSERT(dstFormat->TexelBytes == 0);
687
 
688
   baseFormat = dstFormat->BaseFormat;
689
 
690
   if (srcFormat != baseFormat || srcType != CHAN_TYPE ||
691
       ctx->_ImageTransferState != 0 || unpacking->SwapBytes) {
692
      /* need to convert user's image to texImage->Format, GLchan */
693
      GLint comps = components_in_intformat(baseFormat);
694
      GLint postConvWidth = width, postConvHeight = height;
695
 
696
      /* XXX convolution untested */
697
      if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
698
         _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
699
                                            &postConvHeight);
700
      }
701
 
702
      tempImage = (GLchan*) MALLOC(width * height * comps * sizeof(GLchan));
703
      if (!tempImage) {
704
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
705
         return;
706
      }
707
      transfer_teximage(ctx, dimensions,
708
                        baseFormat,             /* dest format */
709
                        tempImage,              /* dst address */
710
                        width, height, depth,   /* src size */
711
                        0, 0, 0,                /* x/y/zoffset */
712
                        comps * width,          /* dst row stride */
713
                        comps * width * height, /* dst image stride */
714
                        srcFormat, srcType,     /* src format, type */
715
                        source, unpacking,      /* src and src packing */
716
                        ctx->_ImageTransferState);
717
      source = tempImage;
718
      width = postConvWidth;
719
      height = postConvHeight;
720
      srcRowStride = width;
721
   }
722
   else {
723
      if (unpacking->RowLength)
724
         srcRowStride = unpacking->RowLength;
725
      else
726
         srcRowStride = width;
727
   }
728
 
729
   _mesa_compress_teximage(ctx, width, height, baseFormat,
730
                           (const GLchan *) source, srcRowStride,
731
                           dstFormat, dest, dstRowStride);
732
   if (tempImage) {
733
      FREE(tempImage);
734
   }
735
}
736
 
737
 
738
 
739
/*
740
 * This is the software fallback for Driver.TexImage1D()
741
 * and Driver.CopyTexImage2D().
742
 * The texture image type will be GLchan.
743
 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
744
 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
745
 */
746
void
747
_mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
748
                       GLint internalFormat,
749
                       GLint width, GLint border,
750
                       GLenum format, GLenum type, const GLvoid *pixels,
751
                       const struct gl_pixelstore_attrib *packing,
752
                       struct gl_texture_object *texObj,
753
                       struct gl_texture_image *texImage)
754
{
755
   GLint postConvWidth = width;
756
   GLint texelBytes, sizeInBytes;
757
 
758
   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
759
      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
760
   }
761
 
762
   /* choose the texture format */
763
   assert(ctx->Driver.ChooseTextureFormat);
764
   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
765
                                          internalFormat, format, type);
766
   assert(texImage->TexFormat);
767
   texImage->FetchTexel = texImage->TexFormat->FetchTexel1D;
768
 
769
   texelBytes = texImage->TexFormat->TexelBytes;
770
 
771
   /* allocate memory */
772
   if (texImage->IsCompressed)
773
      sizeInBytes = texImage->CompressedSize;
774
   else
775
      sizeInBytes = postConvWidth * texelBytes;
776
   texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
777
   if (!texImage->Data) {
778
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
779
      return;
780
   }
781
 
782
   if (!pixels)
783
      return;
784
 
785
   /* unpack image, apply transfer ops and store in texImage->Data */
786
   if (texImage->IsCompressed) {
787
      GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
788
                                                       width);
789
      transfer_compressed_teximage(ctx, 1, width, 1, 1,
790
                                   format, type, packing,
791
                                   pixels, texImage->TexFormat,
792
                                   (GLubyte *) texImage->Data, dstRowStride);
793
   }
794
   else {
795
      _mesa_transfer_teximage(ctx, 1,
796
                              texImage->Format, /* base format */
797
                              texImage->TexFormat, texImage->Data,
798
                              width, 1, 1,  /* src size */
799
                              0, 0, 0,      /* dstX/Y/Zoffset */
800
                              0, /* dstRowStride */
801
                              0, /* dstImageStride */
802
                              format, type, pixels, packing);
803
   }
804
 
805
   /* GL_SGIS_generate_mipmap */
806
   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
807
      _mesa_generate_mipmap(ctx, target,
808
                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
809
                            texObj);
810
   }
811
}
812
 
813
 
814
/*
815
 * This is the software fallback for Driver.TexImage2D()
816
 * and Driver.CopyTexImage2D().
817
 * The texture image type will be GLchan.
818
 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
819
 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
820
 */
821
void
822
_mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
823
                       GLint internalFormat,
824
                       GLint width, GLint height, GLint border,
825
                       GLenum format, GLenum type, const void *pixels,
826
                       const struct gl_pixelstore_attrib *packing,
827
                       struct gl_texture_object *texObj,
828
                       struct gl_texture_image *texImage)
829
{
830
   GLint postConvWidth = width, postConvHeight = height;
831
   GLint texelBytes, sizeInBytes;
832
 
833
   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
834
      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
835
                                         &postConvHeight);
836
   }
837
 
838
   /* choose the texture format */
839
   assert(ctx->Driver.ChooseTextureFormat);
840
   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
841
                                          internalFormat, format, type);
842
   assert(texImage->TexFormat);
843
   texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
844
 
845
   texelBytes = texImage->TexFormat->TexelBytes;
846
 
847
   /* allocate memory */
848
   if (texImage->IsCompressed)
849
      sizeInBytes = texImage->CompressedSize;
850
   else
851
      sizeInBytes = postConvWidth * postConvHeight * texelBytes;
852
   texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
853
   if (!texImage->Data) {
854
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
855
      return;
856
   }
857
 
858
   if (!pixels)
859
      return;
860
 
861
   /* unpack image, apply transfer ops and store in texImage->Data */
862
   if (texImage->IsCompressed) {
863
      GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
864
                                                       width);
865
      transfer_compressed_teximage(ctx, 2, width, height, 1,
866
                                   format, type, packing,
867
                                   pixels, texImage->TexFormat,
868
                                   (GLubyte *) texImage->Data, dstRowStride);
869
   }
870
   else {
871
      _mesa_transfer_teximage(ctx, 2,
872
                              texImage->Format,
873
                              texImage->TexFormat, texImage->Data,
874
                              width, height, 1,  /* src size */
875
                              0, 0, 0,           /* dstX/Y/Zoffset */
876
                              texImage->Width * texelBytes, /* dstRowStride */
877
                              0, /* dstImageStride */
878
                              format, type, pixels, packing);
879
   }
880
 
881
   /* GL_SGIS_generate_mipmap */
882
   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
883
      _mesa_generate_mipmap(ctx, target,
884
                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
885
                            texObj);
886
   }
887
}
888
 
889
 
890
 
891
/*
892
 * This is the software fallback for Driver.TexImage3D()
893
 * and Driver.CopyTexImage3D().
894
 * The texture image type will be GLchan.
895
 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
896
 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
897
 */
898
void
899
_mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
900
                       GLint internalFormat,
901
                       GLint width, GLint height, GLint depth, GLint border,
902
                       GLenum format, GLenum type, const void *pixels,
903
                       const struct gl_pixelstore_attrib *packing,
904
                       struct gl_texture_object *texObj,
905
                       struct gl_texture_image *texImage)
906
{
907
   GLint texelBytes, sizeInBytes;
908
 
909
   /* choose the texture format */
910
   assert(ctx->Driver.ChooseTextureFormat);
911
   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
912
                                          internalFormat, format, type);
913
   assert(texImage->TexFormat);
914
   texImage->FetchTexel = texImage->TexFormat->FetchTexel3D;
915
 
916
   texelBytes = texImage->TexFormat->TexelBytes;
917
 
918
   /* allocate memory */
919
   if (texImage->IsCompressed)
920
      sizeInBytes = texImage->CompressedSize;
921
   else
922
      sizeInBytes = width * height * depth * texelBytes;
923
   texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
924
   if (!texImage->Data) {
925
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
926
      return;
927
   }
928
 
929
   if (!pixels)
930
      return;
931
 
932
   /* unpack image, apply transfer ops and store in texImage->Data */
933
   if (texImage->IsCompressed) {
934
      GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
935
                                                       width);
936
      transfer_compressed_teximage(ctx, 3, width, height, depth,
937
                                   format, type, packing,
938
                                   pixels, texImage->TexFormat,
939
                                   (GLubyte *) texImage->Data, dstRowStride);
940
   }
941
   else {
942
      _mesa_transfer_teximage(ctx, 3,
943
                              texImage->Format,
944
                              texImage->TexFormat, texImage->Data,
945
                              width, height, depth, /* src size */
946
                              0, 0, 0,  /* dstX/Y/Zoffset */
947
                              texImage->Width * texelBytes, /* dstRowStride */
948
                              texImage->Width * texImage->Height * texelBytes,
949
                              format, type, pixels, packing);
950
   }
951
 
952
   /* GL_SGIS_generate_mipmap */
953
   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
954
      _mesa_generate_mipmap(ctx, target,
955
                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
956
                            texObj);
957
   }
958
}
959
 
960
 
961
 
962
 
963
/*
964
 * This is the software fallback for Driver.TexSubImage1D()
965
 * and Driver.CopyTexSubImage1D().
966
 */
967
void
968
_mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
969
                          GLint xoffset, GLint width,
970
                          GLenum format, GLenum type, const void *pixels,
971
                          const struct gl_pixelstore_attrib *packing,
972
                          struct gl_texture_object *texObj,
973
                          struct gl_texture_image *texImage)
974
{
975
   if (texImage->IsCompressed) {
976
      GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
977
                                                       texImage->Width);
978
      GLubyte *dest = _mesa_compressed_image_address(xoffset, 0, 0,
979
                                                     texImage->IntFormat,
980
                                                     texImage->Width,
981
                                                     texImage->Data);
982
      transfer_compressed_teximage(ctx, 1,             /* dimensions */
983
                                   width, 1, 1,        /* size to replace */
984
                                   format, type,       /* source format/type */
985
                                   packing,            /* source packing */
986
                                   pixels,             /* source data */
987
                                   texImage->TexFormat,/* dest format */
988
                                   dest, dstRowStride);
989
   }
990
   else {
991
      _mesa_transfer_teximage(ctx, 1,
992
                              texImage->Format,
993
                              texImage->TexFormat, texImage->Data,
994
                              width, 1, 1, /* src size */
995
                              xoffset, 0, 0, /* dest offsets */
996
                              0, /* dstRowStride */
997
                              0, /* dstImageStride */
998
                              format, type, pixels, packing);
999
   }
1000
 
1001
   /* GL_SGIS_generate_mipmap */
1002
   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1003
      _mesa_generate_mipmap(ctx, target,
1004
                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1005
                            texObj);
1006
   }
1007
}
1008
 
1009
 
1010
 
1011
/*
1012
 * This is the software fallback for Driver.TexSubImage2D()
1013
 * and Driver.CopyTexSubImage2D().
1014
 */
1015
void
1016
_mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
1017
                          GLint xoffset, GLint yoffset,
1018
                          GLint width, GLint height,
1019
                          GLenum format, GLenum type, const void *pixels,
1020
                          const struct gl_pixelstore_attrib *packing,
1021
                          struct gl_texture_object *texObj,
1022
                          struct gl_texture_image *texImage)
1023
{
1024
   if (texImage->IsCompressed) {
1025
      GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1026
                                                       texImage->Width);
1027
      GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
1028
                                                     texImage->IntFormat,
1029
                                                     texImage->Width,
1030
                                                     texImage->Data);
1031
      transfer_compressed_teximage(ctx, 2,             /* dimensions */
1032
                                   width, height, 1,   /* size to replace */
1033
                                   format, type,       /* source format/type */
1034
                                   packing,            /* source packing */
1035
                                   pixels,             /* source data */
1036
                                   texImage->TexFormat,/* dest format */
1037
                                   dest, dstRowStride);
1038
   }
1039
   else {
1040
      _mesa_transfer_teximage(ctx, 2,
1041
                              texImage->Format,
1042
                              texImage->TexFormat, texImage->Data,
1043
                              width, height, 1, /* src size */
1044
                              xoffset, yoffset, 0, /* dest offsets */
1045
                              texImage->Width *texImage->TexFormat->TexelBytes,
1046
                              0, /* dstImageStride */
1047
                              format, type, pixels, packing);
1048
   }
1049
 
1050
   /* GL_SGIS_generate_mipmap */
1051
   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1052
      _mesa_generate_mipmap(ctx, target,
1053
                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1054
                            texObj);
1055
   }
1056
}
1057
 
1058
 
1059
/*
1060
 * This is the software fallback for Driver.TexSubImage3D().
1061
 * and Driver.CopyTexSubImage3D().
1062
 */
1063
void
1064
_mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
1065
                          GLint xoffset, GLint yoffset, GLint zoffset,
1066
                          GLint width, GLint height, GLint depth,
1067
                          GLenum format, GLenum type, const void *pixels,
1068
                          const struct gl_pixelstore_attrib *packing,
1069
                          struct gl_texture_object *texObj,
1070
                          struct gl_texture_image *texImage)
1071
{
1072
   if (texImage->IsCompressed) {
1073
      GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1074
                                                       texImage->Width);
1075
      GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, zoffset,
1076
                                                     texImage->IntFormat,
1077
                                                     texImage->Width,
1078
                                                     texImage->Data);
1079
      transfer_compressed_teximage(ctx, 3,              /* dimensions */
1080
                                   width, height, depth,/* size to replace */
1081
                                   format, type,       /* source format/type */
1082
                                   packing,            /* source packing */
1083
                                   pixels,             /* source data */
1084
                                   texImage->TexFormat,/* dest format */
1085
                                   dest, dstRowStride);
1086
   }
1087
   else {
1088
      const GLint texelBytes = texImage->TexFormat->TexelBytes;
1089
      _mesa_transfer_teximage(ctx, 3,
1090
                           texImage->Format,
1091
                           texImage->TexFormat, texImage->Data,
1092
                           width, height, depth, /* src size */
1093
                           xoffset, yoffset, xoffset, /* dest offsets */
1094
                           texImage->Width * texelBytes,  /* dst row stride */
1095
                           texImage->Width * texImage->Height * texelBytes,
1096
                           format, type, pixels, packing);
1097
   }
1098
 
1099
   /* GL_SGIS_generate_mipmap */
1100
   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1101
      _mesa_generate_mipmap(ctx, target,
1102
                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1103
                            texObj);
1104
   }
1105
}
1106
 
1107
 
1108
 
1109
 
1110
/*
1111
 * Fallback for Driver.CompressedTexImage1D()
1112
 */
1113
void
1114
_mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level,
1115
                                  GLint internalFormat,
1116
                                  GLint width, GLint border,
1117
                                  GLsizei imageSize, const GLvoid *data,
1118
                                  struct gl_texture_object *texObj,
1119
                                  struct gl_texture_image *texImage)
1120
{
1121
   /* this space intentionally left blank */
1122
}
1123
 
1124
 
1125
 
1126
/*
1127
 * Fallback for Driver.CompressedTexImage2D()
1128
 */
1129
void
1130
_mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level,
1131
                                  GLint internalFormat,
1132
                                  GLint width, GLint height, GLint border,
1133
                                  GLsizei imageSize, const GLvoid *data,
1134
                                  struct gl_texture_object *texObj,
1135
                                  struct gl_texture_image *texImage)
1136
{
1137
   /* This is pretty simple, basically just do a memcpy without worrying
1138
    * about the usual image unpacking or image transfer operations.
1139
    */
1140
   ASSERT(texObj);
1141
   ASSERT(texImage);
1142
   ASSERT(texImage->Width > 0);
1143
   ASSERT(texImage->Height > 0);
1144
   ASSERT(texImage->Depth == 1);
1145
   ASSERT(texImage->Data == NULL); /* was freed in glCompressedTexImage2DARB */
1146
 
1147
   /* choose the texture format */
1148
   assert(ctx->Driver.ChooseTextureFormat);
1149
   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1150
                                          internalFormat, 0, 0);
1151
   assert(texImage->TexFormat);
1152
   texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
1153
 
1154
   /* allocate storage */
1155
   texImage->Data = MESA_PBUFFER_ALLOC(imageSize);
1156
   if (!texImage->Data) {
1157
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2DARB");
1158
      return;
1159
   }
1160
 
1161
   /* copy the data */
1162
   ASSERT(texImage->CompressedSize == imageSize);
1163
   MEMCPY(texImage->Data, data, imageSize);
1164
}
1165
 
1166
 
1167
 
1168
/*
1169
 * Fallback for Driver.CompressedTexImage3D()
1170
 */
1171
void
1172
_mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
1173
                                  GLint internalFormat,
1174
                                  GLint width, GLint height, GLint depth,
1175
                                  GLint border,
1176
                                  GLsizei imageSize, const GLvoid *data,
1177
                                  struct gl_texture_object *texObj,
1178
                                  struct gl_texture_image *texImage)
1179
{
1180
   /* this space intentionally left blank */
1181
}
1182
 
1183
 
1184
 
1185
/**
1186
 * Fallback for Driver.CompressedTexSubImage1D()
1187
 */
1188
void
1189
_mesa_store_compressed_texsubimage1d(GLcontext *ctx, GLenum target,
1190
                                     GLint level,
1191
                                     GLint xoffset, GLsizei width,
1192
                                     GLenum format,
1193
                                     GLsizei imageSize, const GLvoid *data,
1194
                                     struct gl_texture_object *texObj,
1195
                                     struct gl_texture_image *texImage)
1196
{
1197
   /* this space intentionally left blank */
1198
}
1199
 
1200
 
1201
/**
1202
 * Fallback for Driver.CompressedTexSubImage2D()
1203
 */
1204
void
1205
_mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target,
1206
                                     GLint level,
1207
                                     GLint xoffset, GLint yoffset,
1208
                                     GLsizei width, GLsizei height,
1209
                                     GLenum format,
1210
                                     GLsizei imageSize, const GLvoid *data,
1211
                                     struct gl_texture_object *texObj,
1212
                                     struct gl_texture_image *texImage)
1213
{
1214
   GLint bytesPerRow, destRowStride, srcRowStride;
1215
   GLint i, rows;
1216
   GLubyte *dest;
1217
   const GLubyte *src;
1218
 
1219
   /* these should have been caught sooner */
1220
   ASSERT((width & 3) == 0 || width == 2 || width == 1);
1221
   ASSERT((height & 3) == 0 || height == 2 || height == 1);
1222
   ASSERT((xoffset & 3) == 0);
1223
   ASSERT((yoffset & 3) == 0);
1224
 
1225
   srcRowStride = _mesa_compressed_row_stride(texImage->IntFormat, width);
1226
   src = (const GLubyte *) data;
1227
 
1228
   destRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1229
                                               texImage->Width);
1230
   dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
1231
                                         texImage->IntFormat,
1232
                                         texImage->Width, texImage->Data);
1233
 
1234
   bytesPerRow = srcRowStride;
1235
   rows = height / 4;
1236
 
1237
   for (i = 0; i < rows; i++) {
1238
      MEMCPY(dest, src, bytesPerRow);
1239
      dest += destRowStride;
1240
      src += srcRowStride;
1241
   }
1242
}
1243
 
1244
 
1245
/**
1246
 * Fallback for Driver.CompressedTexSubImage3D()
1247
 */
1248
void
1249
_mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target,
1250
                                GLint level,
1251
                                GLint xoffset, GLint yoffset, GLint zoffset,
1252
                                GLsizei width, GLsizei height, GLsizei depth,
1253
                                GLenum format,
1254
                                GLsizei imageSize, const GLvoid *data,
1255
                                struct gl_texture_object *texObj,
1256
                                struct gl_texture_image *texImage)
1257
{
1258
   /* this space intentionally left blank */
1259
}
1260
 
1261
 
1262
 
1263
 
1264
 
1265
/*
1266
 * This is the fallback for Driver.TestProxyTexImage().
1267
 */
1268
GLboolean
1269
_mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
1270
                          GLint internalFormat, GLenum format, GLenum type,
1271
                          GLint width, GLint height, GLint depth, GLint border)
1272
{
1273
   struct gl_texture_unit *texUnit;
1274
   struct gl_texture_object *texObj;
1275
   struct gl_texture_image *texImage;
1276
 
1277
   (void) format;
1278
   (void) type;
1279
 
1280
   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1281
   texObj = _mesa_select_tex_object(ctx, texUnit, target);
1282
   texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
1283
 
1284
   /* We always pass.
1285
    * The core Mesa code will have already tested the image size, etc.
1286
    * If a driver has more stringent texture limits to enforce it will
1287
    * have to override this function.
1288
    */
1289
   /* choose the texture format */
1290
   assert(ctx->Driver.ChooseTextureFormat);
1291
   texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1292
                                          internalFormat, format, type);
1293
   assert(texImage->TexFormat);
1294
 
1295
   return GL_TRUE;
1296
}
1297
 
1298
 
1299
 
1300
/*
1301
 * Average together two rows of a source image to produce a single new
1302
 * row in the dest image.  It's legal for the two source rows to point
1303
 * to the same data.  The source width must be equal to either the
1304
 * dest width or two times the dest width.
1305
 */
1306
static void
1307
do_row(const struct gl_texture_format *format, GLint srcWidth,
1308
       const GLvoid *srcRowA, const GLvoid *srcRowB,
1309
       GLint dstWidth, GLvoid *dstRow)
1310
{
1311
   const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
1312
   const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
1313
 
1314
   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
1315
 
1316
   switch (format->MesaFormat) {
1317
   case MESA_FORMAT_RGBA:
1318
      {
1319
         GLuint i, j, k;
1320
         const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
1321
         const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
1322
         GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
1323
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1324
              i++, j += colStride, k += colStride) {
1325
            dst[i][0] = (rowA[j][0] + rowA[k][0] +
1326
                         rowB[j][0] + rowB[k][0]) / 4;
1327
            dst[i][1] = (rowA[j][1] + rowA[k][1] +
1328
                         rowB[j][1] + rowB[k][1]) / 4;
1329
            dst[i][2] = (rowA[j][2] + rowA[k][2] +
1330
                         rowB[j][2] + rowB[k][2]) / 4;
1331
            dst[i][3] = (rowA[j][3] + rowA[k][3] +
1332
                         rowB[j][3] + rowB[k][3]) / 4;
1333
         }
1334
      }
1335
      return;
1336
   case MESA_FORMAT_RGB:
1337
      {
1338
         GLuint i, j, k;
1339
         const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
1340
         const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
1341
         GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
1342
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1343
              i++, j += colStride, k += colStride) {
1344
            dst[i][0] = (rowA[j][0] + rowA[k][0] +
1345
                         rowB[j][0] + rowB[k][0]) / 4;
1346
            dst[i][1] = (rowA[j][1] + rowA[k][1] +
1347
                         rowB[j][1] + rowB[k][1]) / 4;
1348
            dst[i][2] = (rowA[j][2] + rowA[k][2] +
1349
                         rowB[j][2] + rowB[k][2]) / 4;
1350
         }
1351
      }
1352
      return;
1353
   case MESA_FORMAT_ALPHA:
1354
   case MESA_FORMAT_LUMINANCE:
1355
   case MESA_FORMAT_INTENSITY:
1356
   case MESA_FORMAT_COLOR_INDEX:
1357
      {
1358
         GLuint i, j, k;
1359
         const GLchan *rowA = (const GLchan *) srcRowA;
1360
         const GLchan *rowB = (const GLchan *) srcRowB;
1361
         GLchan *dst = (GLchan *) dstRow;
1362
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1363
              i++, j += colStride, k += colStride) {
1364
            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
1365
         }
1366
      }
1367
      return;
1368
   case MESA_FORMAT_LUMINANCE_ALPHA:
1369
      {
1370
         GLuint i, j, k;
1371
         const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
1372
         const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
1373
         GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
1374
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1375
              i++, j += colStride, k += colStride) {
1376
            dst[i][0] = (rowA[j][0] + rowA[k][0] +
1377
                         rowB[j][0] + rowB[k][0]) / 4;
1378
            dst[i][1] = (rowA[j][1] + rowA[k][1] +
1379
                         rowB[j][1] + rowB[k][1]) / 4;
1380
         }
1381
      }
1382
      return;
1383
   case MESA_FORMAT_DEPTH_COMPONENT:
1384
      {
1385
         GLuint i, j, k;
1386
         const GLfloat *rowA = (const GLfloat *) srcRowA;
1387
         const GLfloat *rowB = (const GLfloat *) srcRowB;
1388
         GLfloat *dst = (GLfloat *) dstRow;
1389
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1390
              i++, j += colStride, k += colStride) {
1391
            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
1392
         }
1393
      }
1394
      return;
1395
   /* Begin hardware formats */
1396
   case MESA_FORMAT_RGBA8888:
1397
   case MESA_FORMAT_ARGB8888:
1398
      {
1399
         GLuint i, j, k;
1400
         const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
1401
         const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
1402
         GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
1403
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1404
              i++, j += colStride, k += colStride) {
1405
            dst[i][0] = (rowA[j][0] + rowA[k][0] +
1406
                         rowB[j][0] + rowB[k][0]) / 4;
1407
            dst[i][1] = (rowA[j][1] + rowA[k][1] +
1408
                         rowB[j][1] + rowB[k][1]) / 4;
1409
            dst[i][2] = (rowA[j][2] + rowA[k][2] +
1410
                         rowB[j][2] + rowB[k][2]) / 4;
1411
            dst[i][3] = (rowA[j][3] + rowA[k][3] +
1412
                         rowB[j][3] + rowB[k][3]) / 4;
1413
         }
1414
      }
1415
      return;
1416
   case MESA_FORMAT_RGB888:
1417
      {
1418
         GLuint i, j, k;
1419
         const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
1420
         const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
1421
         GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
1422
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1423
              i++, j += colStride, k += colStride) {
1424
            dst[i][0] = (rowA[j][0] + rowA[k][0] +
1425
                         rowB[j][0] + rowB[k][0]) / 4;
1426
            dst[i][1] = (rowA[j][1] + rowA[k][1] +
1427
                         rowB[j][1] + rowB[k][1]) / 4;
1428
            dst[i][2] = (rowA[j][2] + rowA[k][2] +
1429
                         rowB[j][2] + rowB[k][2]) / 4;
1430
         }
1431
      }
1432
      return;
1433
   case MESA_FORMAT_RGB565:
1434
      {
1435
         GLuint i, j, k;
1436
         const GLushort *rowA = (const GLushort *) srcRowA;
1437
         const GLushort *rowB = (const GLushort *) srcRowB;
1438
         GLushort *dst = (GLushort *) dstRow;
1439
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1440
              i++, j += colStride, k += colStride) {
1441
            const GLint rowAr0 = rowA[j] & 0x1f;
1442
            const GLint rowAr1 = rowA[k] & 0x1f;
1443
            const GLint rowBr0 = rowB[j] & 0x1f;
1444
            const GLint rowBr1 = rowB[k] & 0x1f;
1445
            const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
1446
            const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
1447
            const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
1448
            const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
1449
            const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
1450
            const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
1451
            const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
1452
            const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
1453
            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1454
            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1455
            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1456
            dst[i] = (blue << 11) | (green << 5) | red;
1457
         }
1458
      }
1459
      return;
1460
   case MESA_FORMAT_ARGB4444:
1461
      {
1462
         GLuint i, j, k;
1463
         const GLushort *rowA = (const GLushort *) srcRowA;
1464
         const GLushort *rowB = (const GLushort *) srcRowB;
1465
         GLushort *dst = (GLushort *) dstRow;
1466
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1467
              i++, j += colStride, k += colStride) {
1468
            const GLint rowAr0 = rowA[j] & 0xf;
1469
            const GLint rowAr1 = rowA[k] & 0xf;
1470
            const GLint rowBr0 = rowB[j] & 0xf;
1471
            const GLint rowBr1 = rowB[k] & 0xf;
1472
            const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
1473
            const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
1474
            const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
1475
            const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
1476
            const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
1477
            const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
1478
            const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
1479
            const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
1480
            const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
1481
            const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
1482
            const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
1483
            const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
1484
            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1485
            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1486
            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1487
            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
1488
            dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
1489
         }
1490
      }
1491
      return;
1492
   case MESA_FORMAT_ARGB1555:
1493
      {
1494
         GLuint i, j, k;
1495
         const GLushort *rowA = (const GLushort *) srcRowA;
1496
         const GLushort *rowB = (const GLushort *) srcRowB;
1497
         GLushort *dst = (GLushort *) dstRow;
1498
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1499
              i++, j += colStride, k += colStride) {
1500
            const GLint rowAr0 = rowA[j] & 0x1f;
1501
            const GLint rowAr1 = rowA[k] & 0x1f;
1502
            const GLint rowBr0 = rowB[j] & 0x1f;
1503
            const GLint rowBr1 = rowB[k] & 0xf;
1504
            const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
1505
            const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
1506
            const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
1507
            const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
1508
            const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
1509
            const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
1510
            const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
1511
            const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
1512
            const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
1513
            const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
1514
            const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
1515
            const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
1516
            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1517
            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1518
            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1519
            const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
1520
            dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
1521
         }
1522
      }
1523
      return;
1524
   case MESA_FORMAT_AL88:
1525
      {
1526
         GLuint i, j, k;
1527
         const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
1528
         const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
1529
         GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
1530
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1531
              i++, j += colStride, k += colStride) {
1532
            dst[i][0] = (rowA[j][0] + rowA[k][0] +
1533
                         rowB[j][0] + rowB[k][0]) >> 2;
1534
            dst[i][1] = (rowA[j][1] + rowA[k][1] +
1535
                         rowB[j][1] + rowB[k][1]) >> 2;
1536
         }
1537
      }
1538
      return;
1539
   case MESA_FORMAT_RGB332:
1540
      {
1541
         GLuint i, j, k;
1542
         const GLubyte *rowA = (const GLubyte *) srcRowA;
1543
         const GLubyte *rowB = (const GLubyte *) srcRowB;
1544
         GLubyte *dst = (GLubyte *) dstRow;
1545
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1546
              i++, j += colStride, k += colStride) {
1547
            const GLint rowAr0 = rowA[j] & 0x3;
1548
            const GLint rowAr1 = rowA[k] & 0x3;
1549
            const GLint rowBr0 = rowB[j] & 0x3;
1550
            const GLint rowBr1 = rowB[k] & 0x3;
1551
            const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
1552
            const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
1553
            const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
1554
            const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
1555
            const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
1556
            const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
1557
            const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
1558
            const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
1559
            const GLint red   = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1560
            const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1561
            const GLint blue  = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1562
            dst[i] = (blue << 5) | (green << 2) | red;
1563
         }
1564
      }
1565
      return;
1566
   case MESA_FORMAT_A8:
1567
   case MESA_FORMAT_L8:
1568
   case MESA_FORMAT_I8:
1569
   case MESA_FORMAT_CI8:
1570
      {
1571
         GLuint i, j, k;
1572
         const GLubyte *rowA = (const GLubyte *) srcRowA;
1573
         const GLubyte *rowB = (const GLubyte *) srcRowB;
1574
         GLubyte *dst = (GLubyte *) dstRow;
1575
         for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1576
              i++, j += colStride, k += colStride) {
1577
            dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
1578
         }
1579
      }
1580
      return;
1581
   default:
1582
      _mesa_problem(NULL, "bad format in do_row()");
1583
   }
1584
}
1585
 
1586
 
1587
/*
1588
 * These functions generate a 1/2-size mipmap image from a source image.
1589
 * Texture borders are handled by copying or averaging the source image's
1590
 * border texels, depending on the scale-down factor.
1591
 */
1592
 
1593
static void
1594
make_1d_mipmap(const struct gl_texture_format *format, GLint border,
1595
               GLint srcWidth, const GLubyte *srcPtr,
1596
               GLint dstWidth, GLubyte *dstPtr)
1597
{
1598
   const GLint bpt = format->TexelBytes;
1599
   const GLubyte *src;
1600
   GLubyte *dst;
1601
 
1602
   /* skip the border pixel, if any */
1603
   src = srcPtr + border * bpt;
1604
   dst = dstPtr + border * bpt;
1605
 
1606
   /* we just duplicate the input row, kind of hack, saves code */
1607
   do_row(format, srcWidth - 2 * border, src, src,
1608
          dstWidth - 2 * border, dst);
1609
 
1610
   if (border) {
1611
      /* copy left-most pixel from source */
1612
      MEMCPY(dstPtr, srcPtr, bpt);
1613
      /* copy right-most pixel from source */
1614
      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
1615
             srcPtr + (srcWidth - 1) * bpt,
1616
             bpt);
1617
   }
1618
}
1619
 
1620
 
1621
static void
1622
make_2d_mipmap(const struct gl_texture_format *format, GLint border,
1623
               GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
1624
               GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
1625
{
1626
   const GLint bpt = format->TexelBytes;
1627
   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
1628
   const GLint dstWidthNB = dstWidth - 2 * border;
1629
   const GLint dstHeightNB = dstHeight - 2 * border;
1630
   const GLint srcRowStride = bpt * srcWidth;
1631
   const GLint dstRowStride = bpt * dstWidth;
1632
   const GLubyte *srcA, *srcB;
1633
   GLubyte *dst;
1634
   GLint row, colStride;
1635
 
1636
   colStride = (srcWidth == dstWidth) ? 1 : 2;
1637
 
1638
   /* Compute src and dst pointers, skipping any border */
1639
   srcA = srcPtr + border * ((srcWidth + 1) * bpt);
1640
   if (srcHeight > 1)
1641
      srcB = srcA + srcRowStride;
1642
   else
1643
      srcB = srcA;
1644
   dst = dstPtr + border * ((dstWidth + 1) * bpt);
1645
 
1646
   for (row = 0; row < dstHeightNB; row++) {
1647
      do_row(format, srcWidthNB, srcA, srcB,
1648
             dstWidthNB, dst);
1649
      srcA += 2 * srcRowStride;
1650
      srcB += 2 * srcRowStride;
1651
      dst += dstRowStride;
1652
   }
1653
 
1654
   /* This is ugly but probably won't be used much */
1655
   if (border > 0) {
1656
      /* fill in dest border */
1657
      /* lower-left border pixel */
1658
      MEMCPY(dstPtr, srcPtr, bpt);
1659
      /* lower-right border pixel */
1660
      MEMCPY(dstPtr + (dstWidth - 1) * bpt,
1661
             srcPtr + (srcWidth - 1) * bpt, bpt);
1662
      /* upper-left border pixel */
1663
      MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
1664
             srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
1665
      /* upper-right border pixel */
1666
      MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
1667
             srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
1668
      /* lower border */
1669
      do_row(format, srcWidthNB,
1670
             srcPtr + bpt,
1671
             srcPtr + bpt,
1672
             dstWidthNB, dstPtr + bpt);
1673
      /* upper border */
1674
      do_row(format, srcWidthNB,
1675
             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1676
             srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1677
             dstWidthNB,
1678
             dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
1679
      /* left and right borders */
1680
      if (srcHeight == dstHeight) {
1681
         /* copy border pixel from src to dst */
1682
         for (row = 1; row < srcHeight; row++) {
1683
            MEMCPY(dstPtr + dstWidth * row * bpt,
1684
                   srcPtr + srcWidth * row * bpt, bpt);
1685
            MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
1686
                   srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
1687
         }
1688
      }
1689
      else {
1690
         /* average two src pixels each dest pixel */
1691
         for (row = 0; row < dstHeightNB; row += 2) {
1692
            do_row(format, 1,
1693
                   srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
1694
                   srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
1695
                   1, dstPtr + (dstWidth * row + 1) * bpt);
1696
            do_row(format, 1,
1697
                   srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
1698
                   srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
1699
                   1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
1700
         }
1701
      }
1702
   }
1703
}
1704
 
1705
 
1706
static void
1707
make_3d_mipmap(const struct gl_texture_format *format, GLint border,
1708
               GLint srcWidth, GLint srcHeight, GLint srcDepth,
1709
               const GLubyte *srcPtr,
1710
               GLint dstWidth, GLint dstHeight, GLint dstDepth,
1711
               GLubyte *dstPtr)
1712
{
1713
   const GLint bpt = format->TexelBytes;
1714
   const GLint srcWidthNB = srcWidth - 2 * border;  /* sizes w/out border */
1715
   const GLint srcDepthNB = srcDepth - 2 * border;
1716
   const GLint dstWidthNB = dstWidth - 2 * border;
1717
   const GLint dstHeightNB = dstHeight - 2 * border;
1718
   const GLint dstDepthNB = dstDepth - 2 * border;
1719
   GLvoid *tmpRowA, *tmpRowB;
1720
   GLint img, row;
1721
   GLint bytesPerSrcImage, bytesPerDstImage;
1722
   GLint bytesPerSrcRow, bytesPerDstRow;
1723
   GLint srcImageOffset, srcRowOffset;
1724
 
1725
   (void) srcDepthNB; /* silence warnings */
1726
 
1727
   /* Need two temporary row buffers */
1728
   tmpRowA = MALLOC(srcWidth * bpt);
1729
   if (!tmpRowA)
1730
      return;
1731
   tmpRowB = MALLOC(srcWidth * bpt);
1732
   if (!tmpRowB) {
1733
      FREE(tmpRowA);
1734
      return;
1735
   }
1736
 
1737
   bytesPerSrcImage = srcWidth * srcHeight * bpt;
1738
   bytesPerDstImage = dstWidth * dstHeight * bpt;
1739
 
1740
   bytesPerSrcRow = srcWidth * bpt;
1741
   bytesPerDstRow = dstWidth * bpt;
1742
 
1743
   /* Offset between adjacent src images to be averaged together */
1744
   srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
1745
 
1746
   /* Offset between adjacent src rows to be averaged together */
1747
   srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
1748
 
1749
   /*
1750
    * Need to average together up to 8 src pixels for each dest pixel.
1751
    * Break that down into 3 operations:
1752
    *   1. take two rows from source image and average them together.
1753
    *   2. take two rows from next source image and average them together.
1754
    *   3. take the two averaged rows and average them for the final dst row.
1755
    */
1756
 
1757
   /*
1758
   _mesa_printf("mip3d %d x %d x %d  ->  %d x %d x %d\n",
1759
          srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
1760
   */
1761
 
1762
   for (img = 0; img < dstDepthNB; img++) {
1763
      /* first source image pointer, skipping border */
1764
      const GLubyte *imgSrcA = srcPtr
1765
         + (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
1766
         + img * (bytesPerSrcImage + srcImageOffset);
1767
      /* second source image pointer, skipping border */
1768
      const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
1769
      /* address of the dest image, skipping border */
1770
      GLubyte *imgDst = dstPtr
1771
         + (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
1772
         + img * bytesPerDstImage;
1773
 
1774
      /* setup the four source row pointers and the dest row pointer */
1775
      const GLubyte *srcImgARowA = imgSrcA;
1776
      const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
1777
      const GLubyte *srcImgBRowA = imgSrcB;
1778
      const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
1779
      GLubyte *dstImgRow = imgDst;
1780
 
1781
      for (row = 0; row < dstHeightNB; row++) {
1782
         /* Average together two rows from first src image */
1783
         do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
1784
                srcWidthNB, tmpRowA);
1785
         /* Average together two rows from second src image */
1786
         do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
1787
                srcWidthNB, tmpRowB);
1788
         /* Average together the temp rows to make the final row */
1789
         do_row(format, srcWidthNB, tmpRowA, tmpRowB,
1790
                dstWidthNB, dstImgRow);
1791
         /* advance to next rows */
1792
         srcImgARowA += bytesPerSrcRow + srcRowOffset;
1793
         srcImgARowB += bytesPerSrcRow + srcRowOffset;
1794
         srcImgBRowA += bytesPerSrcRow + srcRowOffset;
1795
         srcImgBRowB += bytesPerSrcRow + srcRowOffset;
1796
         dstImgRow += bytesPerDstRow;
1797
      }
1798
   }
1799
 
1800
   FREE(tmpRowA);
1801
   FREE(tmpRowB);
1802
 
1803
   /* Luckily we can leverage the make_2d_mipmap() function here! */
1804
   if (border > 0) {
1805
      /* do front border image */
1806
      make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
1807
                     dstWidth, dstHeight, dstPtr);
1808
      /* do back border image */
1809
      make_2d_mipmap(format, 1, srcWidth, srcHeight,
1810
                     srcPtr + bytesPerSrcImage * (srcDepth - 1),
1811
                     dstWidth, dstHeight,
1812
                     dstPtr + bytesPerDstImage * (dstDepth - 1));
1813
      /* do four remaining border edges that span the image slices */
1814
      if (srcDepth == dstDepth) {
1815
         /* just copy border pixels from src to dst */
1816
         for (img = 0; img < dstDepthNB; img++) {
1817
            const GLubyte *src;
1818
            GLubyte *dst;
1819
 
1820
            /* do border along [img][row=0][col=0] */
1821
            src = srcPtr + (img + 1) * bytesPerSrcImage;
1822
            dst = dstPtr + (img + 1) * bytesPerDstImage;
1823
            MEMCPY(dst, src, bpt);
1824
 
1825
            /* do border along [img][row=dstHeight-1][col=0] */
1826
            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1827
                         + (srcHeight - 1) * bytesPerSrcRow;
1828
            dst = dstPtr + (img + 1) * bytesPerDstImage
1829
                         + (dstHeight - 1) * bytesPerDstRow;
1830
            MEMCPY(dst, src, bpt);
1831
 
1832
            /* do border along [img][row=0][col=dstWidth-1] */
1833
            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1834
                         + (srcWidth - 1) * bpt;
1835
            dst = dstPtr + (img + 1) * bytesPerDstImage
1836
                         + (dstWidth - 1) * bpt;
1837
            MEMCPY(dst, src, bpt);
1838
 
1839
            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1840
            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1841
                         + (bytesPerSrcImage - bpt);
1842
            dst = dstPtr + (img + 1) * bytesPerDstImage
1843
                         + (bytesPerDstImage - bpt);
1844
            MEMCPY(dst, src, bpt);
1845
         }
1846
      }
1847
      else {
1848
         /* average border pixels from adjacent src image pairs */
1849
         ASSERT(srcDepthNB == 2 * dstDepthNB);
1850
         for (img = 0; img < dstDepthNB; img++) {
1851
            const GLubyte *src;
1852
            GLubyte *dst;
1853
 
1854
            /* do border along [img][row=0][col=0] */
1855
            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
1856
            dst = dstPtr + (img + 1) * bytesPerDstImage;
1857
            do_row(format, 1, src, src + srcImageOffset, 1, dst);
1858
 
1859
            /* do border along [img][row=dstHeight-1][col=0] */
1860
            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1861
                         + (srcHeight - 1) * bytesPerSrcRow;
1862
            dst = dstPtr + (img + 1) * bytesPerDstImage
1863
                         + (dstHeight - 1) * bytesPerDstRow;
1864
            do_row(format, 1, src, src + srcImageOffset, 1, dst);
1865
 
1866
            /* do border along [img][row=0][col=dstWidth-1] */
1867
            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1868
                         + (srcWidth - 1) * bpt;
1869
            dst = dstPtr + (img + 1) * bytesPerDstImage
1870
                         + (dstWidth - 1) * bpt;
1871
            do_row(format, 1, src, src + srcImageOffset, 1, dst);
1872
 
1873
            /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1874
            src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1875
                         + (bytesPerSrcImage - bpt);
1876
            dst = dstPtr + (img + 1) * bytesPerDstImage
1877
                         + (bytesPerDstImage - bpt);
1878
            do_row(format, 1, src, src + srcImageOffset, 1, dst);
1879
         }
1880
      }
1881
   }
1882
}
1883
 
1884
 
1885
/*
1886
 * For GL_SGIX_generate_mipmap:
1887
 * Generate a complete set of mipmaps from texObj's base-level image.
1888
 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
1889
 */
1890
void
1891
_mesa_generate_mipmap(GLcontext *ctx, GLenum target,
1892
                      const struct gl_texture_unit *texUnit,
1893
                      struct gl_texture_object *texObj)
1894
{
1895
   const struct gl_texture_image *srcImage;
1896
   const struct gl_texture_format *convertFormat;
1897
   const GLubyte *srcData;
1898
   GLubyte *dstData;
1899
   GLint level, maxLevels;
1900
 
1901
   ASSERT(texObj);
1902
   srcImage = texObj->Image[texObj->BaseLevel];
1903
   ASSERT(srcImage);
1904
 
1905
   maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
1906
   ASSERT(maxLevels > 0);  /* bad target */
1907
 
1908
   /* Find convertFormat - the format that do_row() will process */
1909
   if (srcImage->IsCompressed) {
1910
      /* setup for compressed textures */
1911
      GLuint row;
1912
      GLint  components, size;
1913
      GLchan *dst;
1914
 
1915
      assert(texObj->Target == GL_TEXTURE_2D);
1916
 
1917
      if (srcImage->Format == GL_RGB) {
1918
         convertFormat = &_mesa_texformat_rgb;
1919
         components = 3;
1920
      }
1921
      else if (srcImage->Format == GL_RGBA) {
1922
         convertFormat = &_mesa_texformat_rgba;
1923
         components = 4;
1924
      }
1925
      else {
1926
         _mesa_problem(ctx, "bad srcImage->Format in _mesa_generate_mipmaps");
1927
         return;
1928
      }
1929
 
1930
      /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
1931
      size = _mesa_bytes_per_pixel(srcImage->Format, CHAN_TYPE)
1932
         * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
1933
      /* 20 extra bytes, just be safe when calling last FetchTexel */
1934
      srcData = MALLOC(size);
1935
      if (!srcData) {
1936
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
1937
         return;
1938
      }
1939
      dstData = MALLOC(size / 2);  /* 1/4 would probably be OK */
1940
      if (!dstData) {
1941
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
1942
         FREE((void *) srcData);
1943
         return;
1944
      }
1945
 
1946
      /* decompress base image here */
1947
      dst = (GLchan *) srcData;
1948
      for (row = 0; row < srcImage->Height; row++) {
1949
         GLuint col;
1950
         for (col = 0; col < srcImage->Width; col++) {
1951
            (*srcImage->FetchTexel)(srcImage, col, row, 0, (GLvoid *) dst);
1952
            dst += components;
1953
         }
1954
      }
1955
   }
1956
   else {
1957
      /* uncompressed */
1958
      convertFormat = srcImage->TexFormat;
1959
   }
1960
 
1961
   for (level = texObj->BaseLevel; level < texObj->MaxLevel
1962
           && level < maxLevels - 1; level++) {
1963
      /* generate image[level+1] from image[level] */
1964
      const struct gl_texture_image *srcImage;
1965
      struct gl_texture_image *dstImage;
1966
      GLint srcWidth, srcHeight, srcDepth;
1967
      GLint dstWidth, dstHeight, dstDepth;
1968
      GLint border, bytesPerTexel;
1969
 
1970
      /* get src image parameters */
1971
      srcImage = texObj->Image[level];
1972
      ASSERT(srcImage);
1973
      srcWidth = srcImage->Width;
1974
      srcHeight = srcImage->Height;
1975
      srcDepth = srcImage->Depth;
1976
      border = srcImage->Border;
1977
 
1978
      /* compute next (level+1) image size */
1979
      if (srcWidth - 2 * border > 1) {
1980
         dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1981
      }
1982
      else {
1983
         dstWidth = srcWidth; /* can't go smaller */
1984
      }
1985
      if (srcHeight - 2 * border > 1) {
1986
         dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1987
      }
1988
      else {
1989
         dstHeight = srcHeight; /* can't go smaller */
1990
      }
1991
      if (srcDepth - 2 * border > 1) {
1992
         dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1993
      }
1994
      else {
1995
         dstDepth = srcDepth; /* can't go smaller */
1996
      }
1997
 
1998
      if (dstWidth == srcWidth &&
1999
          dstHeight == srcHeight &&
2000
          dstDepth == srcDepth) {
2001
         /* all done */
2002
         if (srcImage->IsCompressed) {
2003
            FREE((void *) srcData);
2004
            FREE(dstData);
2005
         }
2006
         return;
2007
      }
2008
 
2009
      /* get dest gl_texture_image */
2010
      dstImage = _mesa_select_tex_image(ctx, texUnit, target, level+1);
2011
      if (!dstImage) {
2012
         dstImage = _mesa_alloc_texture_image();
2013
         if (!dstImage) {
2014
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
2015
            return;
2016
         }
2017
         _mesa_set_tex_image(texObj, target, level + 1, dstImage);
2018
      }
2019
 
2020
      /* Free old image data */
2021
      if (dstImage->Data)
2022
         MESA_PBUFFER_FREE(dstImage->Data);
2023
 
2024
      /* initialize new image */
2025
      _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
2026
                                 dstDepth, border, srcImage->IntFormat);
2027
      dstImage->DriverData = NULL;
2028
      dstImage->TexFormat = srcImage->TexFormat;
2029
      dstImage->FetchTexel = srcImage->FetchTexel;
2030
      ASSERT(dstImage->TexFormat);
2031
      ASSERT(dstImage->FetchTexel);
2032
 
2033
      /* Alloc new teximage data buffer.
2034
       * Setup src and dest data pointers.
2035
       */
2036
      if (dstImage->IsCompressed) {
2037
         ASSERT(dstImage->CompressedSize > 0); /* set by init_teximage_fields*/
2038
         dstImage->Data = MESA_PBUFFER_ALLOC(dstImage->CompressedSize);
2039
         if (!dstImage->Data) {
2040
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
2041
            return;
2042
         }
2043
         /* srcData and dstData are already set */
2044
         ASSERT(srcData);
2045
         ASSERT(dstData);
2046
      }
2047
      else {
2048
         bytesPerTexel = srcImage->TexFormat->TexelBytes;
2049
         ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
2050
         dstImage->Data = MESA_PBUFFER_ALLOC(dstWidth * dstHeight * dstDepth
2051
                                             * bytesPerTexel);
2052
         if (!dstImage->Data) {
2053
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
2054
            return;
2055
         }
2056
         srcData = (const GLubyte *) srcImage->Data;
2057
         dstData = (GLubyte *) dstImage->Data;
2058
      }
2059
 
2060
      /*
2061
       * We use simple 2x2 averaging to compute the next mipmap level.
2062
       */
2063
      switch (target) {
2064
         case GL_TEXTURE_1D:
2065
            make_1d_mipmap(convertFormat, border,
2066
                           srcWidth, srcData,
2067
                           dstWidth, dstData);
2068
            break;
2069
         case GL_TEXTURE_2D:
2070
         case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
2071
         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
2072
         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
2073
         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
2074
         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
2075
         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
2076
            make_2d_mipmap(convertFormat, border,
2077
                           srcWidth, srcHeight, srcData,
2078
                           dstWidth, dstHeight, dstData);
2079
            break;
2080
         case GL_TEXTURE_3D:
2081
            make_3d_mipmap(convertFormat, border,
2082
                           srcWidth, srcHeight, srcDepth, srcData,
2083
                           dstWidth, dstHeight, dstDepth, dstData);
2084
            break;
2085
         case GL_TEXTURE_RECTANGLE_NV:
2086
            /* no mipmaps, do nothing */
2087
            break;
2088
         default:
2089
            _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
2090
            return;
2091
      }
2092
 
2093
      if (dstImage->IsCompressed) {
2094
         GLubyte *temp;
2095
         /* compress image from dstData into dstImage->Data */
2096
         const GLenum srcFormat = convertFormat->BaseFormat;
2097
         GLint dstRowStride = _mesa_compressed_row_stride(srcImage->IntFormat,
2098
                                                          dstWidth);
2099
         ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
2100
         _mesa_compress_teximage(ctx,
2101
                                 dstWidth, dstHeight, /* size */
2102
                                 srcFormat,           /* source format */
2103
                                 dstData,             /* source buffer */
2104
                                 dstWidth,            /* source row stride */
2105
                                 dstImage->TexFormat, /* dest format */
2106
                                 dstImage->Data,      /* dest buffer */
2107
                                 dstRowStride );      /* dest row stride */
2108
 
2109
         /* swap src and dest pointers */
2110
         temp = (GLubyte *) srcData;
2111
         srcData = dstData;
2112
         dstData = temp;
2113
      }
2114
 
2115
   } /* loop over mipmap levels */
2116
}