1 /* $Id: texstore.c,v 1.41 2002/09/21 16:51:25 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
38 #include "texformat.h"
45 * Given an internal texture format enum or 1, 2, 3, 4 return the
46 * corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE,
47 * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA. Return the
48 * number of components for the format. Return -1 if invalid enum.
50 * GH: Do we really need this? We have the number of bytes per texel
51 * in the texture format structures, so why don't we just use that?
54 components_in_intformat( GLint format
)
71 case GL_LUMINANCE_ALPHA
:
72 case GL_LUMINANCE4_ALPHA4
:
73 case GL_LUMINANCE6_ALPHA2
:
74 case GL_LUMINANCE8_ALPHA8
:
75 case GL_LUMINANCE12_ALPHA4
:
76 case GL_LUMINANCE12_ALPHA12
:
77 case GL_LUMINANCE16_ALPHA16
:
106 case GL_COLOR_INDEX1_EXT
:
107 case GL_COLOR_INDEX2_EXT
:
108 case GL_COLOR_INDEX4_EXT
:
109 case GL_COLOR_INDEX8_EXT
:
110 case GL_COLOR_INDEX12_EXT
:
111 case GL_COLOR_INDEX16_EXT
:
113 case GL_DEPTH_COMPONENT
:
114 case GL_DEPTH_COMPONENT16_SGIX
:
115 case GL_DEPTH_COMPONENT24_SGIX
:
116 case GL_DEPTH_COMPONENT32_SGIX
:
119 return 2; /* Y + (Cb or Cr) */
121 return -1; /* error */
127 * This function is used to transfer the user's image data into a texture
128 * image buffer. We handle both full texture images and subtexture images.
129 * We also take care of all image transfer operations here, including
130 * convolution, scale/bias, colortables, etc.
132 * The destination texel channel type is always GLchan.
134 * A hardware driver may use this as a helper routine to unpack and
135 * apply pixel transfer ops into a temporary image buffer. Then,
136 * convert the temporary image into the special hardware format.
139 * dimensions - 1, 2, or 3
140 * texFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA,
142 * texDestAddr - destination image address
143 * srcWidth, srcHeight, srcDepth - size (in pixels) of src and dest images
144 * dstXoffset, dstYoffset, dstZoffset - position to store the image within
145 * the destination 3D texture
146 * dstRowStride, dstImageStride - dest image strides in bytes
147 * srcFormat - source image format (GL_ALPHA, GL_RED, GL_RGB, etc)
148 * srcType - GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_FLOAT, etc
149 * srcPacking - describes packing of incoming image.
150 * transferOps - mask of pixel transfer operations
153 transfer_teximage(GLcontext
*ctx
, GLuint dimensions
,
154 GLenum texDestFormat
, GLvoid
*texDestAddr
,
155 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
156 GLint dstXoffset
, GLint dstYoffset
, GLint dstZoffset
,
157 GLint dstRowStride
, GLint dstImageStride
,
158 GLenum srcFormat
, GLenum srcType
,
159 const GLvoid
*srcAddr
,
160 const struct gl_pixelstore_attrib
*srcPacking
,
166 ASSERT(dimensions
>= 1 && dimensions
<= 3);
168 ASSERT(srcWidth
>= 1);
169 ASSERT(srcHeight
>= 1);
170 ASSERT(srcDepth
>= 1);
171 ASSERT(dstXoffset
>= 0);
172 ASSERT(dstYoffset
>= 0);
173 ASSERT(dstZoffset
>= 0);
174 ASSERT(dstRowStride
>= 0);
175 ASSERT(dstImageStride
>= 0);
179 texComponents
= components_in_intformat(texDestFormat
);
181 /* try common 2D texture cases first */
182 if (!transferOps
&& dimensions
== 2 && srcType
== CHAN_TYPE
) {
184 if (srcFormat
== texDestFormat
) {
185 /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA,
186 * GL_LUMINANCE_ALPHA, etc. texture formats. Use memcpy().
188 const GLchan
*src
= (const GLchan
*) _mesa_image_address(
189 srcPacking
, srcAddr
, srcWidth
, srcHeight
,
190 srcFormat
, srcType
, 0, 0, 0);
191 const GLint srcRowStride
= _mesa_image_row_stride(srcPacking
,
192 srcWidth
, srcFormat
, srcType
);
193 const GLint widthInBytes
= srcWidth
* texComponents
* sizeof(GLchan
);
194 GLchan
*dst
= (GLchan
*) texDestAddr
195 + dstYoffset
* (dstRowStride
/ sizeof(GLchan
))
196 + dstXoffset
* texComponents
;
197 if (srcRowStride
== widthInBytes
&& dstRowStride
== widthInBytes
) {
198 MEMCPY(dst
, src
, srcHeight
* widthInBytes
);
202 for (i
= 0; i
< srcHeight
; i
++) {
203 MEMCPY(dst
, src
, widthInBytes
);
204 src
+= (srcRowStride
/ sizeof(GLchan
));
205 dst
+= (dstRowStride
/ sizeof(GLchan
));
208 return; /* all done */
210 else if (srcFormat
== GL_RGBA
&& texDestFormat
== GL_RGB
) {
211 /* commonly used by Quake */
212 const GLchan
*src
= (const GLchan
*) _mesa_image_address(
213 srcPacking
, srcAddr
, srcWidth
, srcHeight
,
214 srcFormat
, srcType
, 0, 0, 0);
215 const GLint srcRowStride
= _mesa_image_row_stride(srcPacking
,
216 srcWidth
, srcFormat
, srcType
);
217 GLchan
*dst
= (GLchan
*) texDestAddr
218 + dstYoffset
* (dstRowStride
/ sizeof(GLchan
))
219 + dstXoffset
* texComponents
;
221 for (i
= 0; i
< srcHeight
; i
++) {
222 const GLchan
*s
= src
;
224 for (j
= 0; j
< srcWidth
; j
++) {
226 *d
++ = *s
++; /*green*/
227 *d
++ = *s
++; /*blue*/
230 src
+= (srcRowStride
/ sizeof(GLchan
));
231 dst
+= (dstRowStride
/ sizeof(GLchan
));
233 return; /* all done */
238 * General case solutions
240 if (texDestFormat
== GL_COLOR_INDEX
) {
241 /* color index texture */
242 const GLenum texType
= CHAN_TYPE
;
244 GLchan
*dest
= (GLchan
*) texDestAddr
245 + dstZoffset
* (dstImageStride
/ sizeof(GLchan
))
246 + dstYoffset
* (dstRowStride
/ sizeof(GLchan
))
247 + dstXoffset
* texComponents
;
248 for (img
= 0; img
< srcDepth
; img
++) {
249 GLchan
*destRow
= dest
;
250 for (row
= 0; row
< srcHeight
; row
++) {
251 const GLvoid
*src
= _mesa_image_address(srcPacking
,
252 srcAddr
, srcWidth
, srcHeight
, srcFormat
, srcType
, img
, row
, 0);
253 _mesa_unpack_index_span(ctx
, srcWidth
, texType
, destRow
,
254 srcType
, src
, srcPacking
, transferOps
);
255 destRow
+= (dstRowStride
/ sizeof(GLchan
));
257 dest
+= dstImageStride
;
260 else if (texDestFormat
== GL_YCBCR_MESA
) {
263 GLushort
*dest
= (GLushort
*) texDestAddr
264 + dstZoffset
* (dstImageStride
/ sizeof(GLushort
))
265 + dstYoffset
* (dstRowStride
/ sizeof(GLushort
))
266 + dstXoffset
* texComponents
;
267 ASSERT(ctx
->Extensions
.MESA_ycbcr_texture
);
268 printf("copy ycbcr\n");
269 for (img
= 0; img
< srcDepth
; img
++) {
270 GLushort
*destRow
= dest
;
271 for (row
= 0; row
< srcHeight
; row
++) {
272 const GLvoid
*srcRow
= _mesa_image_address(srcPacking
,
273 srcAddr
, srcWidth
, srcHeight
,
274 srcFormat
, srcType
, img
, row
, 0);
275 MEMCPY(destRow
, srcRow
, srcWidth
* sizeof(GLushort
));
276 destRow
+= (dstRowStride
/ sizeof(GLushort
));
278 dest
+= dstImageStride
/ sizeof(GLushort
);
281 else if (texDestFormat
== GL_DEPTH_COMPONENT
) {
282 /* Depth texture (shadow maps) */
284 GLubyte
*dest
= (GLubyte
*) texDestAddr
285 + dstZoffset
* dstImageStride
286 + dstYoffset
* (dstRowStride
/ sizeof(GLchan
))
287 + dstXoffset
* texComponents
;
288 for (img
= 0; img
< srcDepth
; img
++) {
289 GLubyte
*destRow
= dest
;
290 for (row
= 0; row
< srcHeight
; row
++) {
291 const GLvoid
*src
= _mesa_image_address(srcPacking
,
292 srcAddr
, srcWidth
, srcHeight
, srcFormat
, srcType
, img
, row
, 0);
293 _mesa_unpack_depth_span(ctx
, srcWidth
, (GLfloat
*) destRow
,
294 srcType
, src
, srcPacking
);
295 destRow
+= (dstRowStride
/ sizeof(GLchan
));
297 dest
+= dstImageStride
;
301 /* regular, color texture */
302 if ((dimensions
== 1 && ctx
->Pixel
.Convolution1DEnabled
) ||
303 (dimensions
>= 2 && ctx
->Pixel
.Convolution2DEnabled
) ||
304 (dimensions
>= 2 && ctx
->Pixel
.Separable2DEnabled
)) {
306 * Fill texture image with convolution
309 GLint convWidth
= srcWidth
, convHeight
= srcHeight
;
310 GLfloat
*tmpImage
, *convImage
;
311 tmpImage
= (GLfloat
*) MALLOC(srcWidth
* srcHeight
* 4 * sizeof(GLfloat
));
313 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTexImage");
316 convImage
= (GLfloat
*) MALLOC(srcWidth
* srcHeight
* 4 * sizeof(GLfloat
));
318 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTexImage");
323 for (img
= 0; img
< srcDepth
; img
++) {
325 GLfloat
*dstf
= tmpImage
;
328 /* unpack and do transfer ops up to convolution */
329 for (row
= 0; row
< srcHeight
; row
++) {
330 const GLvoid
*src
= _mesa_image_address(srcPacking
,
331 srcAddr
, srcWidth
, srcHeight
,
332 srcFormat
, srcType
, img
, row
, 0);
333 _mesa_unpack_float_color_span(ctx
, srcWidth
, GL_RGBA
, dstf
,
334 srcFormat
, srcType
, src
, srcPacking
,
335 transferOps
& IMAGE_PRE_CONVOLUTION_BITS
,
337 dstf
+= srcWidth
* 4;
341 if (dimensions
== 1) {
342 ASSERT(ctx
->Pixel
.Convolution1DEnabled
);
343 _mesa_convolve_1d_image(ctx
, &convWidth
, tmpImage
, convImage
);
346 if (ctx
->Pixel
.Convolution2DEnabled
) {
347 _mesa_convolve_2d_image(ctx
, &convWidth
, &convHeight
,
348 tmpImage
, convImage
);
351 ASSERT(ctx
->Pixel
.Separable2DEnabled
);
352 _mesa_convolve_sep_image(ctx
, &convWidth
, &convHeight
,
353 tmpImage
, convImage
);
357 /* packing and transfer ops after convolution */
359 dest
= (GLchan
*) texDestAddr
360 + (dstZoffset
+ img
) * (dstImageStride
/ sizeof(GLchan
))
361 + dstYoffset
* (dstRowStride
/ sizeof(GLchan
));
362 for (row
= 0; row
< convHeight
; row
++) {
363 _mesa_pack_float_rgba_span(ctx
, convWidth
,
364 (const GLfloat (*)[4]) srcf
,
365 texDestFormat
, CHAN_TYPE
,
366 dest
, &_mesa_native_packing
,
368 & IMAGE_POST_CONVOLUTION_BITS
);
369 srcf
+= convWidth
* 4;
370 dest
+= (dstRowStride
/ sizeof(GLchan
));
382 GLchan
*dest
= (GLchan
*) texDestAddr
383 + dstZoffset
* (dstImageStride
/ sizeof(GLchan
))
384 + dstYoffset
* (dstRowStride
/ sizeof(GLchan
))
385 + dstXoffset
* texComponents
;
386 for (img
= 0; img
< srcDepth
; img
++) {
387 GLchan
*destRow
= dest
;
388 for (row
= 0; row
< srcHeight
; row
++) {
389 const GLvoid
*srcRow
= _mesa_image_address(srcPacking
,
390 srcAddr
, srcWidth
, srcHeight
,
391 srcFormat
, srcType
, img
, row
, 0);
392 _mesa_unpack_chan_color_span(ctx
, srcWidth
, texDestFormat
,
393 destRow
, srcFormat
, srcType
, srcRow
,
394 srcPacking
, transferOps
);
395 destRow
+= (dstRowStride
/ sizeof(GLchan
));
397 dest
+= dstImageStride
/ sizeof(GLchan
);
406 * Transfer a texture image from user space to <destAddr> applying all
407 * needed image transfer operations and storing the result in the format
408 * specified by <dstFormat>. <dstFormat> may be any format from texformat.h.
410 * dimensions - 1, 2 or 3
411 * baseInternalFormat - base format of the internal texture format
412 * specified by the user. This is very important, see below.
413 * dstFormat - destination image format
414 * dstAddr - destination address
415 * srcWidth, srcHeight, srcDepth - size of source iamge
416 * dstX/Y/Zoffset - as specified by glTexSubImage
417 * dstRowStride - stride between dest rows in bytes
418 * dstImageStride - stride between dest images in bytes
419 * srcFormat, srcType - incoming image format and datatype
420 * srcAddr - source image address
421 * srcPacking - packing params of source image
423 * XXX this function is a bit more complicated than it should be. If
424 * _mesa_convert_texsubimage[123]d could handle any dest/source formats
425 * or if transfer_teximage() could store in any MESA_FORMAT_* format, we
426 * could simplify things here.
429 _mesa_transfer_teximage(GLcontext
*ctx
, GLuint dimensions
,
430 GLenum baseInternalFormat
,
431 const struct gl_texture_format
*dstFormat
,
433 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
434 GLint dstXoffset
, GLint dstYoffset
, GLint dstZoffset
,
435 GLint dstRowStride
, GLint dstImageStride
,
436 GLenum srcFormat
, GLenum srcType
,
437 const GLvoid
*srcAddr
,
438 const struct gl_pixelstore_attrib
*srcPacking
)
440 const GLint dstRowStridePixels
= dstRowStride
/ dstFormat
->TexelBytes
;
441 const GLint dstImageStridePixels
= dstImageStride
/ dstFormat
->TexelBytes
;
443 GLuint transferOps
= ctx
->_ImageTransferState
;
444 GLboolean freeSourceData
= GL_FALSE
;
445 GLint postConvWidth
= srcWidth
, postConvHeight
= srcHeight
;
447 assert(baseInternalFormat
> 0);
449 if (transferOps
& IMAGE_CONVOLUTION_BIT
) {
450 _mesa_adjust_image_for_convolution(ctx
, dimensions
, &postConvWidth
,
455 * Consider this scenario: The user's source image is GL_RGB and the
456 * requested internal format is GL_LUMINANCE. Now suppose the device
457 * driver doesn't support GL_LUMINANCE and instead uses RGB16 as the
458 * texture format. In that case we still need to do an intermediate
459 * conversion to luminance format so that the incoming red channel gets
460 * replicated into the dest red, green and blue channels. The following
461 * code takes care of that.
463 if (dstFormat
->BaseFormat
!= baseInternalFormat
) {
464 /* Allocate storage for temporary image in the baseInternalFormat */
465 const GLint texelSize
= _mesa_components_in_format(baseInternalFormat
)
467 const GLint bytes
= texelSize
* postConvWidth
* postConvHeight
*srcDepth
;
468 const GLint tmpRowStride
= texelSize
* postConvWidth
;
469 const GLint tmpImgStride
= texelSize
* postConvWidth
* postConvHeight
;
470 GLvoid
*tmpImage
= MALLOC(bytes
);
473 transfer_teximage(ctx
, dimensions
, baseInternalFormat
, tmpImage
,
474 srcWidth
, srcHeight
, srcDepth
,
475 0, 0, 0, /* x/y/zoffset */
476 tmpRowStride
, tmpImgStride
,
477 srcFormat
, srcType
, srcAddr
, srcPacking
, transferOps
);
479 /* this is our new source image */
480 srcWidth
= postConvWidth
;
481 srcHeight
= postConvHeight
;
482 srcFormat
= baseInternalFormat
;
485 srcPacking
= &_mesa_native_packing
;
486 freeSourceData
= GL_TRUE
;
487 transferOps
= 0; /* image transfer ops were completed */
490 /* Let the optimized tex conversion functions take a crack at the
491 * image conversion if the dest format is a h/w format.
493 if (_mesa_is_hardware_tex_format(dstFormat
)) {
498 if (dimensions
== 1) {
499 makeTemp
= !_mesa_convert_texsubimage1d(dstFormat
->MesaFormat
,
506 else if (dimensions
== 2) {
507 makeTemp
= !_mesa_convert_texsubimage2d(dstFormat
->MesaFormat
,
508 dstXoffset
, dstYoffset
,
516 assert(dimensions
== 3);
517 makeTemp
= !_mesa_convert_texsubimage3d(dstFormat
->MesaFormat
,
518 dstXoffset
, dstYoffset
, dstZoffset
,
519 srcWidth
, srcHeight
, srcDepth
,
520 dstRowStridePixels
, dstImageStridePixels
,
522 srcPacking
, srcAddr
, dstAddr
);
527 FREE((void *) srcAddr
);
533 /* software texture format */
538 GLint postConvWidth
= srcWidth
, postConvHeight
= srcHeight
;
540 GLuint tmpComps
, tmpTexelSize
;
541 GLint tmpRowStride
, tmpImageStride
;
544 if (transferOps
& IMAGE_CONVOLUTION_BIT
) {
545 _mesa_adjust_image_for_convolution(ctx
, dimensions
, &postConvWidth
,
549 tmpFormat
= dstFormat
->BaseFormat
;
550 tmpComps
= _mesa_components_in_format(tmpFormat
);
551 tmpTexelSize
= tmpComps
* sizeof(GLchan
);
552 tmpRowStride
= postConvWidth
* tmpTexelSize
;
553 tmpImageStride
= postConvWidth
* postConvHeight
* tmpTexelSize
;
554 tmpImage
= (GLubyte
*) MALLOC(postConvWidth
* postConvHeight
*
555 srcDepth
* tmpTexelSize
);
558 FREE((void *) srcAddr
);
562 transfer_teximage(ctx
, dimensions
, tmpFormat
, tmpImage
,
563 srcWidth
, srcHeight
, srcDepth
,
564 0, 0, 0, /* x/y/zoffset */
565 tmpRowStride
, tmpImageStride
,
566 srcFormat
, srcType
, srcAddr
, srcPacking
, transferOps
);
569 FREE((void *) srcAddr
);
571 /* the temp image is our new source image */
572 srcWidth
= postConvWidth
;
573 srcHeight
= postConvHeight
;
574 srcFormat
= tmpFormat
;
577 srcPacking
= &_mesa_native_packing
;
578 freeSourceData
= GL_TRUE
;
581 if (_mesa_is_hardware_tex_format(dstFormat
)) {
583 if (dimensions
== 1) {
585 b
= _mesa_convert_texsubimage1d(dstFormat
->MesaFormat
,
593 else if (dimensions
== 2) {
595 b
= _mesa_convert_texsubimage2d(dstFormat
->MesaFormat
,
596 dstXoffset
, dstYoffset
,
606 b
= _mesa_convert_texsubimage3d(dstFormat
->MesaFormat
,
607 dstXoffset
, dstYoffset
, dstZoffset
,
608 srcWidth
, srcHeight
, srcDepth
,
609 dstRowStridePixels
, dstImageStridePixels
,
611 srcPacking
, srcAddr
, dstAddr
);
616 /* software format */
618 transfer_teximage(ctx
, dimensions
, dstFormat
->BaseFormat
, dstAddr
,
619 srcWidth
, srcHeight
, srcDepth
,
620 dstXoffset
, dstYoffset
, dstZoffset
,
621 dstRowStride
, dstImageStride
,
622 srcFormat
, srcType
, srcAddr
, srcPacking
, transferOps
);
626 FREE((void *) srcAddr
); /* the temp image */
631 * This is the software fallback for Driver.TexImage1D().
632 * The texture image type will be GLchan.
633 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
634 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
638 _mesa_store_teximage1d(GLcontext
*ctx
, GLenum target
, GLint level
,
639 GLint internalFormat
,
640 GLint width
, GLint border
,
641 GLenum format
, GLenum type
, const GLvoid
*pixels
,
642 const struct gl_pixelstore_attrib
*packing
,
643 struct gl_texture_object
*texObj
,
644 struct gl_texture_image
*texImage
)
646 GLint postConvWidth
= width
;
647 GLint texelBytes
, sizeInBytes
;
649 if (ctx
->_ImageTransferState
& IMAGE_CONVOLUTION_BIT
) {
650 _mesa_adjust_image_for_convolution(ctx
, 1, &postConvWidth
, NULL
);
653 /* choose the texture format */
654 assert(ctx
->Driver
.ChooseTextureFormat
);
655 texImage
->TexFormat
= (*ctx
->Driver
.ChooseTextureFormat
)(ctx
,
656 internalFormat
, format
, type
);
657 assert(texImage
->TexFormat
);
658 texImage
->FetchTexel
= texImage
->TexFormat
->FetchTexel1D
;
660 texelBytes
= texImage
->TexFormat
->TexelBytes
;
662 /* Compute image size, in bytes */
663 if (texImage
->IsCompressed
) {
664 assert(ctx
->Driver
.CompressedTextureSize
);
665 sizeInBytes
= ctx
->Driver
.CompressedTextureSize(ctx
, texImage
);
666 assert(sizeInBytes
> 0);
667 texImage
->CompressedSize
= sizeInBytes
;
670 sizeInBytes
= postConvWidth
* texelBytes
;
673 /* allocate memory */
674 texImage
->Data
= MESA_PBUFFER_ALLOC(sizeInBytes
);
675 if (!texImage
->Data
) {
676 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTexImage1D");
681 /* unpack image, apply transfer ops and store in texImage->Data */
682 _mesa_transfer_teximage(ctx
, 1,
683 _mesa_base_tex_format(ctx
, internalFormat
),
684 texImage
->TexFormat
, texImage
->Data
,
685 width
, 1, 1, 0, 0, 0,
686 0, /* dstRowStride */
687 0, /* dstImageStride */
688 format
, type
, pixels
, packing
);
690 /* GL_SGIS_generate_mipmap */
691 if (level
== texObj
->BaseLevel
&& texObj
->GenerateMipmap
) {
692 _mesa_generate_mipmap(ctx
, target
,
693 &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
],
701 * This is the software fallback for Driver.TexImage2D().
702 * The texture image type will be GLchan.
703 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
704 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
706 * NOTE: if real texture compression is supported, this whole function
707 * will need to be overridden.
710 _mesa_store_teximage2d(GLcontext
*ctx
, GLenum target
, GLint level
,
711 GLint internalFormat
,
712 GLint width
, GLint height
, GLint border
,
713 GLenum format
, GLenum type
, const void *pixels
,
714 const struct gl_pixelstore_attrib
*packing
,
715 struct gl_texture_object
*texObj
,
716 struct gl_texture_image
*texImage
)
718 GLint postConvWidth
= width
, postConvHeight
= height
;
719 GLint texelBytes
, sizeInBytes
;
721 if (ctx
->_ImageTransferState
& IMAGE_CONVOLUTION_BIT
) {
722 _mesa_adjust_image_for_convolution(ctx
, 2, &postConvWidth
,
726 /* choose the texture format */
727 assert(ctx
->Driver
.ChooseTextureFormat
);
728 texImage
->TexFormat
= (*ctx
->Driver
.ChooseTextureFormat
)(ctx
,
729 internalFormat
, format
, type
);
730 assert(texImage
->TexFormat
);
731 texImage
->FetchTexel
= texImage
->TexFormat
->FetchTexel2D
;
733 texelBytes
= texImage
->TexFormat
->TexelBytes
;
735 /* Compute image size, in bytes */
736 if (texImage
->IsCompressed
) {
737 assert(ctx
->Driver
.CompressedTextureSize
);
738 sizeInBytes
= ctx
->Driver
.CompressedTextureSize(ctx
, texImage
);
739 assert(sizeInBytes
> 0);
740 texImage
->CompressedSize
= sizeInBytes
;
743 sizeInBytes
= postConvWidth
* postConvHeight
* texelBytes
;
746 /* allocate memory */
747 texImage
->Data
= MESA_PBUFFER_ALLOC(sizeInBytes
);
748 if (!texImage
->Data
) {
749 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTexImage2D");
754 /* unpack image, apply transfer ops and store in texImage->Data */
755 _mesa_transfer_teximage(ctx
, 2,
756 _mesa_base_tex_format(ctx
, internalFormat
),
757 texImage
->TexFormat
, texImage
->Data
,
758 width
, height
, 1, 0, 0, 0,
759 texImage
->Width
* texelBytes
,
760 0, /* dstImageStride */
761 format
, type
, pixels
, packing
);
763 /* GL_SGIS_generate_mipmap */
764 if (level
== texObj
->BaseLevel
&& texObj
->GenerateMipmap
) {
765 _mesa_generate_mipmap(ctx
, target
,
766 &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
],
775 * This is the software fallback for Driver.TexImage3D().
776 * The texture image type will be GLchan.
777 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
778 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
782 _mesa_store_teximage3d(GLcontext
*ctx
, GLenum target
, GLint level
,
783 GLint internalFormat
,
784 GLint width
, GLint height
, GLint depth
, GLint border
,
785 GLenum format
, GLenum type
, const void *pixels
,
786 const struct gl_pixelstore_attrib
*packing
,
787 struct gl_texture_object
*texObj
,
788 struct gl_texture_image
*texImage
)
790 GLint texelBytes
, sizeInBytes
;
792 /* choose the texture format */
793 assert(ctx
->Driver
.ChooseTextureFormat
);
794 texImage
->TexFormat
= (*ctx
->Driver
.ChooseTextureFormat
)(ctx
,
795 internalFormat
, format
, type
);
796 assert(texImage
->TexFormat
);
797 texImage
->FetchTexel
= texImage
->TexFormat
->FetchTexel3D
;
799 texelBytes
= texImage
->TexFormat
->TexelBytes
;
801 /* Compute image size, in bytes */
802 if (texImage
->IsCompressed
) {
803 assert(ctx
->Driver
.CompressedTextureSize
);
804 sizeInBytes
= ctx
->Driver
.CompressedTextureSize(ctx
, texImage
);
805 assert(sizeInBytes
> 0);
806 texImage
->CompressedSize
= sizeInBytes
;
809 sizeInBytes
= width
* height
* depth
* texelBytes
;
812 /* allocate memory */
813 texImage
->Data
= MESA_PBUFFER_ALLOC(sizeInBytes
);
814 if (!texImage
->Data
) {
815 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glTexImage3D");
820 /* unpack image, apply transfer ops and store in texImage->Data */
821 _mesa_transfer_teximage(ctx
, 3,
822 _mesa_base_tex_format(ctx
, internalFormat
),
823 texImage
->TexFormat
, texImage
->Data
,
824 width
, height
, depth
, 0, 0, 0,
825 texImage
->Width
* texelBytes
,
826 texImage
->Width
* texImage
->Height
* texelBytes
,
827 format
, type
, pixels
, packing
);
829 /* GL_SGIS_generate_mipmap */
830 if (level
== texObj
->BaseLevel
&& texObj
->GenerateMipmap
) {
831 _mesa_generate_mipmap(ctx
, target
,
832 &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
],
842 * This is the software fallback for Driver.TexSubImage1D().
845 _mesa_store_texsubimage1d(GLcontext
*ctx
, GLenum target
, GLint level
,
846 GLint xoffset
, GLint width
,
847 GLenum format
, GLenum type
, const void *pixels
,
848 const struct gl_pixelstore_attrib
*packing
,
849 struct gl_texture_object
*texObj
,
850 struct gl_texture_image
*texImage
)
852 _mesa_transfer_teximage(ctx
, 1,
853 _mesa_base_tex_format(ctx
, texImage
->IntFormat
),
854 texImage
->TexFormat
, texImage
->Data
,
855 width
, 1, 1, /* src size */
856 xoffset
, 0, 0, /* dest offsets */
857 0, /* dstRowStride */
858 0, /* dstImageStride */
859 format
, type
, pixels
, packing
);
861 /* GL_SGIS_generate_mipmap */
862 if (level
== texObj
->BaseLevel
&& texObj
->GenerateMipmap
) {
863 _mesa_generate_mipmap(ctx
, target
,
864 &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
],
871 * This is the software fallback for Driver.TexSubImage2D().
874 _mesa_store_texsubimage2d(GLcontext
*ctx
, GLenum target
, GLint level
,
875 GLint xoffset
, GLint yoffset
,
876 GLint width
, GLint height
,
877 GLenum format
, GLenum type
, const void *pixels
,
878 const struct gl_pixelstore_attrib
*packing
,
879 struct gl_texture_object
*texObj
,
880 struct gl_texture_image
*texImage
)
882 _mesa_transfer_teximage(ctx
, 2,
883 _mesa_base_tex_format(ctx
, texImage
->IntFormat
),
884 texImage
->TexFormat
, texImage
->Data
,
885 width
, height
, 1, /* src size */
886 xoffset
, yoffset
, 0, /* dest offsets */
887 texImage
->Width
* texImage
->TexFormat
->TexelBytes
,
888 0, /* dstImageStride */
889 format
, type
, pixels
, packing
);
891 /* GL_SGIS_generate_mipmap */
892 if (level
== texObj
->BaseLevel
&& texObj
->GenerateMipmap
) {
893 _mesa_generate_mipmap(ctx
, target
,
894 &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
],
901 * This is the software fallback for Driver.TexSubImage3D().
904 _mesa_store_texsubimage3d(GLcontext
*ctx
, GLenum target
, GLint level
,
905 GLint xoffset
, GLint yoffset
, GLint zoffset
,
906 GLint width
, GLint height
, GLint depth
,
907 GLenum format
, GLenum type
, const void *pixels
,
908 const struct gl_pixelstore_attrib
*packing
,
909 struct gl_texture_object
*texObj
,
910 struct gl_texture_image
*texImage
)
912 const GLint texelBytes
= texImage
->TexFormat
->TexelBytes
;
913 _mesa_transfer_teximage(ctx
, 3,
914 _mesa_base_tex_format(ctx
, texImage
->IntFormat
),
915 texImage
->TexFormat
, texImage
->Data
,
916 width
, height
, depth
, /* src size */
917 xoffset
, yoffset
, xoffset
, /* dest offsets */
918 texImage
->Width
* texelBytes
,
919 texImage
->Width
* texImage
->Height
* texelBytes
,
920 format
, type
, pixels
, packing
);
921 /* GL_SGIS_generate_mipmap */
922 if (level
== texObj
->BaseLevel
&& texObj
->GenerateMipmap
) {
923 _mesa_generate_mipmap(ctx
, target
,
924 &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
],
933 * Fallback for Driver.CompressedTexImage1D()
936 _mesa_store_compressed_teximage1d(GLcontext
*ctx
, GLenum target
, GLint level
,
937 GLint internalFormat
,
938 GLint width
, GLint border
,
939 GLsizei imageSize
, const GLvoid
*data
,
940 struct gl_texture_object
*texObj
,
941 struct gl_texture_image
*texImage
)
944 * The device driver has to do it all.
951 * Fallback for Driver.CompressedTexImage2D()
954 _mesa_store_compressed_teximage2d(GLcontext
*ctx
, GLenum target
, GLint level
,
955 GLint internalFormat
,
956 GLint width
, GLint height
, GLint border
,
957 GLsizei imageSize
, const GLvoid
*data
,
958 struct gl_texture_object
*texObj
,
959 struct gl_texture_image
*texImage
)
962 * The device driver has to do it all.
969 * Fallback for Driver.CompressedTexImage3D()
972 _mesa_store_compressed_teximage3d(GLcontext
*ctx
, GLenum target
, GLint level
,
973 GLint internalFormat
,
974 GLint width
, GLint height
, GLint depth
,
976 GLsizei imageSize
, const GLvoid
*data
,
977 struct gl_texture_object
*texObj
,
978 struct gl_texture_image
*texImage
)
981 * The device driver has to do it all.
988 * Fallback for Driver.GetCompressedTexImage3D()
989 * This will probably work find for hardware drivers. That is, hardware
990 * drivers won't have to override this function, unless the compressed
991 * texture must first be fetched from the TRAM.
994 _mesa_get_compressed_teximage(GLcontext
*ctx
, GLenum target
,
995 GLint level
, void *image
,
996 const struct gl_texture_object
*texObj
,
997 struct gl_texture_image
*texImage
)
999 assert(texImage
->IsCompressed
);
1000 assert(texImage
->CompressedSize
> 0);
1001 MEMCPY(image
, texImage
->Data
, texImage
->CompressedSize
);
1007 * This is the fallback for Driver.TestProxyTexImage().
1010 _mesa_test_proxy_teximage(GLcontext
*ctx
, GLenum target
, GLint level
,
1011 GLint internalFormat
, GLenum format
, GLenum type
,
1012 GLint width
, GLint height
, GLint depth
, GLint border
)
1014 struct gl_texture_unit
*texUnit
;
1015 struct gl_texture_object
*texObj
;
1016 struct gl_texture_image
*texImage
;
1021 texUnit
= &ctx
->Texture
.Unit
[ctx
->Texture
.CurrentUnit
];
1022 texObj
= _mesa_select_tex_object(ctx
, texUnit
, target
);
1023 texImage
= _mesa_select_tex_image(ctx
, texUnit
, target
, level
);
1026 * The core Mesa code will have already tested the image size, etc.
1027 * If a driver has more stringent texture limits to enforce it will
1028 * have to override this function.
1030 /* choose the texture format */
1031 assert(ctx
->Driver
.ChooseTextureFormat
);
1032 texImage
->TexFormat
= (*ctx
->Driver
.ChooseTextureFormat
)(ctx
,
1033 internalFormat
, format
, type
);
1034 assert(texImage
->TexFormat
);
1042 * Average together two rows of a source image to produce a single new
1043 * row in the dest image. It's legal for the two source rows to point
1044 * to the same data. The source width must be equal to either the
1045 * dest width or two times the dest width.
1048 do_row(const struct gl_texture_format
*format
, GLint srcWidth
,
1049 const GLvoid
*srcRowA
, const GLvoid
*srcRowB
,
1050 GLint dstWidth
, GLvoid
*dstRow
)
1052 const GLuint k0
= (srcWidth
== dstWidth
) ? 0 : 1;
1053 const GLuint colStride
= (srcWidth
== dstWidth
) ? 1 : 2;
1055 assert(srcWidth
== dstWidth
|| srcWidth
== 2 * dstWidth
);
1057 switch (format
->MesaFormat
) {
1058 case MESA_FORMAT_RGBA
:
1061 const GLchan (*rowA
)[4] = (const GLchan (*)[4]) srcRowA
;
1062 const GLchan (*rowB
)[4] = (const GLchan (*)[4]) srcRowB
;
1063 GLchan (*dst
)[4] = (GLchan (*)[4]) dstRow
;
1064 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1065 i
++, j
+= colStride
, k
+= colStride
) {
1066 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
1067 rowB
[j
][0] + rowB
[k
][0]) / 4;
1068 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
1069 rowB
[j
][1] + rowB
[k
][1]) / 4;
1070 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
1071 rowB
[j
][2] + rowB
[k
][2]) / 4;
1072 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
1073 rowB
[j
][3] + rowB
[k
][3]) / 4;
1077 case MESA_FORMAT_RGB
:
1080 const GLchan (*rowA
)[3] = (const GLchan (*)[3]) srcRowA
;
1081 const GLchan (*rowB
)[3] = (const GLchan (*)[3]) srcRowB
;
1082 GLchan (*dst
)[3] = (GLchan (*)[3]) dstRow
;
1083 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1084 i
++, j
+= colStride
, k
+= colStride
) {
1085 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
1086 rowB
[j
][0] + rowB
[k
][0]) / 4;
1087 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
1088 rowB
[j
][1] + rowB
[k
][1]) / 4;
1089 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
1090 rowB
[j
][2] + rowB
[k
][2]) / 4;
1094 case MESA_FORMAT_ALPHA
:
1095 case MESA_FORMAT_LUMINANCE
:
1096 case MESA_FORMAT_INTENSITY
:
1097 case MESA_FORMAT_COLOR_INDEX
:
1100 const GLchan
*rowA
= (const GLchan
*) srcRowA
;
1101 const GLchan
*rowB
= (const GLchan
*) srcRowB
;
1102 GLchan
*dst
= (GLchan
*) dstRow
;
1103 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1104 i
++, j
+= colStride
, k
+= colStride
) {
1105 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) / 4;
1109 case MESA_FORMAT_LUMINANCE_ALPHA
:
1112 const GLchan (*rowA
)[2] = (const GLchan (*)[2]) srcRowA
;
1113 const GLchan (*rowB
)[2] = (const GLchan (*)[2]) srcRowB
;
1114 GLchan (*dst
)[2] = (GLchan (*)[2]) dstRow
;
1115 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1116 i
++, j
+= colStride
, k
+= colStride
) {
1117 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
1118 rowB
[j
][0] + rowB
[k
][0]) / 4;
1119 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
1120 rowB
[j
][1] + rowB
[k
][1]) / 4;
1124 case MESA_FORMAT_DEPTH_COMPONENT
:
1127 const GLfloat
*rowA
= (const GLfloat
*) srcRowA
;
1128 const GLfloat
*rowB
= (const GLfloat
*) srcRowB
;
1129 GLfloat
*dst
= (GLfloat
*) dstRow
;
1130 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1131 i
++, j
+= colStride
, k
+= colStride
) {
1132 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) * 0.25F
;
1136 /* Begin hardware formats */
1137 case MESA_FORMAT_RGBA8888
:
1138 case MESA_FORMAT_ARGB8888
:
1141 const GLubyte (*rowA
)[4] = (const GLubyte (*)[4]) srcRowA
;
1142 const GLubyte (*rowB
)[4] = (const GLubyte (*)[4]) srcRowB
;
1143 GLubyte (*dst
)[4] = (GLubyte (*)[4]) dstRow
;
1144 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1145 i
++, j
+= colStride
, k
+= colStride
) {
1146 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
1147 rowB
[j
][0] + rowB
[k
][0]) / 4;
1148 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
1149 rowB
[j
][1] + rowB
[k
][1]) / 4;
1150 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
1151 rowB
[j
][2] + rowB
[k
][2]) / 4;
1152 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
1153 rowB
[j
][3] + rowB
[k
][3]) / 4;
1157 case MESA_FORMAT_RGB888
:
1160 const GLubyte (*rowA
)[3] = (const GLubyte (*)[3]) srcRowA
;
1161 const GLubyte (*rowB
)[3] = (const GLubyte (*)[3]) srcRowB
;
1162 GLubyte (*dst
)[3] = (GLubyte (*)[3]) dstRow
;
1163 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1164 i
++, j
+= colStride
, k
+= colStride
) {
1165 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
1166 rowB
[j
][0] + rowB
[k
][0]) / 4;
1167 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
1168 rowB
[j
][1] + rowB
[k
][1]) / 4;
1169 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
1170 rowB
[j
][2] + rowB
[k
][2]) / 4;
1174 case MESA_FORMAT_RGB565
:
1177 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
1178 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
1179 GLushort
*dst
= (GLushort
*) dstRow
;
1180 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1181 i
++, j
+= colStride
, k
+= colStride
) {
1182 const GLint rowAr0
= rowA
[j
] & 0x1f;
1183 const GLint rowAr1
= rowA
[k
] & 0x1f;
1184 const GLint rowBr0
= rowB
[j
] & 0x1f;
1185 const GLint rowBr1
= rowB
[k
] & 0x1f;
1186 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x3f;
1187 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x3f;
1188 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x3f;
1189 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x3f;
1190 const GLint rowAb0
= (rowA
[j
] >> 11) & 0x1f;
1191 const GLint rowAb1
= (rowA
[k
] >> 11) & 0x1f;
1192 const GLint rowBb0
= (rowB
[j
] >> 11) & 0x1f;
1193 const GLint rowBb1
= (rowB
[k
] >> 11) & 0x1f;
1194 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 4;
1195 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 4;
1196 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 4;
1197 dst
[i
] = (blue
<< 11) | (green
<< 5) | red
;
1201 case MESA_FORMAT_ARGB4444
:
1204 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
1205 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
1206 GLushort
*dst
= (GLushort
*) dstRow
;
1207 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1208 i
++, j
+= colStride
, k
+= colStride
) {
1209 const GLint rowAr0
= rowA
[j
] & 0xf;
1210 const GLint rowAr1
= rowA
[k
] & 0xf;
1211 const GLint rowBr0
= rowB
[j
] & 0xf;
1212 const GLint rowBr1
= rowB
[k
] & 0xf;
1213 const GLint rowAg0
= (rowA
[j
] >> 4) & 0xf;
1214 const GLint rowAg1
= (rowA
[k
] >> 4) & 0xf;
1215 const GLint rowBg0
= (rowB
[j
] >> 4) & 0xf;
1216 const GLint rowBg1
= (rowB
[k
] >> 4) & 0xf;
1217 const GLint rowAb0
= (rowA
[j
] >> 8) & 0xf;
1218 const GLint rowAb1
= (rowA
[k
] >> 8) & 0xf;
1219 const GLint rowBb0
= (rowB
[j
] >> 8) & 0xf;
1220 const GLint rowBb1
= (rowB
[k
] >> 8) & 0xf;
1221 const GLint rowAa0
= (rowA
[j
] >> 12) & 0xf;
1222 const GLint rowAa1
= (rowA
[k
] >> 12) & 0xf;
1223 const GLint rowBa0
= (rowB
[j
] >> 12) & 0xf;
1224 const GLint rowBa1
= (rowB
[k
] >> 12) & 0xf;
1225 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 4;
1226 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 4;
1227 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 4;
1228 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 4;
1229 dst
[i
] = (alpha
<< 12) | (blue
<< 8) | (green
<< 4) | red
;
1233 case MESA_FORMAT_ARGB1555
:
1236 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
1237 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
1238 GLushort
*dst
= (GLushort
*) dstRow
;
1239 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1240 i
++, j
+= colStride
, k
+= colStride
) {
1241 const GLint rowAr0
= rowA
[j
] & 0x1f;
1242 const GLint rowAr1
= rowA
[k
] & 0x1f;
1243 const GLint rowBr0
= rowB
[j
] & 0x1f;
1244 const GLint rowBr1
= rowB
[k
] & 0xf;
1245 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x1f;
1246 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x1f;
1247 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x1f;
1248 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x1f;
1249 const GLint rowAb0
= (rowA
[j
] >> 10) & 0x1f;
1250 const GLint rowAb1
= (rowA
[k
] >> 10) & 0x1f;
1251 const GLint rowBb0
= (rowB
[j
] >> 10) & 0x1f;
1252 const GLint rowBb1
= (rowB
[k
] >> 10) & 0x1f;
1253 const GLint rowAa0
= (rowA
[j
] >> 15) & 0x1;
1254 const GLint rowAa1
= (rowA
[k
] >> 15) & 0x1;
1255 const GLint rowBa0
= (rowB
[j
] >> 15) & 0x1;
1256 const GLint rowBa1
= (rowB
[k
] >> 15) & 0x1;
1257 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 4;
1258 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 4;
1259 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 4;
1260 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 4;
1261 dst
[i
] = (alpha
<< 15) | (blue
<< 10) | (green
<< 5) | red
;
1265 case MESA_FORMAT_AL88
:
1268 const GLubyte (*rowA
)[2] = (const GLubyte (*)[2]) srcRowA
;
1269 const GLubyte (*rowB
)[2] = (const GLubyte (*)[2]) srcRowB
;
1270 GLubyte (*dst
)[2] = (GLubyte (*)[2]) dstRow
;
1271 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1272 i
++, j
+= colStride
, k
+= colStride
) {
1273 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
1274 rowB
[j
][0] + rowB
[k
][0]) >> 2;
1275 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
1276 rowB
[j
][1] + rowB
[k
][1]) >> 2;
1280 case MESA_FORMAT_RGB332
:
1283 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
1284 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
1285 GLubyte
*dst
= (GLubyte
*) dstRow
;
1286 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1287 i
++, j
+= colStride
, k
+= colStride
) {
1288 const GLint rowAr0
= rowA
[j
] & 0x3;
1289 const GLint rowAr1
= rowA
[k
] & 0x3;
1290 const GLint rowBr0
= rowB
[j
] & 0x3;
1291 const GLint rowBr1
= rowB
[k
] & 0x3;
1292 const GLint rowAg0
= (rowA
[j
] >> 2) & 0x7;
1293 const GLint rowAg1
= (rowA
[k
] >> 2) & 0x7;
1294 const GLint rowBg0
= (rowB
[j
] >> 2) & 0x7;
1295 const GLint rowBg1
= (rowB
[k
] >> 2) & 0x7;
1296 const GLint rowAb0
= (rowA
[j
] >> 5) & 0x7;
1297 const GLint rowAb1
= (rowA
[k
] >> 5) & 0x7;
1298 const GLint rowBb0
= (rowB
[j
] >> 5) & 0x7;
1299 const GLint rowBb1
= (rowB
[k
] >> 5) & 0x7;
1300 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 4;
1301 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 4;
1302 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 4;
1303 dst
[i
] = (blue
<< 5) | (green
<< 2) | red
;
1307 case MESA_FORMAT_A8
:
1308 case MESA_FORMAT_L8
:
1309 case MESA_FORMAT_I8
:
1310 case MESA_FORMAT_CI8
:
1313 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
1314 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
1315 GLubyte
*dst
= (GLubyte
*) dstRow
;
1316 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
1317 i
++, j
+= colStride
, k
+= colStride
) {
1318 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) >> 2;
1323 _mesa_problem(NULL
, "bad format in do_row()");
1329 * These functions generate a 1/2-size mipmap image from a source image.
1330 * Texture borders are handled by copying or averaging the source image's
1331 * border texels, depending on the scale-down factor.
1335 make_1d_mipmap(const struct gl_texture_format
*format
, GLint border
,
1336 GLint srcWidth
, const GLubyte
*srcPtr
,
1337 GLint dstWidth
, GLubyte
*dstPtr
)
1339 const GLint bpt
= format
->TexelBytes
;
1343 /* skip the border pixel, if any */
1344 src
= srcPtr
+ border
* bpt
;
1345 dst
= dstPtr
+ border
* bpt
;
1347 /* we just duplicate the input row, kind of hack, saves code */
1348 do_row(format
, srcWidth
- 2 * border
, src
, src
,
1349 dstWidth
- 2 * border
, dst
);
1352 /* copy left-most pixel from source */
1353 MEMCPY(dstPtr
, srcPtr
, bpt
);
1354 /* copy right-most pixel from source */
1355 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
1356 srcPtr
+ (srcWidth
- 1) * bpt
,
1363 make_2d_mipmap(const struct gl_texture_format
*format
, GLint border
,
1364 GLint srcWidth
, GLint srcHeight
, const GLubyte
*srcPtr
,
1365 GLint dstWidth
, GLint dstHeight
, GLubyte
*dstPtr
)
1367 const GLint bpt
= format
->TexelBytes
;
1368 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
1369 const GLint dstWidthNB
= dstWidth
- 2 * border
;
1370 const GLint dstHeightNB
= dstHeight
- 2 * border
;
1371 const GLint srcRowStride
= bpt
* srcWidth
;
1372 const GLint dstRowStride
= bpt
* dstWidth
;
1373 const GLubyte
*srcA
, *srcB
;
1375 GLint row
, colStride
;
1377 colStride
= (srcWidth
== dstWidth
) ? 1 : 2;
1379 /* Compute src and dst pointers, skipping any border */
1380 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
1382 srcB
= srcA
+ srcRowStride
;
1385 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
1387 for (row
= 0; row
< dstHeightNB
; row
++) {
1388 do_row(format
, srcWidthNB
, srcA
, srcB
,
1390 srcA
+= 2 * srcRowStride
;
1391 srcB
+= 2 * srcRowStride
;
1392 dst
+= dstRowStride
;
1395 /* This is ugly but probably won't be used much */
1397 /* fill in dest border */
1398 /* lower-left border pixel */
1399 MEMCPY(dstPtr
, srcPtr
, bpt
);
1400 /* lower-right border pixel */
1401 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
1402 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
1403 /* upper-left border pixel */
1404 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
1405 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
1406 /* upper-right border pixel */
1407 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
1408 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
1410 do_row(format
, srcWidthNB
,
1413 dstWidthNB
, dstPtr
+ bpt
);
1415 do_row(format
, srcWidthNB
,
1416 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
1417 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
1419 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
1420 /* left and right borders */
1421 if (srcHeight
== dstHeight
) {
1422 /* copy border pixel from src to dst */
1423 for (row
= 1; row
< srcHeight
; row
++) {
1424 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
1425 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
1426 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
1427 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
1431 /* average two src pixels each dest pixel */
1432 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
1434 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
1435 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
1436 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
1438 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
1439 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
1440 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
1448 make_3d_mipmap(const struct gl_texture_format
*format
, GLint border
,
1449 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
1450 const GLubyte
*srcPtr
,
1451 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
1454 const GLint bpt
= format
->TexelBytes
;
1455 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
1456 const GLint srcDepthNB
= srcDepth
- 2 * border
;
1457 const GLint dstWidthNB
= dstWidth
- 2 * border
;
1458 const GLint dstHeightNB
= dstHeight
- 2 * border
;
1459 const GLint dstDepthNB
= dstDepth
- 2 * border
;
1460 GLvoid
*tmpRowA
, *tmpRowB
;
1462 GLint bytesPerSrcImage
, bytesPerDstImage
;
1463 GLint bytesPerSrcRow
, bytesPerDstRow
;
1464 GLint srcImageOffset
, srcRowOffset
;
1466 (void) srcDepthNB
; /* silence warnings */
1468 /* Need two temporary row buffers */
1469 tmpRowA
= MALLOC(srcWidth
* bpt
);
1472 tmpRowB
= MALLOC(srcWidth
* bpt
);
1478 bytesPerSrcImage
= srcWidth
* srcHeight
* bpt
;
1479 bytesPerDstImage
= dstWidth
* dstHeight
* bpt
;
1481 bytesPerSrcRow
= srcWidth
* bpt
;
1482 bytesPerDstRow
= dstWidth
* bpt
;
1484 /* Offset between adjacent src images to be averaged together */
1485 srcImageOffset
= (srcDepth
== dstDepth
) ? 0 : bytesPerSrcImage
;
1487 /* Offset between adjacent src rows to be averaged together */
1488 srcRowOffset
= (srcHeight
== dstHeight
) ? 0 : srcWidth
* bpt
;
1491 * Need to average together up to 8 src pixels for each dest pixel.
1492 * Break that down into 3 operations:
1493 * 1. take two rows from source image and average them together.
1494 * 2. take two rows from next source image and average them together.
1495 * 3. take the two averaged rows and average them for the final dst row.
1499 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
1500 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
1503 for (img
= 0; img
< dstDepthNB
; img
++) {
1504 /* first source image pointer, skipping border */
1505 const GLubyte
*imgSrcA
= srcPtr
1506 + (bytesPerSrcImage
+ bytesPerSrcRow
+ border
) * bpt
* border
1507 + img
* (bytesPerSrcImage
+ srcImageOffset
);
1508 /* second source image pointer, skipping border */
1509 const GLubyte
*imgSrcB
= imgSrcA
+ srcImageOffset
;
1510 /* address of the dest image, skipping border */
1511 GLubyte
*imgDst
= dstPtr
1512 + (bytesPerDstImage
+ bytesPerDstRow
+ border
) * bpt
* border
1513 + img
* bytesPerDstImage
;
1515 /* setup the four source row pointers and the dest row pointer */
1516 const GLubyte
*srcImgARowA
= imgSrcA
;
1517 const GLubyte
*srcImgARowB
= imgSrcA
+ srcRowOffset
;
1518 const GLubyte
*srcImgBRowA
= imgSrcB
;
1519 const GLubyte
*srcImgBRowB
= imgSrcB
+ srcRowOffset
;
1520 GLubyte
*dstImgRow
= imgDst
;
1522 for (row
= 0; row
< dstHeightNB
; row
++) {
1523 /* Average together two rows from first src image */
1524 do_row(format
, srcWidthNB
, srcImgARowA
, srcImgARowB
,
1525 srcWidthNB
, tmpRowA
);
1526 /* Average together two rows from second src image */
1527 do_row(format
, srcWidthNB
, srcImgBRowA
, srcImgBRowB
,
1528 srcWidthNB
, tmpRowB
);
1529 /* Average together the temp rows to make the final row */
1530 do_row(format
, srcWidthNB
, tmpRowA
, tmpRowB
,
1531 dstWidthNB
, dstImgRow
);
1532 /* advance to next rows */
1533 srcImgARowA
+= bytesPerSrcRow
+ srcRowOffset
;
1534 srcImgARowB
+= bytesPerSrcRow
+ srcRowOffset
;
1535 srcImgBRowA
+= bytesPerSrcRow
+ srcRowOffset
;
1536 srcImgBRowB
+= bytesPerSrcRow
+ srcRowOffset
;
1537 dstImgRow
+= bytesPerDstRow
;
1544 /* Luckily we can leverage the make_2d_mipmap() function here! */
1546 /* do front border image */
1547 make_2d_mipmap(format
, 1, srcWidth
, srcHeight
, srcPtr
,
1548 dstWidth
, dstHeight
, dstPtr
);
1549 /* do back border image */
1550 make_2d_mipmap(format
, 1, srcWidth
, srcHeight
,
1551 srcPtr
+ bytesPerSrcImage
* (srcDepth
- 1),
1552 dstWidth
, dstHeight
,
1553 dstPtr
+ bytesPerDstImage
* (dstDepth
- 1));
1554 /* do four remaining border edges that span the image slices */
1555 if (srcDepth
== dstDepth
) {
1556 /* just copy border pixels from src to dst */
1557 for (img
= 0; img
< dstDepthNB
; img
++) {
1561 /* do border along [img][row=0][col=0] */
1562 src
= srcPtr
+ (img
+ 1) * bytesPerSrcImage
;
1563 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
1564 MEMCPY(dst
, src
, bpt
);
1566 /* do border along [img][row=dstHeight-1][col=0] */
1567 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
1568 + (srcHeight
- 1) * bytesPerSrcRow
;
1569 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
1570 + (dstHeight
- 1) * bytesPerDstRow
;
1571 MEMCPY(dst
, src
, bpt
);
1573 /* do border along [img][row=0][col=dstWidth-1] */
1574 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
1575 + (srcWidth
- 1) * bpt
;
1576 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
1577 + (dstWidth
- 1) * bpt
;
1578 MEMCPY(dst
, src
, bpt
);
1580 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1581 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
1582 + (bytesPerSrcImage
- bpt
);
1583 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
1584 + (bytesPerDstImage
- bpt
);
1585 MEMCPY(dst
, src
, bpt
);
1589 /* average border pixels from adjacent src image pairs */
1590 ASSERT(srcDepthNB
== 2 * dstDepthNB
);
1591 for (img
= 0; img
< dstDepthNB
; img
++) {
1595 /* do border along [img][row=0][col=0] */
1596 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
;
1597 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
1598 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
1600 /* do border along [img][row=dstHeight-1][col=0] */
1601 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
1602 + (srcHeight
- 1) * bytesPerSrcRow
;
1603 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
1604 + (dstHeight
- 1) * bytesPerDstRow
;
1605 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
1607 /* do border along [img][row=0][col=dstWidth-1] */
1608 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
1609 + (srcWidth
- 1) * bpt
;
1610 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
1611 + (dstWidth
- 1) * bpt
;
1612 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
1614 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1615 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
1616 + (bytesPerSrcImage
- bpt
);
1617 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
1618 + (bytesPerDstImage
- bpt
);
1619 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
1627 * For GL_SGIX_generate_mipmap:
1628 * Generate a complete set of mipmaps from texObj's base-level image.
1629 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
1632 _mesa_generate_mipmap(GLcontext
*ctx
, GLenum target
,
1633 const struct gl_texture_unit
*texUnit
,
1634 struct gl_texture_object
*texObj
)
1637 GLint maxLevels
= 0;
1640 ASSERT(texObj
->Image
[texObj
->BaseLevel
]);
1642 switch (texObj
->Target
) {
1644 maxLevels
= ctx
->Const
.MaxTextureLevels
;
1647 maxLevels
= ctx
->Const
.MaxTextureLevels
;
1650 maxLevels
= ctx
->Const
.Max3DTextureLevels
;
1652 case GL_TEXTURE_CUBE_MAP_ARB
:
1653 maxLevels
= ctx
->Const
.MaxCubeTextureLevels
;
1655 case GL_TEXTURE_RECTANGLE_NV
:
1660 "Bad texture object dimension in _mesa_generate_mipmaps");
1664 for (level
= texObj
->BaseLevel
; level
< texObj
->MaxLevel
1665 && level
< maxLevels
- 1; level
++) {
1666 /* generate image[level+1] from image[level] */
1667 const struct gl_texture_image
*srcImage
;
1668 struct gl_texture_image
*dstImage
;
1669 GLint srcWidth
, srcHeight
, srcDepth
;
1670 GLint dstWidth
, dstHeight
, dstDepth
;
1671 GLint border
, bytesPerTexel
;
1673 srcImage
= texObj
->Image
[level
];
1675 srcWidth
= srcImage
->Width
;
1676 srcHeight
= srcImage
->Height
;
1677 srcDepth
= srcImage
->Depth
;
1678 border
= srcImage
->Border
;
1679 bytesPerTexel
= srcImage
->TexFormat
->TexelBytes
;
1681 /* compute next (level+1) image size */
1682 if (srcWidth
- 2 * border
> 1) {
1683 dstWidth
= (srcWidth
- 2 * border
) / 2 + 2 * border
;
1686 dstWidth
= srcWidth
; /* can't go smaller */
1688 if (srcHeight
- 2 * border
> 1) {
1689 dstHeight
= (srcHeight
- 2 * border
) / 2 + 2 * border
;
1692 dstHeight
= srcHeight
; /* can't go smaller */
1694 if (srcDepth
- 2 * border
> 1) {
1695 dstDepth
= (srcDepth
- 2 * border
) / 2 + 2 * border
;
1698 dstDepth
= srcDepth
; /* can't go smaller */
1701 if (dstWidth
== srcWidth
&&
1702 dstHeight
== srcHeight
&&
1703 dstDepth
== srcDepth
) {
1708 /* get dest gl_texture_image */
1709 dstImage
= _mesa_select_tex_image(ctx
, texUnit
, target
, level
+1);
1711 dstImage
= _mesa_alloc_texture_image();
1713 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1716 _mesa_set_tex_image(texObj
, target
, level
+ 1, dstImage
);
1719 /* Free old image data */
1721 MESA_PBUFFER_FREE(dstImage
->Data
);
1723 /* initialize new image */
1724 _mesa_init_teximage_fields(ctx
, target
, dstImage
, dstWidth
, dstHeight
,
1725 dstDepth
, border
, srcImage
->Format
);
1726 dstImage
->DriverData
= NULL
;
1727 dstImage
->TexFormat
= srcImage
->TexFormat
;
1728 dstImage
->FetchTexel
= srcImage
->FetchTexel
;
1729 ASSERT(dstImage
->TexFormat
);
1730 ASSERT(dstImage
->FetchTexel
);
1732 ASSERT(dstWidth
* dstHeight
* dstDepth
* bytesPerTexel
> 0);
1734 /* alloc new image buffer */
1735 dstImage
->Data
= MESA_PBUFFER_ALLOC(dstWidth
* dstHeight
* dstDepth
1737 if (!dstImage
->Data
) {
1738 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1743 * We use simple 2x2 averaging to compute the next mipmap level.
1747 make_1d_mipmap(srcImage
->TexFormat
, border
,
1748 srcWidth
, (const GLubyte
*) srcImage
->Data
,
1749 dstWidth
, (GLubyte
*) dstImage
->Data
);
1752 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
:
1753 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
:
1754 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
:
1755 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
:
1756 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
:
1757 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
:
1758 make_2d_mipmap(srcImage
->TexFormat
, border
,
1759 srcWidth
, srcHeight
, (const GLubyte
*) srcImage
->Data
,
1760 dstWidth
, dstHeight
, (GLubyte
*) dstImage
->Data
);
1763 make_3d_mipmap(srcImage
->TexFormat
, border
,
1764 srcWidth
, srcHeight
, srcDepth
,
1765 (const GLubyte
*) srcImage
->Data
,
1766 dstWidth
, dstHeight
, dstDepth
,
1767 (GLubyte
*) dstImage
->Data
);
1769 case GL_TEXTURE_RECTANGLE_NV
:
1770 /* no mipmaps, do nothing */
1773 _mesa_problem(ctx
, "bad dimensions in _mesa_generate_mipmaps");
1776 } /* loop over mipmap levels */