7d37bcb00fd8c0f1aad576430ada4637f4f23ff9
[mesa.git] / src / mesa / main / texstore.c
1 /* $Id: texstore.c,v 1.37 2002/06/15 03:03:09 brianp 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 #include "colormac.h"
33 #include "context.h"
34 #include "convolve.h"
35 #include "image.h"
36 #include "macros.h"
37 #include "mem.h"
38 #include "texformat.h"
39 #include "teximage.h"
40 #include "texstore.h"
41 #include "texutil.h"
42
43
44 /*
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.
49 *
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?
52 */
53 static GLint
54 components_in_intformat( GLint format )
55 {
56 switch (format) {
57 case GL_ALPHA:
58 case GL_ALPHA4:
59 case GL_ALPHA8:
60 case GL_ALPHA12:
61 case GL_ALPHA16:
62 return 1;
63 case 1:
64 case GL_LUMINANCE:
65 case GL_LUMINANCE4:
66 case GL_LUMINANCE8:
67 case GL_LUMINANCE12:
68 case GL_LUMINANCE16:
69 return 1;
70 case 2:
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:
78 return 2;
79 case GL_INTENSITY:
80 case GL_INTENSITY4:
81 case GL_INTENSITY8:
82 case GL_INTENSITY12:
83 case GL_INTENSITY16:
84 return 1;
85 case 3:
86 case GL_RGB:
87 case GL_R3_G3_B2:
88 case GL_RGB4:
89 case GL_RGB5:
90 case GL_RGB8:
91 case GL_RGB10:
92 case GL_RGB12:
93 case GL_RGB16:
94 return 3;
95 case 4:
96 case GL_RGBA:
97 case GL_RGBA2:
98 case GL_RGBA4:
99 case GL_RGB5_A1:
100 case GL_RGBA8:
101 case GL_RGB10_A2:
102 case GL_RGBA12:
103 case GL_RGBA16:
104 return 4;
105 case GL_COLOR_INDEX:
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:
112 return 1;
113 case GL_DEPTH_COMPONENT:
114 case GL_DEPTH_COMPONENT16_SGIX:
115 case GL_DEPTH_COMPONENT24_SGIX:
116 case GL_DEPTH_COMPONENT32_SGIX:
117 return 1;
118 default:
119 return -1; /* error */
120 }
121 }
122
123
124 /*
125 * This function is used to transfer the user's image data into a texture
126 * image buffer. We handle both full texture images and subtexture images.
127 * We also take care of all image transfer operations here, including
128 * convolution, scale/bias, colortables, etc.
129 *
130 * The destination texel channel type is always GLchan.
131 *
132 * A hardware driver may use this as a helper routine to unpack and
133 * apply pixel transfer ops into a temporary image buffer. Then,
134 * convert the temporary image into the special hardware format.
135 *
136 * Input:
137 * dimensions - 1, 2, or 3
138 * texFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA,
139 * GL_RGB or GL_RGBA
140 * texDestAddr - destination image address
141 * srcWidth, srcHeight, srcDepth - size (in pixels) of src and dest images
142 * dstXoffset, dstYoffset, dstZoffset - position to store the image within
143 * the destination 3D texture
144 * dstRowStride, dstImageStride - dest image strides in bytes
145 * srcFormat - source image format (GL_ALPHA, GL_RED, GL_RGB, etc)
146 * srcType - GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_FLOAT, etc
147 * srcPacking - describes packing of incoming image.
148 * transferOps - mask of pixel transfer operations
149 */
150 static void
151 transfer_teximage(GLcontext *ctx, GLuint dimensions,
152 GLenum texDestFormat, GLvoid *texDestAddr,
153 GLint srcWidth, GLint srcHeight, GLint srcDepth,
154 GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
155 GLint dstRowStride, GLint dstImageStride,
156 GLenum srcFormat, GLenum srcType,
157 const GLvoid *srcAddr,
158 const struct gl_pixelstore_attrib *srcPacking,
159 GLuint transferOps)
160 {
161 GLint texComponents;
162
163 ASSERT(ctx);
164 ASSERT(dimensions >= 1 && dimensions <= 3);
165 ASSERT(texDestAddr);
166 ASSERT(srcWidth >= 1);
167 ASSERT(srcHeight >= 1);
168 ASSERT(srcDepth >= 1);
169 ASSERT(dstXoffset >= 0);
170 ASSERT(dstYoffset >= 0);
171 ASSERT(dstZoffset >= 0);
172 ASSERT(dstRowStride >= 0);
173 ASSERT(dstImageStride >= 0);
174 ASSERT(srcAddr);
175 ASSERT(srcPacking);
176
177 texComponents = components_in_intformat(texDestFormat);
178
179 /* try common 2D texture cases first */
180 if (!transferOps && dimensions == 2 && srcType == CHAN_TYPE) {
181
182 if (srcFormat == texDestFormat) {
183 /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA,
184 * GL_LUMINANCE_ALPHA, etc. texture formats. Use memcpy().
185 */
186 const GLchan *src = (const GLchan *) _mesa_image_address(
187 srcPacking, srcAddr, srcWidth, srcHeight,
188 srcFormat, srcType, 0, 0, 0);
189 const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
190 srcWidth, srcFormat, srcType);
191 const GLint widthInBytes = srcWidth * texComponents * sizeof(GLchan);
192 GLchan *dst = (GLchan *) texDestAddr
193 + dstYoffset * (dstRowStride / sizeof(GLchan))
194 + dstXoffset * texComponents;
195 if (srcRowStride == widthInBytes && dstRowStride == widthInBytes) {
196 MEMCPY(dst, src, srcHeight * widthInBytes);
197 }
198 else {
199 GLint i;
200 for (i = 0; i < srcHeight; i++) {
201 MEMCPY(dst, src, widthInBytes);
202 src += (srcRowStride / sizeof(GLchan));
203 dst += (dstRowStride / sizeof(GLchan));
204 }
205 }
206 return; /* all done */
207 }
208 else if (srcFormat == GL_RGBA && texDestFormat == GL_RGB) {
209 /* commonly used by Quake */
210 const GLchan *src = (const GLchan *) _mesa_image_address(
211 srcPacking, srcAddr, srcWidth, srcHeight,
212 srcFormat, srcType, 0, 0, 0);
213 const GLint srcRowStride = _mesa_image_row_stride(srcPacking,
214 srcWidth, srcFormat, srcType);
215 GLchan *dst = (GLchan *) texDestAddr
216 + dstYoffset * (dstRowStride / sizeof(GLchan))
217 + dstXoffset * texComponents;
218 GLint i, j;
219 for (i = 0; i < srcHeight; i++) {
220 const GLchan *s = src;
221 GLchan *d = dst;
222 for (j = 0; j < srcWidth; j++) {
223 *d++ = *s++; /*red*/
224 *d++ = *s++; /*green*/
225 *d++ = *s++; /*blue*/
226 s++; /*alpha*/
227 }
228 src += (srcRowStride / sizeof(GLchan));
229 dst += (dstRowStride / sizeof(GLchan));
230 }
231 return; /* all done */
232 }
233 }
234
235 /*
236 * General case solutions
237 */
238 if (texDestFormat == GL_COLOR_INDEX) {
239 /* color index texture */
240 const GLenum texType = CHAN_TYPE;
241 GLint img, row;
242 GLchan *dest = (GLchan *) texDestAddr
243 + dstZoffset * (dstImageStride / sizeof(GLchan))
244 + dstYoffset * (dstRowStride / sizeof(GLchan))
245 + dstXoffset * texComponents;
246 for (img = 0; img < srcDepth; img++) {
247 GLchan *destRow = dest;
248 for (row = 0; row < srcHeight; row++) {
249 const GLvoid *src = _mesa_image_address(srcPacking,
250 srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
251 _mesa_unpack_index_span(ctx, srcWidth, texType, destRow,
252 srcType, src, srcPacking, transferOps);
253 destRow += (dstRowStride / sizeof(GLchan));
254 }
255 dest += dstImageStride;
256 }
257 }
258 else if (texDestFormat == GL_DEPTH_COMPONENT) {
259 /* Depth texture (shadow maps) */
260 GLint img, row;
261 GLubyte *dest = (GLubyte *) texDestAddr
262 + dstZoffset * dstImageStride
263 + dstYoffset * (dstRowStride / sizeof(GLchan))
264 + dstXoffset * texComponents;
265 for (img = 0; img < srcDepth; img++) {
266 GLubyte *destRow = dest;
267 for (row = 0; row < srcHeight; row++) {
268 const GLvoid *src = _mesa_image_address(srcPacking,
269 srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0);
270 _mesa_unpack_depth_span(ctx, srcWidth, (GLfloat *) destRow,
271 srcType, src, srcPacking);
272 destRow += (dstRowStride / sizeof(GLchan));
273 }
274 dest += dstImageStride;
275 }
276 }
277 else {
278 /* regular, color texture */
279 if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) ||
280 (dimensions >= 2 && ctx->Pixel.Convolution2DEnabled) ||
281 (dimensions >= 2 && ctx->Pixel.Separable2DEnabled)) {
282 /*
283 * Fill texture image with convolution
284 */
285 GLint img, row;
286 GLint convWidth = srcWidth, convHeight = srcHeight;
287 GLfloat *tmpImage, *convImage;
288 tmpImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
289 if (!tmpImage) {
290 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
291 return;
292 }
293 convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
294 if (!convImage) {
295 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
296 FREE(tmpImage);
297 return;
298 }
299
300 for (img = 0; img < srcDepth; img++) {
301 const GLfloat *srcf;
302 GLfloat *dstf = tmpImage;
303 GLchan *dest;
304
305 /* unpack and do transfer ops up to convolution */
306 for (row = 0; row < srcHeight; row++) {
307 const GLvoid *src = _mesa_image_address(srcPacking,
308 srcAddr, srcWidth, srcHeight,
309 srcFormat, srcType, img, row, 0);
310 _mesa_unpack_float_color_span(ctx, srcWidth, GL_RGBA, dstf,
311 srcFormat, srcType, src, srcPacking,
312 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
313 GL_TRUE);
314 dstf += srcWidth * 4;
315 }
316
317 /* convolve */
318 if (dimensions == 1) {
319 ASSERT(ctx->Pixel.Convolution1DEnabled);
320 _mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage);
321 }
322 else {
323 if (ctx->Pixel.Convolution2DEnabled) {
324 _mesa_convolve_2d_image(ctx, &convWidth, &convHeight,
325 tmpImage, convImage);
326 }
327 else {
328 ASSERT(ctx->Pixel.Separable2DEnabled);
329 _mesa_convolve_sep_image(ctx, &convWidth, &convHeight,
330 tmpImage, convImage);
331 }
332 }
333
334 /* packing and transfer ops after convolution */
335 srcf = convImage;
336 dest = (GLchan *) texDestAddr
337 + (dstZoffset + img) * (dstImageStride / sizeof(GLchan))
338 + dstYoffset * (dstRowStride / sizeof(GLchan));
339 for (row = 0; row < convHeight; row++) {
340 _mesa_pack_float_rgba_span(ctx, convWidth,
341 (const GLfloat (*)[4]) srcf,
342 texDestFormat, CHAN_TYPE,
343 dest, &_mesa_native_packing,
344 transferOps
345 & IMAGE_POST_CONVOLUTION_BITS);
346 srcf += convWidth * 4;
347 dest += (dstRowStride / sizeof(GLchan));
348 }
349 }
350
351 FREE(convImage);
352 FREE(tmpImage);
353 }
354 else {
355 /*
356 * no convolution
357 */
358 GLint img, row;
359 GLchan *dest = (GLchan *) texDestAddr
360 + dstZoffset * (dstImageStride / sizeof(GLchan))
361 + dstYoffset * (dstRowStride / sizeof(GLchan))
362 + dstXoffset * texComponents;
363 for (img = 0; img < srcDepth; img++) {
364 GLchan *destRow = dest;
365 for (row = 0; row < srcHeight; row++) {
366 const GLvoid *srcRow = _mesa_image_address(srcPacking,
367 srcAddr, srcWidth, srcHeight,
368 srcFormat, srcType, img, row, 0);
369 _mesa_unpack_chan_color_span(ctx, srcWidth, texDestFormat,
370 destRow, srcFormat, srcType, srcRow,
371 srcPacking, transferOps);
372 destRow += (dstRowStride / sizeof(GLchan));
373 }
374 dest += dstImageStride / sizeof(GLchan);
375 }
376 }
377 }
378 }
379
380
381
382 /*
383 * Transfer a texture image from user space to <destAddr> applying all
384 * needed image transfer operations and storing the result in the format
385 * specified by <dstFormat>. <dstFormat> may be any format from texformat.h.
386 * Input:
387 * dimensions - 1, 2 or 3
388 * baseInternalFormat - base format of the internal texture format
389 * specified by the user. This is very important, see below.
390 * dstFormat - destination image format
391 * dstAddr - destination address
392 * srcWidth, srcHeight, srcDepth - size of source iamge
393 * dstX/Y/Zoffset - as specified by glTexSubImage
394 * dstRowStride - stride between dest rows in bytes
395 * dstImageStride - stride between dest images in bytes
396 * srcFormat, srcType - incoming image format and datatype
397 * srcAddr - source image address
398 * srcPacking - packing params of source image
399 *
400 * XXX this function is a bit more complicated than it should be. If
401 * _mesa_convert_texsubimage[123]d could handle any dest/source formats
402 * or if transfer_teximage() could store in any MESA_FORMAT_* format, we
403 * could simplify things here.
404 */
405 void
406 _mesa_transfer_teximage(GLcontext *ctx, GLuint dimensions,
407 GLenum baseInternalFormat,
408 const struct gl_texture_format *dstFormat,
409 GLvoid *dstAddr,
410 GLint srcWidth, GLint srcHeight, GLint srcDepth,
411 GLint dstXoffset, GLint dstYoffset, GLint dstZoffset,
412 GLint dstRowStride, GLint dstImageStride,
413 GLenum srcFormat, GLenum srcType,
414 const GLvoid *srcAddr,
415 const struct gl_pixelstore_attrib *srcPacking)
416 {
417 const GLint dstRowStridePixels = dstRowStride / dstFormat->TexelBytes;
418 const GLint dstImageStridePixels = dstImageStride / dstFormat->TexelBytes;
419 GLboolean makeTemp;
420 GLuint transferOps = ctx->_ImageTransferState;
421 GLboolean freeSourceData = GL_FALSE;
422 GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
423
424 assert(baseInternalFormat > 0);
425
426 if (transferOps & IMAGE_CONVOLUTION_BIT) {
427 _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
428 &postConvHeight);
429 }
430
431 /*
432 * Consider this scenario: The user's source image is GL_RGB and the
433 * requested internal format is GL_LUMINANCE. Now suppose the device
434 * driver doesn't support GL_LUMINANCE and instead uses RGB16 as the
435 * texture format. In that case we still need to do an intermediate
436 * conversion to luminance format so that the incoming red channel gets
437 * replicated into the dest red, green and blue channels. The following
438 * code takes care of that.
439 */
440 if (dstFormat->BaseFormat != baseInternalFormat) {
441 /* Allocate storage for temporary image in the baseInternalFormat */
442 const GLint texelSize = _mesa_components_in_format(baseInternalFormat)
443 * sizeof(GLchan);
444 const GLint bytes = texelSize * postConvWidth * postConvHeight *srcDepth;
445 const GLint tmpRowStride = texelSize * postConvWidth;
446 const GLint tmpImgStride = texelSize * postConvWidth * postConvHeight;
447 GLvoid *tmpImage = MALLOC(bytes);
448 if (!tmpImage)
449 return;
450 transfer_teximage(ctx, dimensions, baseInternalFormat, tmpImage,
451 srcWidth, srcHeight, srcDepth,
452 0, 0, 0, /* x/y/zoffset */
453 tmpRowStride, tmpImgStride,
454 srcFormat, srcType, srcAddr, srcPacking, transferOps);
455
456 /* this is our new source image */
457 srcWidth = postConvWidth;
458 srcHeight = postConvHeight;
459 srcFormat = baseInternalFormat;
460 srcType = CHAN_TYPE;
461 srcAddr = tmpImage;
462 srcPacking = &_mesa_native_packing;
463 freeSourceData = GL_TRUE;
464 transferOps = 0; /* image transfer ops were completed */
465 }
466
467 /* Let the optimized tex conversion functions take a crack at the
468 * image conversion if the dest format is a h/w format.
469 */
470 if (_mesa_is_hardware_tex_format(dstFormat)) {
471 if (transferOps) {
472 makeTemp = GL_TRUE;
473 }
474 else {
475 if (dimensions == 1) {
476 makeTemp = !_mesa_convert_texsubimage1d(dstFormat->MesaFormat,
477 dstXoffset,
478 srcWidth,
479 srcFormat, srcType,
480 srcPacking, srcAddr,
481 dstAddr);
482 }
483 else if (dimensions == 2) {
484 makeTemp = !_mesa_convert_texsubimage2d(dstFormat->MesaFormat,
485 dstXoffset, dstYoffset,
486 srcWidth, srcHeight,
487 dstRowStridePixels,
488 srcFormat, srcType,
489 srcPacking, srcAddr,
490 dstAddr);
491 }
492 else {
493 assert(dimensions == 3);
494 makeTemp = !_mesa_convert_texsubimage3d(dstFormat->MesaFormat,
495 dstXoffset, dstYoffset, dstZoffset,
496 srcWidth, srcHeight, srcDepth,
497 dstRowStridePixels, dstImageStridePixels,
498 srcFormat, srcType,
499 srcPacking, srcAddr, dstAddr);
500 }
501 if (!makeTemp) {
502 /* all done! */
503 if (freeSourceData)
504 FREE((void *) srcAddr);
505 return;
506 }
507 }
508 }
509 else {
510 /* software texture format */
511 makeTemp = GL_FALSE;
512 }
513
514 if (makeTemp) {
515 GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
516 GLenum tmpFormat;
517 GLuint tmpComps, tmpTexelSize;
518 GLint tmpRowStride, tmpImageStride;
519 GLubyte *tmpImage;
520
521 if (transferOps & IMAGE_CONVOLUTION_BIT) {
522 _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
523 &postConvHeight);
524 }
525
526 tmpFormat = dstFormat->BaseFormat;
527 tmpComps = _mesa_components_in_format(tmpFormat);
528 tmpTexelSize = tmpComps * sizeof(GLchan);
529 tmpRowStride = postConvWidth * tmpTexelSize;
530 tmpImageStride = postConvWidth * postConvHeight * tmpTexelSize;
531 tmpImage = (GLubyte *) MALLOC(postConvWidth * postConvHeight *
532 srcDepth * tmpTexelSize);
533 if (!tmpImage) {
534 if (freeSourceData)
535 FREE((void *) srcAddr);
536 return;
537 }
538
539 transfer_teximage(ctx, dimensions, tmpFormat, tmpImage,
540 srcWidth, srcHeight, srcDepth,
541 0, 0, 0, /* x/y/zoffset */
542 tmpRowStride, tmpImageStride,
543 srcFormat, srcType, srcAddr, srcPacking, transferOps);
544
545 if (freeSourceData)
546 FREE((void *) srcAddr);
547
548 /* the temp image is our new source image */
549 srcWidth = postConvWidth;
550 srcHeight = postConvHeight;
551 srcFormat = tmpFormat;
552 srcType = CHAN_TYPE;
553 srcAddr = tmpImage;
554 srcPacking = &_mesa_native_packing;
555 freeSourceData = GL_TRUE;
556 }
557
558 if (_mesa_is_hardware_tex_format(dstFormat)) {
559 assert(makeTemp);
560 if (dimensions == 1) {
561 GLboolean b;
562 b = _mesa_convert_texsubimage1d(dstFormat->MesaFormat,
563 dstXoffset,
564 srcWidth,
565 srcFormat, srcType,
566 srcPacking, srcAddr,
567 dstAddr);
568 assert(b);
569 }
570 else if (dimensions == 2) {
571 GLboolean b;
572 b = _mesa_convert_texsubimage2d(dstFormat->MesaFormat,
573 dstXoffset, dstYoffset,
574 srcWidth, srcHeight,
575 dstRowStridePixels,
576 srcFormat, srcType,
577 srcPacking, srcAddr,
578 dstAddr);
579 assert(b);
580 }
581 else {
582 GLboolean b;
583 b = _mesa_convert_texsubimage3d(dstFormat->MesaFormat,
584 dstXoffset, dstYoffset, dstZoffset,
585 srcWidth, srcHeight, srcDepth,
586 dstRowStridePixels, dstImageStridePixels,
587 srcFormat, srcType,
588 srcPacking, srcAddr, dstAddr);
589 assert(b);
590 }
591 }
592 else {
593 /* software format */
594 assert(!makeTemp);
595 transfer_teximage(ctx, dimensions, dstFormat->BaseFormat, dstAddr,
596 srcWidth, srcHeight, srcDepth,
597 dstXoffset, dstYoffset, dstZoffset,
598 dstRowStride, dstImageStride,
599 srcFormat, srcType, srcAddr, srcPacking, transferOps);
600 }
601
602 if (freeSourceData)
603 FREE((void *) srcAddr); /* the temp image */
604 }
605
606
607 /*
608 * This is the software fallback for Driver.TexImage1D().
609 * The texture image type will be GLchan.
610 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
611 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
612 *
613 */
614 void
615 _mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
616 GLint internalFormat,
617 GLint width, GLint border,
618 GLenum format, GLenum type, const GLvoid *pixels,
619 const struct gl_pixelstore_attrib *packing,
620 struct gl_texture_object *texObj,
621 struct gl_texture_image *texImage)
622 {
623 GLint postConvWidth = width;
624 GLint texelBytes, sizeInBytes;
625
626 if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
627 _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
628 }
629
630 /* choose the texture format */
631 assert(ctx->Driver.ChooseTextureFormat);
632 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
633 internalFormat, format, type);
634 assert(texImage->TexFormat);
635 texImage->FetchTexel = texImage->TexFormat->FetchTexel1D;
636
637 texelBytes = texImage->TexFormat->TexelBytes;
638
639 /* Compute image size, in bytes */
640 if (texImage->IsCompressed) {
641 assert(ctx->Driver.CompressedTextureSize);
642 sizeInBytes = ctx->Driver.CompressedTextureSize(ctx, texImage);
643 assert(sizeInBytes > 0);
644 texImage->CompressedSize = sizeInBytes;
645 }
646 else {
647 sizeInBytes = postConvWidth * texelBytes;
648 }
649
650 /* allocate memory */
651 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
652 if (!texImage->Data) {
653 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
654 return;
655 }
656
657 if (pixels) {
658 /* unpack image, apply transfer ops and store in texImage->Data */
659 _mesa_transfer_teximage(ctx, 1,
660 _mesa_base_tex_format(ctx, internalFormat),
661 texImage->TexFormat, texImage->Data,
662 width, 1, 1, 0, 0, 0,
663 0, /* dstRowStride */
664 0, /* dstImageStride */
665 format, type, pixels, packing);
666
667 /* GL_SGIS_generate_mipmap */
668 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
669 _mesa_generate_mipmap(ctx,
670 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
671 texObj);
672 }
673 }
674 }
675
676
677 /*
678 * This is the software fallback for Driver.TexImage2D().
679 * The texture image type will be GLchan.
680 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
681 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
682 *
683 * NOTE: if real texture compression is supported, this whole function
684 * will need to be overridden.
685 */
686 void
687 _mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
688 GLint internalFormat,
689 GLint width, GLint height, GLint border,
690 GLenum format, GLenum type, const void *pixels,
691 const struct gl_pixelstore_attrib *packing,
692 struct gl_texture_object *texObj,
693 struct gl_texture_image *texImage)
694 {
695 GLint postConvWidth = width, postConvHeight = height;
696 GLint texelBytes, sizeInBytes;
697
698 if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
699 _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
700 &postConvHeight);
701 }
702
703 /* choose the texture format */
704 assert(ctx->Driver.ChooseTextureFormat);
705 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
706 internalFormat, format, type);
707 assert(texImage->TexFormat);
708 texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
709
710 texelBytes = texImage->TexFormat->TexelBytes;
711
712 /* Compute image size, in bytes */
713 if (texImage->IsCompressed) {
714 assert(ctx->Driver.CompressedTextureSize);
715 sizeInBytes = ctx->Driver.CompressedTextureSize(ctx, texImage);
716 assert(sizeInBytes > 0);
717 texImage->CompressedSize = sizeInBytes;
718 }
719 else {
720 sizeInBytes = postConvWidth * postConvHeight * texelBytes;
721 }
722
723 /* allocate memory */
724 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
725 if (!texImage->Data) {
726 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
727 return;
728 }
729
730 if (pixels) {
731 /* unpack image, apply transfer ops and store in texImage->Data */
732 _mesa_transfer_teximage(ctx, 2,
733 _mesa_base_tex_format(ctx, internalFormat),
734 texImage->TexFormat, texImage->Data,
735 width, height, 1, 0, 0, 0,
736 texImage->Width * texelBytes,
737 0, /* dstImageStride */
738 format, type, pixels, packing);
739
740 /* GL_SGIS_generate_mipmap */
741 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
742 _mesa_generate_mipmap(ctx,
743 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
744 texObj);
745 }
746 }
747 }
748
749
750
751 /*
752 * This is the software fallback for Driver.TexImage3D().
753 * The texture image type will be GLchan.
754 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
755 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
756 *
757 */
758 void
759 _mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
760 GLint internalFormat,
761 GLint width, GLint height, GLint depth, GLint border,
762 GLenum format, GLenum type, const void *pixels,
763 const struct gl_pixelstore_attrib *packing,
764 struct gl_texture_object *texObj,
765 struct gl_texture_image *texImage)
766 {
767 GLint texelBytes, sizeInBytes;
768
769 /* choose the texture format */
770 assert(ctx->Driver.ChooseTextureFormat);
771 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
772 internalFormat, format, type);
773 assert(texImage->TexFormat);
774 texImage->FetchTexel = texImage->TexFormat->FetchTexel3D;
775
776 texelBytes = texImage->TexFormat->TexelBytes;
777
778 /* Compute image size, in bytes */
779 if (texImage->IsCompressed) {
780 assert(ctx->Driver.CompressedTextureSize);
781 sizeInBytes = ctx->Driver.CompressedTextureSize(ctx, texImage);
782 assert(sizeInBytes > 0);
783 texImage->CompressedSize = sizeInBytes;
784 }
785 else {
786 sizeInBytes = width * height * depth * texelBytes;
787 }
788
789 /* allocate memory */
790 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
791 if (!texImage->Data) {
792 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
793 return;
794 }
795
796 if (pixels) {
797 /* unpack image, apply transfer ops and store in texImage->Data */
798 _mesa_transfer_teximage(ctx, 3,
799 _mesa_base_tex_format(ctx, internalFormat),
800 texImage->TexFormat, texImage->Data,
801 width, height, depth, 0, 0, 0,
802 texImage->Width * texelBytes,
803 texImage->Width * texImage->Height * texelBytes,
804 format, type, pixels, packing);
805
806 /* GL_SGIS_generate_mipmap */
807 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
808 _mesa_generate_mipmap(ctx,
809 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
810 texObj);
811 }
812 }
813 }
814
815
816
817
818 /*
819 * This is the software fallback for Driver.TexSubImage1D().
820 */
821 void
822 _mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
823 GLint xoffset, GLint width,
824 GLenum format, GLenum type, const void *pixels,
825 const struct gl_pixelstore_attrib *packing,
826 struct gl_texture_object *texObj,
827 struct gl_texture_image *texImage)
828 {
829 _mesa_transfer_teximage(ctx, 1,
830 _mesa_base_tex_format(ctx, texImage->IntFormat),
831 texImage->TexFormat, texImage->Data,
832 width, 1, 1, /* src size */
833 xoffset, 0, 0, /* dest offsets */
834 0, /* dstRowStride */
835 0, /* dstImageStride */
836 format, type, pixels, packing);
837
838 /* GL_SGIS_generate_mipmap */
839 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
840 _mesa_generate_mipmap(ctx, &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
841 texObj);
842 }
843 }
844
845
846 /*
847 * This is the software fallback for Driver.TexSubImage2D().
848 */
849 void
850 _mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
851 GLint xoffset, GLint yoffset,
852 GLint width, GLint height,
853 GLenum format, GLenum type, const void *pixels,
854 const struct gl_pixelstore_attrib *packing,
855 struct gl_texture_object *texObj,
856 struct gl_texture_image *texImage)
857 {
858 _mesa_transfer_teximage(ctx, 2,
859 _mesa_base_tex_format(ctx, texImage->IntFormat),
860 texImage->TexFormat, texImage->Data,
861 width, height, 1, /* src size */
862 xoffset, yoffset, 0, /* dest offsets */
863 texImage->Width * texImage->TexFormat->TexelBytes,
864 0, /* dstImageStride */
865 format, type, pixels, packing);
866
867 /* GL_SGIS_generate_mipmap */
868 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
869 _mesa_generate_mipmap(ctx, &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
870 texObj);
871 }
872 }
873
874
875 /*
876 * This is the software fallback for Driver.TexSubImage3D().
877 */
878 void
879 _mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
880 GLint xoffset, GLint yoffset, GLint zoffset,
881 GLint width, GLint height, GLint depth,
882 GLenum format, GLenum type, const void *pixels,
883 const struct gl_pixelstore_attrib *packing,
884 struct gl_texture_object *texObj,
885 struct gl_texture_image *texImage)
886 {
887 const GLint texelBytes = texImage->TexFormat->TexelBytes;
888 _mesa_transfer_teximage(ctx, 3,
889 _mesa_base_tex_format(ctx, texImage->IntFormat),
890 texImage->TexFormat, texImage->Data,
891 width, height, depth, /* src size */
892 xoffset, yoffset, xoffset, /* dest offsets */
893 texImage->Width * texelBytes,
894 texImage->Width * texImage->Height * texelBytes,
895 format, type, pixels, packing);
896 /* GL_SGIS_generate_mipmap */
897 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
898 _mesa_generate_mipmap(ctx, &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
899 texObj);
900 }
901 }
902
903
904
905
906 /*
907 * Fallback for Driver.CompressedTexImage1D()
908 */
909 void
910 _mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level,
911 GLint internalFormat,
912 GLint width, GLint border,
913 GLsizei imageSize, const GLvoid *data,
914 struct gl_texture_object *texObj,
915 struct gl_texture_image *texImage)
916 {
917 /* Nothing here.
918 * The device driver has to do it all.
919 */
920 }
921
922
923
924 /*
925 * Fallback for Driver.CompressedTexImage2D()
926 */
927 void
928 _mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level,
929 GLint internalFormat,
930 GLint width, GLint height, GLint border,
931 GLsizei imageSize, const GLvoid *data,
932 struct gl_texture_object *texObj,
933 struct gl_texture_image *texImage)
934 {
935 /* Nothing here.
936 * The device driver has to do it all.
937 */
938 }
939
940
941
942 /*
943 * Fallback for Driver.CompressedTexImage3D()
944 */
945 void
946 _mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
947 GLint internalFormat,
948 GLint width, GLint height, GLint depth,
949 GLint border,
950 GLsizei imageSize, const GLvoid *data,
951 struct gl_texture_object *texObj,
952 struct gl_texture_image *texImage)
953 {
954 /* Nothing here.
955 * The device driver has to do it all.
956 */
957 }
958
959
960
961 /*
962 * Fallback for Driver.GetCompressedTexImage3D()
963 * This will probably work find for hardware drivers. That is, hardware
964 * drivers won't have to override this function, unless the compressed
965 * texture must first be fetched from the TRAM.
966 */
967 void
968 _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target,
969 GLint level, void *image,
970 const struct gl_texture_object *texObj,
971 struct gl_texture_image *texImage)
972 {
973 assert(texImage->IsCompressed);
974 assert(texImage->CompressedSize > 0);
975 MEMCPY(image, texImage->Data, texImage->CompressedSize);
976 }
977
978
979
980 /*
981 * This is the fallback for Driver.TestProxyTexImage().
982 */
983 GLboolean
984 _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
985 GLint internalFormat, GLenum format, GLenum type,
986 GLint width, GLint height, GLint depth, GLint border)
987 {
988 struct gl_texture_unit *texUnit;
989 struct gl_texture_object *texObj;
990 struct gl_texture_image *texImage;
991
992 (void) format;
993 (void) type;
994
995 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
996 texObj = _mesa_select_tex_object(ctx, texUnit, target);
997 texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
998
999 /* We always pass.
1000 * The core Mesa code will have already tested the image size, etc.
1001 * If a driver has more stringent texture limits to enforce it will
1002 * have to override this function.
1003 */
1004 /* choose the texture format */
1005 assert(ctx->Driver.ChooseTextureFormat);
1006 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1007 internalFormat, format, type);
1008 assert(texImage->TexFormat);
1009
1010 return GL_TRUE;
1011 }
1012
1013
1014
1015 /*
1016 * Average together two rows of a source image to produce a single new
1017 * row in the dest image. It's legal for the two source rows to point
1018 * to the same data. The source width must be equal to either the
1019 * dest width or two times the dest width.
1020 */
1021 static void
1022 do_row(const struct gl_texture_format *format, GLint srcWidth,
1023 const GLvoid *srcRowA, const GLvoid *srcRowB,
1024 GLint dstWidth, GLvoid *dstRow)
1025 {
1026 const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
1027 const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
1028
1029 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
1030
1031 switch (format->MesaFormat) {
1032 case MESA_FORMAT_RGBA:
1033 {
1034 GLuint i, j, k;
1035 const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
1036 const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
1037 GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
1038 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1039 i++, j += colStride, k += colStride) {
1040 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1041 rowB[j][0] + rowB[k][0]) / 4;
1042 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1043 rowB[j][1] + rowB[k][1]) / 4;
1044 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1045 rowB[j][2] + rowB[k][2]) / 4;
1046 dst[i][3] = (rowA[j][3] + rowA[k][3] +
1047 rowB[j][3] + rowB[k][3]) / 4;
1048 }
1049 }
1050 return;
1051 case MESA_FORMAT_RGB:
1052 {
1053 GLuint i, j, k;
1054 const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
1055 const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
1056 GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
1057 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1058 i++, j += colStride, k += colStride) {
1059 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1060 rowB[j][0] + rowB[k][0]) / 4;
1061 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1062 rowB[j][1] + rowB[k][1]) / 4;
1063 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1064 rowB[j][2] + rowB[k][2]) / 4;
1065 }
1066 }
1067 return;
1068 case MESA_FORMAT_ALPHA:
1069 case MESA_FORMAT_LUMINANCE:
1070 case MESA_FORMAT_INTENSITY:
1071 case MESA_FORMAT_COLOR_INDEX:
1072 {
1073 GLuint i, j, k;
1074 const GLchan *rowA = (const GLchan *) srcRowA;
1075 const GLchan *rowB = (const GLchan *) srcRowB;
1076 GLchan *dst = (GLchan *) dstRow;
1077 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1078 i++, j += colStride, k += colStride) {
1079 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
1080 }
1081 }
1082 return;
1083 case MESA_FORMAT_LUMINANCE_ALPHA:
1084 {
1085 GLuint i, j, k;
1086 const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
1087 const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
1088 GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
1089 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1090 i++, j += colStride, k += colStride) {
1091 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1092 rowB[j][0] + rowB[k][0]) / 4;
1093 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1094 rowB[j][1] + rowB[k][1]) / 4;
1095 }
1096 }
1097 return;
1098 case MESA_FORMAT_DEPTH_COMPONENT:
1099 {
1100 GLuint i, j, k;
1101 const GLfloat *rowA = (const GLfloat *) srcRowA;
1102 const GLfloat *rowB = (const GLfloat *) srcRowB;
1103 GLfloat *dst = (GLfloat *) dstRow;
1104 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1105 i++, j += colStride, k += colStride) {
1106 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
1107 }
1108 }
1109 return;
1110 /* Begin hardware formats */
1111 case MESA_FORMAT_RGBA8888:
1112 case MESA_FORMAT_ARGB8888:
1113 {
1114 GLuint i, j, k;
1115 const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
1116 const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
1117 GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
1118 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1119 i++, j += colStride, k += colStride) {
1120 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1121 rowB[j][0] + rowB[k][0]) / 4;
1122 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1123 rowB[j][1] + rowB[k][1]) / 4;
1124 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1125 rowB[j][2] + rowB[k][2]) / 4;
1126 dst[i][3] = (rowA[j][3] + rowA[k][3] +
1127 rowB[j][3] + rowB[k][3]) / 4;
1128 }
1129 }
1130 return;
1131 case MESA_FORMAT_RGB888:
1132 {
1133 GLuint i, j, k;
1134 const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
1135 const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
1136 GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
1137 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1138 i++, j += colStride, k += colStride) {
1139 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1140 rowB[j][0] + rowB[k][0]) / 4;
1141 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1142 rowB[j][1] + rowB[k][1]) / 4;
1143 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1144 rowB[j][2] + rowB[k][2]) / 4;
1145 }
1146 }
1147 return;
1148 case MESA_FORMAT_RGB565:
1149 {
1150 GLuint i, j, k;
1151 const GLushort *rowA = (const GLushort *) srcRowA;
1152 const GLushort *rowB = (const GLushort *) srcRowB;
1153 GLushort *dst = (GLushort *) dstRow;
1154 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1155 i++, j += colStride, k += colStride) {
1156 const GLint rowAr0 = rowA[j] & 0x1f;
1157 const GLint rowAr1 = rowA[k] & 0x1f;
1158 const GLint rowBr0 = rowB[j] & 0x1f;
1159 const GLint rowBr1 = rowB[k] & 0x1f;
1160 const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
1161 const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
1162 const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
1163 const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
1164 const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
1165 const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
1166 const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
1167 const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
1168 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1169 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1170 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1171 dst[i] = (blue << 11) | (green << 5) | red;
1172 }
1173 }
1174 return;
1175 case MESA_FORMAT_ARGB4444:
1176 {
1177 GLuint i, j, k;
1178 const GLushort *rowA = (const GLushort *) srcRowA;
1179 const GLushort *rowB = (const GLushort *) srcRowB;
1180 GLushort *dst = (GLushort *) dstRow;
1181 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1182 i++, j += colStride, k += colStride) {
1183 const GLint rowAr0 = rowA[j] & 0xf;
1184 const GLint rowAr1 = rowA[k] & 0xf;
1185 const GLint rowBr0 = rowB[j] & 0xf;
1186 const GLint rowBr1 = rowB[k] & 0xf;
1187 const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
1188 const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
1189 const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
1190 const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
1191 const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
1192 const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
1193 const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
1194 const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
1195 const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
1196 const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
1197 const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
1198 const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
1199 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1200 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1201 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1202 const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
1203 dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
1204 }
1205 }
1206 return;
1207 case MESA_FORMAT_ARGB1555:
1208 {
1209 GLuint i, j, k;
1210 const GLushort *rowA = (const GLushort *) srcRowA;
1211 const GLushort *rowB = (const GLushort *) srcRowB;
1212 GLushort *dst = (GLushort *) dstRow;
1213 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1214 i++, j += colStride, k += colStride) {
1215 const GLint rowAr0 = rowA[j] & 0x1f;
1216 const GLint rowAr1 = rowA[k] & 0x1f;
1217 const GLint rowBr0 = rowB[j] & 0x1f;
1218 const GLint rowBr1 = rowB[k] & 0xf;
1219 const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
1220 const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
1221 const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
1222 const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
1223 const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
1224 const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
1225 const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
1226 const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
1227 const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
1228 const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
1229 const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
1230 const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
1231 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1232 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1233 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1234 const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
1235 dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
1236 }
1237 }
1238 return;
1239 case MESA_FORMAT_AL88:
1240 {
1241 GLuint i, j, k;
1242 const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
1243 const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
1244 GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
1245 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1246 i++, j += colStride, k += colStride) {
1247 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1248 rowB[j][0] + rowB[k][0]) >> 2;
1249 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1250 rowB[j][1] + rowB[k][1]) >> 2;
1251 }
1252 }
1253 return;
1254 case MESA_FORMAT_RGB332:
1255 {
1256 GLuint i, j, k;
1257 const GLubyte *rowA = (const GLubyte *) srcRowA;
1258 const GLubyte *rowB = (const GLubyte *) srcRowB;
1259 GLubyte *dst = (GLubyte *) dstRow;
1260 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1261 i++, j += colStride, k += colStride) {
1262 const GLint rowAr0 = rowA[j] & 0x3;
1263 const GLint rowAr1 = rowA[k] & 0x3;
1264 const GLint rowBr0 = rowB[j] & 0x3;
1265 const GLint rowBr1 = rowB[k] & 0x3;
1266 const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
1267 const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
1268 const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
1269 const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
1270 const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
1271 const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
1272 const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
1273 const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
1274 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1275 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1276 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1277 dst[i] = (blue << 5) | (green << 2) | red;
1278 }
1279 }
1280 return;
1281 case MESA_FORMAT_A8:
1282 case MESA_FORMAT_L8:
1283 case MESA_FORMAT_I8:
1284 case MESA_FORMAT_CI8:
1285 {
1286 GLuint i, j, k;
1287 const GLubyte *rowA = (const GLubyte *) srcRowA;
1288 const GLubyte *rowB = (const GLubyte *) srcRowB;
1289 GLubyte *dst = (GLubyte *) dstRow;
1290 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1291 i++, j += colStride, k += colStride) {
1292 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
1293 }
1294 }
1295 return;
1296 default:
1297 _mesa_problem(NULL, "bad format in do_row()");
1298 }
1299 }
1300
1301
1302 /*
1303 * These functions generate a 1/2-size mipmap image from a source image.
1304 * Texture borders are handled by copying or averaging the source image's
1305 * border texels, depending on the scale-down factor.
1306 */
1307
1308 static void
1309 make_1d_mipmap(const struct gl_texture_format *format, GLint border,
1310 GLint srcWidth, const GLubyte *srcPtr,
1311 GLint dstWidth, GLubyte *dstPtr)
1312 {
1313 const GLint bpt = format->TexelBytes;
1314 const GLubyte *src;
1315 GLubyte *dst;
1316
1317 /* skip the border pixel, if any */
1318 src = srcPtr + border * bpt;
1319 dst = dstPtr + border * bpt;
1320
1321 /* we just duplicate the input row, kind of hack, saves code */
1322 do_row(format, srcWidth - 2 * border, src, src,
1323 dstWidth - 2 * border, dst);
1324
1325 if (border) {
1326 /* copy left-most pixel from source */
1327 MEMCPY(dstPtr, srcPtr, bpt);
1328 /* copy right-most pixel from source */
1329 MEMCPY(dstPtr + (dstWidth - 1) * bpt,
1330 srcPtr + (srcWidth - 1) * bpt,
1331 bpt);
1332 }
1333 }
1334
1335
1336 static void
1337 make_2d_mipmap(const struct gl_texture_format *format, GLint border,
1338 GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
1339 GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
1340 {
1341 const GLint bpt = format->TexelBytes;
1342 const GLint srcWidthNB = srcWidth - 2 * border; /* sizes w/out border */
1343 const GLint dstWidthNB = dstWidth - 2 * border;
1344 const GLint dstHeightNB = dstHeight - 2 * border;
1345 const GLint srcRowStride = bpt * srcWidth;
1346 const GLint dstRowStride = bpt * dstWidth;
1347 const GLubyte *srcA, *srcB;
1348 GLubyte *dst;
1349 GLint row, colStride;
1350
1351 colStride = (srcWidth == dstWidth) ? 1 : 2;
1352
1353 /* Compute src and dst pointers, skipping any border */
1354 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
1355 if (srcHeight > 1)
1356 srcB = srcA + srcRowStride;
1357 else
1358 srcB = srcA;
1359 dst = dstPtr + border * ((dstWidth + 1) * bpt);
1360
1361 for (row = 0; row < dstHeightNB; row++) {
1362 do_row(format, srcWidthNB, srcA, srcB,
1363 dstWidthNB, dst);
1364 srcA += 2 * srcRowStride;
1365 srcB += 2 * srcRowStride;
1366 dst += dstRowStride;
1367 }
1368
1369 /* This is ugly but probably won't be used much */
1370 if (border > 0) {
1371 /* fill in dest border */
1372 /* lower-left border pixel */
1373 MEMCPY(dstPtr, srcPtr, bpt);
1374 /* lower-right border pixel */
1375 MEMCPY(dstPtr + (dstWidth - 1) * bpt,
1376 srcPtr + (srcWidth - 1) * bpt, bpt);
1377 /* upper-left border pixel */
1378 MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
1379 srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
1380 /* upper-right border pixel */
1381 MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
1382 srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
1383 /* lower border */
1384 do_row(format, srcWidthNB,
1385 srcPtr + bpt,
1386 srcPtr + bpt,
1387 dstWidthNB, dstPtr + bpt);
1388 /* upper border */
1389 do_row(format, srcWidthNB,
1390 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1391 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1392 dstWidthNB,
1393 dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
1394 /* left and right borders */
1395 if (srcHeight == dstHeight) {
1396 /* copy border pixel from src to dst */
1397 for (row = 1; row < srcHeight; row++) {
1398 MEMCPY(dstPtr + dstWidth * row * bpt,
1399 srcPtr + srcWidth * row * bpt, bpt);
1400 MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
1401 srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
1402 }
1403 }
1404 else {
1405 /* average two src pixels each dest pixel */
1406 for (row = 0; row < dstHeightNB; row += 2) {
1407 do_row(format, 1,
1408 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
1409 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
1410 1, dstPtr + (dstWidth * row + 1) * bpt);
1411 do_row(format, 1,
1412 srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
1413 srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
1414 1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
1415 }
1416 }
1417 }
1418 }
1419
1420
1421 static void
1422 make_3d_mipmap(const struct gl_texture_format *format, GLint border,
1423 GLint srcWidth, GLint srcHeight, GLint srcDepth,
1424 const GLubyte *srcPtr,
1425 GLint dstWidth, GLint dstHeight, GLint dstDepth,
1426 GLubyte *dstPtr)
1427 {
1428 const GLint bpt = format->TexelBytes;
1429 const GLint srcWidthNB = srcWidth - 2 * border; /* sizes w/out border */
1430 const GLint srcDepthNB = srcDepth - 2 * border;
1431 const GLint dstWidthNB = dstWidth - 2 * border;
1432 const GLint dstHeightNB = dstHeight - 2 * border;
1433 const GLint dstDepthNB = dstDepth - 2 * border;
1434 GLvoid *tmpRowA, *tmpRowB;
1435 GLint img, row;
1436 GLint bytesPerSrcImage, bytesPerDstImage;
1437 GLint bytesPerSrcRow, bytesPerDstRow;
1438 GLint srcImageOffset, srcRowOffset;
1439
1440 (void) srcDepthNB; /* silence warnings */
1441
1442 /* Need two temporary row buffers */
1443 tmpRowA = MALLOC(srcWidth * bpt);
1444 if (!tmpRowA)
1445 return;
1446 tmpRowB = MALLOC(srcWidth * bpt);
1447 if (!tmpRowB) {
1448 FREE(tmpRowA);
1449 return;
1450 }
1451
1452 bytesPerSrcImage = srcWidth * srcHeight * bpt;
1453 bytesPerDstImage = dstWidth * dstHeight * bpt;
1454
1455 bytesPerSrcRow = srcWidth * bpt;
1456 bytesPerDstRow = dstWidth * bpt;
1457
1458 /* Offset between adjacent src images to be averaged together */
1459 srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
1460
1461 /* Offset between adjacent src rows to be averaged together */
1462 srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
1463
1464 /*
1465 * Need to average together up to 8 src pixels for each dest pixel.
1466 * Break that down into 3 operations:
1467 * 1. take two rows from source image and average them together.
1468 * 2. take two rows from next source image and average them together.
1469 * 3. take the two averaged rows and average them for the final dst row.
1470 */
1471
1472 /*
1473 printf("mip3d %d x %d x %d -> %d x %d x %d\n",
1474 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
1475 */
1476
1477 for (img = 0; img < dstDepthNB; img++) {
1478 /* first source image pointer, skipping border */
1479 const GLubyte *imgSrcA = srcPtr
1480 + (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
1481 + img * (bytesPerSrcImage + srcImageOffset);
1482 /* second source image pointer, skipping border */
1483 const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
1484 /* address of the dest image, skipping border */
1485 GLubyte *imgDst = dstPtr
1486 + (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
1487 + img * bytesPerDstImage;
1488
1489 /* setup the four source row pointers and the dest row pointer */
1490 const GLubyte *srcImgARowA = imgSrcA;
1491 const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
1492 const GLubyte *srcImgBRowA = imgSrcB;
1493 const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
1494 GLubyte *dstImgRow = imgDst;
1495
1496 for (row = 0; row < dstHeightNB; row++) {
1497 /* Average together two rows from first src image */
1498 do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
1499 srcWidthNB, tmpRowA);
1500 /* Average together two rows from second src image */
1501 do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
1502 srcWidthNB, tmpRowB);
1503 /* Average together the temp rows to make the final row */
1504 do_row(format, srcWidthNB, tmpRowA, tmpRowB,
1505 dstWidthNB, dstImgRow);
1506 /* advance to next rows */
1507 srcImgARowA += bytesPerSrcRow + srcRowOffset;
1508 srcImgARowB += bytesPerSrcRow + srcRowOffset;
1509 srcImgBRowA += bytesPerSrcRow + srcRowOffset;
1510 srcImgBRowB += bytesPerSrcRow + srcRowOffset;
1511 dstImgRow += bytesPerDstRow;
1512 }
1513 }
1514
1515 FREE(tmpRowA);
1516 FREE(tmpRowB);
1517
1518 /* Luckily we can leverage the make_2d_mipmap() function here! */
1519 if (border > 0) {
1520 /* do front border image */
1521 make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
1522 dstWidth, dstHeight, dstPtr);
1523 /* do back border image */
1524 make_2d_mipmap(format, 1, srcWidth, srcHeight,
1525 srcPtr + bytesPerSrcImage * (srcDepth - 1),
1526 dstWidth, dstHeight,
1527 dstPtr + bytesPerDstImage * (dstDepth - 1));
1528 /* do four remaining border edges that span the image slices */
1529 if (srcDepth == dstDepth) {
1530 /* just copy border pixels from src to dst */
1531 for (img = 0; img < dstDepthNB; img++) {
1532 const GLubyte *src;
1533 GLubyte *dst;
1534
1535 /* do border along [img][row=0][col=0] */
1536 src = srcPtr + (img + 1) * bytesPerSrcImage;
1537 dst = dstPtr + (img + 1) * bytesPerDstImage;
1538 MEMCPY(dst, src, bpt);
1539
1540 /* do border along [img][row=dstHeight-1][col=0] */
1541 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1542 + (srcHeight - 1) * bytesPerSrcRow;
1543 dst = dstPtr + (img + 1) * bytesPerDstImage
1544 + (dstHeight - 1) * bytesPerDstRow;
1545 MEMCPY(dst, src, bpt);
1546
1547 /* do border along [img][row=0][col=dstWidth-1] */
1548 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1549 + (srcWidth - 1) * bpt;
1550 dst = dstPtr + (img + 1) * bytesPerDstImage
1551 + (dstWidth - 1) * bpt;
1552 MEMCPY(dst, src, bpt);
1553
1554 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1555 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1556 + (bytesPerSrcImage - bpt);
1557 dst = dstPtr + (img + 1) * bytesPerDstImage
1558 + (bytesPerDstImage - bpt);
1559 MEMCPY(dst, src, bpt);
1560 }
1561 }
1562 else {
1563 /* average border pixels from adjacent src image pairs */
1564 ASSERT(srcDepthNB == 2 * dstDepthNB);
1565 for (img = 0; img < dstDepthNB; img++) {
1566 const GLubyte *src;
1567 GLubyte *dst;
1568
1569 /* do border along [img][row=0][col=0] */
1570 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
1571 dst = dstPtr + (img + 1) * bytesPerDstImage;
1572 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1573
1574 /* do border along [img][row=dstHeight-1][col=0] */
1575 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1576 + (srcHeight - 1) * bytesPerSrcRow;
1577 dst = dstPtr + (img + 1) * bytesPerDstImage
1578 + (dstHeight - 1) * bytesPerDstRow;
1579 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1580
1581 /* do border along [img][row=0][col=dstWidth-1] */
1582 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1583 + (srcWidth - 1) * bpt;
1584 dst = dstPtr + (img + 1) * bytesPerDstImage
1585 + (dstWidth - 1) * bpt;
1586 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1587
1588 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1589 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1590 + (bytesPerSrcImage - bpt);
1591 dst = dstPtr + (img + 1) * bytesPerDstImage
1592 + (bytesPerDstImage - bpt);
1593 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1594 }
1595 }
1596 }
1597 }
1598
1599
1600 /*
1601 * For GL_SGIX_generate_mipmap:
1602 * Generate a complete set of mipmaps from texObj's base-level image.
1603 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
1604 */
1605 void
1606 _mesa_generate_mipmap(GLcontext *ctx,
1607 const struct gl_texture_unit *texUnit,
1608 struct gl_texture_object *texObj)
1609 {
1610 const GLenum targets1D[] = { GL_TEXTURE_1D, 0 };
1611 const GLenum targets2D[] = { GL_TEXTURE_2D, 0 };
1612 const GLenum targets3D[] = { GL_TEXTURE_3D, 0 };
1613 const GLenum targetsCube[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1614 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1615 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1616 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1617 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1618 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
1619 0 };
1620 const GLenum targetsRect[] = { GL_TEXTURE_RECTANGLE_NV, 0 };
1621 const GLenum *targets;
1622 GLint level;
1623 GLint maxLevels = 0;
1624
1625 ASSERT(texObj);
1626 ASSERT(texObj->Image[texObj->BaseLevel]);
1627
1628 switch (texObj->Target) {
1629 case GL_TEXTURE_1D:
1630 targets = targets1D;
1631 maxLevels = ctx->Const.MaxTextureLevels;
1632 break;
1633 case GL_TEXTURE_2D:
1634 targets = targets2D;
1635 maxLevels = ctx->Const.MaxTextureLevels;
1636 break;
1637 case GL_TEXTURE_3D:
1638 targets = targets3D;
1639 maxLevels = ctx->Const.Max3DTextureLevels;
1640 break;
1641 case GL_TEXTURE_CUBE_MAP_ARB:
1642 targets = targetsCube;
1643 maxLevels = ctx->Const.MaxCubeTextureLevels;
1644 break;
1645 case GL_TEXTURE_RECTANGLE_NV:
1646 targets = targetsRect;
1647 maxLevels = 1;
1648 break;
1649 default:
1650 _mesa_problem(ctx,
1651 "Bad texture object dimension in _mesa_generate_mipmaps");
1652 return;
1653 }
1654
1655 for (level = texObj->BaseLevel; level < texObj->MaxLevel
1656 && level < maxLevels - 1; level++) {
1657 /* generate image[level+1] from image[level] */
1658 const struct gl_texture_image *srcImage;
1659 struct gl_texture_image *dstImage;
1660 GLint srcWidth, srcHeight, srcDepth;
1661 GLint dstWidth, dstHeight, dstDepth;
1662 GLint border, bytesPerTexel;
1663 GLint t;
1664
1665 srcImage = texObj->Image[level];
1666 ASSERT(srcImage);
1667 srcWidth = srcImage->Width;
1668 srcHeight = srcImage->Height;
1669 srcDepth = srcImage->Depth;
1670 border = srcImage->Border;
1671 bytesPerTexel = srcImage->TexFormat->TexelBytes;
1672
1673 /* compute next (level+1) image size */
1674 if (srcWidth - 2 * border > 1) {
1675 dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1676 }
1677 else {
1678 dstWidth = srcWidth; /* can't go smaller */
1679 }
1680 if (srcHeight - 2 * border > 1) {
1681 dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1682 }
1683 else {
1684 dstHeight = srcHeight; /* can't go smaller */
1685 }
1686 if (srcDepth - 2 * border > 1) {
1687 dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1688 }
1689 else {
1690 dstDepth = srcDepth; /* can't go smaller */
1691 }
1692
1693 if (dstWidth == srcWidth &&
1694 dstHeight == srcHeight &&
1695 dstDepth == srcDepth) {
1696 /* all done */
1697 return;
1698 }
1699
1700 /* Need this loop just because of cubemaps */
1701 for (t = 0; targets[t]; t++) {
1702 ASSERT(t < 6);
1703
1704 dstImage = _mesa_select_tex_image(ctx, texUnit, targets[t], level+1);
1705 if (!dstImage) {
1706 dstImage = _mesa_alloc_texture_image();
1707 if (!dstImage) {
1708 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1709 return;
1710 }
1711 _mesa_set_tex_image(texObj, targets[t], level + 1, dstImage);
1712 }
1713
1714 /* Free old image data */
1715 if (dstImage->Data)
1716 MESA_PBUFFER_FREE(dstImage->Data);
1717
1718 /* initialize new image */
1719 _mesa_init_teximage_fields(ctx, t, dstImage, dstWidth, dstHeight,
1720 dstDepth, border, srcImage->Format);
1721 dstImage->DriverData = NULL;
1722 dstImage->TexFormat = srcImage->TexFormat;
1723 dstImage->FetchTexel = srcImage->FetchTexel;
1724 ASSERT(dstImage->TexFormat);
1725 ASSERT(dstImage->FetchTexel);
1726
1727 ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
1728
1729 /* alloc new image buffer */
1730 dstImage->Data = MESA_PBUFFER_ALLOC(dstWidth * dstHeight * dstDepth
1731 * bytesPerTexel);
1732 if (!dstImage->Data) {
1733 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1734 return;
1735 }
1736
1737 /*
1738 * We use simple 2x2 averaging to compute the next mipmap level.
1739 */
1740 switch (texObj->Target) {
1741 case GL_TEXTURE_1D:
1742 make_1d_mipmap(srcImage->TexFormat, border,
1743 srcWidth, (const GLubyte *) srcImage->Data,
1744 dstWidth, (GLubyte *) dstImage->Data);
1745 break;
1746 case GL_TEXTURE_2D:
1747 case GL_TEXTURE_CUBE_MAP_ARB:
1748 make_2d_mipmap(srcImage->TexFormat, border,
1749 srcWidth, srcHeight, (const GLubyte *) srcImage->Data,
1750 dstWidth, dstHeight, (GLubyte *) dstImage->Data);
1751 break;
1752 case GL_TEXTURE_3D:
1753 make_3d_mipmap(srcImage->TexFormat, border,
1754 srcWidth, srcHeight, srcDepth, (const GLubyte *) srcImage->Data,
1755 dstWidth, dstHeight, dstDepth, (GLubyte *) dstImage->Data);
1756 break;
1757 case GL_TEXTURE_RECTANGLE_NV:
1758 /* no mipmaps, do nothing */
1759 break;
1760 default:
1761 _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
1762 return;
1763 }
1764 } /* loop over tex image targets */
1765 } /* loop over tex levels */
1766 }