07404a26094e4112d208c1267878c8b8c0901396
[mesa.git] / src / mesa / main / texstore.c
1 /* $Id: texstore.c,v 1.41 2002/09/21 16:51:25 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 case GL_YCBCR_MESA:
119 return 2; /* Y + (Cb or Cr) */
120 default:
121 return -1; /* error */
122 }
123 }
124
125
126 /*
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.
131 *
132 * The destination texel channel type is always GLchan.
133 *
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.
137 *
138 * Input:
139 * dimensions - 1, 2, or 3
140 * texFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA,
141 * GL_RGB or GL_RGBA
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
151 */
152 static void
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,
161 GLuint transferOps)
162 {
163 GLint texComponents;
164
165 ASSERT(ctx);
166 ASSERT(dimensions >= 1 && dimensions <= 3);
167 ASSERT(texDestAddr);
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);
176 ASSERT(srcAddr);
177 ASSERT(srcPacking);
178
179 texComponents = components_in_intformat(texDestFormat);
180
181 /* try common 2D texture cases first */
182 if (!transferOps && dimensions == 2 && srcType == CHAN_TYPE) {
183
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().
187 */
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);
199 }
200 else {
201 GLint i;
202 for (i = 0; i < srcHeight; i++) {
203 MEMCPY(dst, src, widthInBytes);
204 src += (srcRowStride / sizeof(GLchan));
205 dst += (dstRowStride / sizeof(GLchan));
206 }
207 }
208 return; /* all done */
209 }
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;
220 GLint i, j;
221 for (i = 0; i < srcHeight; i++) {
222 const GLchan *s = src;
223 GLchan *d = dst;
224 for (j = 0; j < srcWidth; j++) {
225 *d++ = *s++; /*red*/
226 *d++ = *s++; /*green*/
227 *d++ = *s++; /*blue*/
228 s++; /*alpha*/
229 }
230 src += (srcRowStride / sizeof(GLchan));
231 dst += (dstRowStride / sizeof(GLchan));
232 }
233 return; /* all done */
234 }
235 }
236
237 /*
238 * General case solutions
239 */
240 if (texDestFormat == GL_COLOR_INDEX) {
241 /* color index texture */
242 const GLenum texType = CHAN_TYPE;
243 GLint img, row;
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));
256 }
257 dest += dstImageStride;
258 }
259 }
260 else if (texDestFormat == GL_YCBCR_MESA) {
261 /* YCbCr texture */
262 GLint img, row;
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));
277 }
278 dest += dstImageStride / sizeof(GLushort);
279 }
280 }
281 else if (texDestFormat == GL_DEPTH_COMPONENT) {
282 /* Depth texture (shadow maps) */
283 GLint img, row;
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));
296 }
297 dest += dstImageStride;
298 }
299 }
300 else {
301 /* regular, color texture */
302 if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) ||
303 (dimensions >= 2 && ctx->Pixel.Convolution2DEnabled) ||
304 (dimensions >= 2 && ctx->Pixel.Separable2DEnabled)) {
305 /*
306 * Fill texture image with convolution
307 */
308 GLint img, row;
309 GLint convWidth = srcWidth, convHeight = srcHeight;
310 GLfloat *tmpImage, *convImage;
311 tmpImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
312 if (!tmpImage) {
313 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
314 return;
315 }
316 convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat));
317 if (!convImage) {
318 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
319 FREE(tmpImage);
320 return;
321 }
322
323 for (img = 0; img < srcDepth; img++) {
324 const GLfloat *srcf;
325 GLfloat *dstf = tmpImage;
326 GLchan *dest;
327
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,
336 GL_TRUE);
337 dstf += srcWidth * 4;
338 }
339
340 /* convolve */
341 if (dimensions == 1) {
342 ASSERT(ctx->Pixel.Convolution1DEnabled);
343 _mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage);
344 }
345 else {
346 if (ctx->Pixel.Convolution2DEnabled) {
347 _mesa_convolve_2d_image(ctx, &convWidth, &convHeight,
348 tmpImage, convImage);
349 }
350 else {
351 ASSERT(ctx->Pixel.Separable2DEnabled);
352 _mesa_convolve_sep_image(ctx, &convWidth, &convHeight,
353 tmpImage, convImage);
354 }
355 }
356
357 /* packing and transfer ops after convolution */
358 srcf = convImage;
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,
367 transferOps
368 & IMAGE_POST_CONVOLUTION_BITS);
369 srcf += convWidth * 4;
370 dest += (dstRowStride / sizeof(GLchan));
371 }
372 }
373
374 FREE(convImage);
375 FREE(tmpImage);
376 }
377 else {
378 /*
379 * no convolution
380 */
381 GLint img, row;
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));
396 }
397 dest += dstImageStride / sizeof(GLchan);
398 }
399 }
400 }
401 }
402
403
404
405 /*
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.
409 * Input:
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
422 *
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.
427 */
428 void
429 _mesa_transfer_teximage(GLcontext *ctx, GLuint dimensions,
430 GLenum baseInternalFormat,
431 const struct gl_texture_format *dstFormat,
432 GLvoid *dstAddr,
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)
439 {
440 const GLint dstRowStridePixels = dstRowStride / dstFormat->TexelBytes;
441 const GLint dstImageStridePixels = dstImageStride / dstFormat->TexelBytes;
442 GLboolean makeTemp;
443 GLuint transferOps = ctx->_ImageTransferState;
444 GLboolean freeSourceData = GL_FALSE;
445 GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
446
447 assert(baseInternalFormat > 0);
448
449 if (transferOps & IMAGE_CONVOLUTION_BIT) {
450 _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
451 &postConvHeight);
452 }
453
454 /*
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.
462 */
463 if (dstFormat->BaseFormat != baseInternalFormat) {
464 /* Allocate storage for temporary image in the baseInternalFormat */
465 const GLint texelSize = _mesa_components_in_format(baseInternalFormat)
466 * sizeof(GLchan);
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);
471 if (!tmpImage)
472 return;
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);
478
479 /* this is our new source image */
480 srcWidth = postConvWidth;
481 srcHeight = postConvHeight;
482 srcFormat = baseInternalFormat;
483 srcType = CHAN_TYPE;
484 srcAddr = tmpImage;
485 srcPacking = &_mesa_native_packing;
486 freeSourceData = GL_TRUE;
487 transferOps = 0; /* image transfer ops were completed */
488 }
489
490 /* Let the optimized tex conversion functions take a crack at the
491 * image conversion if the dest format is a h/w format.
492 */
493 if (_mesa_is_hardware_tex_format(dstFormat)) {
494 if (transferOps) {
495 makeTemp = GL_TRUE;
496 }
497 else {
498 if (dimensions == 1) {
499 makeTemp = !_mesa_convert_texsubimage1d(dstFormat->MesaFormat,
500 dstXoffset,
501 srcWidth,
502 srcFormat, srcType,
503 srcPacking, srcAddr,
504 dstAddr);
505 }
506 else if (dimensions == 2) {
507 makeTemp = !_mesa_convert_texsubimage2d(dstFormat->MesaFormat,
508 dstXoffset, dstYoffset,
509 srcWidth, srcHeight,
510 dstRowStridePixels,
511 srcFormat, srcType,
512 srcPacking, srcAddr,
513 dstAddr);
514 }
515 else {
516 assert(dimensions == 3);
517 makeTemp = !_mesa_convert_texsubimage3d(dstFormat->MesaFormat,
518 dstXoffset, dstYoffset, dstZoffset,
519 srcWidth, srcHeight, srcDepth,
520 dstRowStridePixels, dstImageStridePixels,
521 srcFormat, srcType,
522 srcPacking, srcAddr, dstAddr);
523 }
524 if (!makeTemp) {
525 /* all done! */
526 if (freeSourceData)
527 FREE((void *) srcAddr);
528 return;
529 }
530 }
531 }
532 else {
533 /* software texture format */
534 makeTemp = GL_FALSE;
535 }
536
537 if (makeTemp) {
538 GLint postConvWidth = srcWidth, postConvHeight = srcHeight;
539 GLenum tmpFormat;
540 GLuint tmpComps, tmpTexelSize;
541 GLint tmpRowStride, tmpImageStride;
542 GLubyte *tmpImage;
543
544 if (transferOps & IMAGE_CONVOLUTION_BIT) {
545 _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
546 &postConvHeight);
547 }
548
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);
556 if (!tmpImage) {
557 if (freeSourceData)
558 FREE((void *) srcAddr);
559 return;
560 }
561
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);
567
568 if (freeSourceData)
569 FREE((void *) srcAddr);
570
571 /* the temp image is our new source image */
572 srcWidth = postConvWidth;
573 srcHeight = postConvHeight;
574 srcFormat = tmpFormat;
575 srcType = CHAN_TYPE;
576 srcAddr = tmpImage;
577 srcPacking = &_mesa_native_packing;
578 freeSourceData = GL_TRUE;
579 }
580
581 if (_mesa_is_hardware_tex_format(dstFormat)) {
582 assert(makeTemp);
583 if (dimensions == 1) {
584 GLboolean b;
585 b = _mesa_convert_texsubimage1d(dstFormat->MesaFormat,
586 dstXoffset,
587 srcWidth,
588 srcFormat, srcType,
589 srcPacking, srcAddr,
590 dstAddr);
591 assert(b);
592 }
593 else if (dimensions == 2) {
594 GLboolean b;
595 b = _mesa_convert_texsubimage2d(dstFormat->MesaFormat,
596 dstXoffset, dstYoffset,
597 srcWidth, srcHeight,
598 dstRowStridePixels,
599 srcFormat, srcType,
600 srcPacking, srcAddr,
601 dstAddr);
602 assert(b);
603 }
604 else {
605 GLboolean b;
606 b = _mesa_convert_texsubimage3d(dstFormat->MesaFormat,
607 dstXoffset, dstYoffset, dstZoffset,
608 srcWidth, srcHeight, srcDepth,
609 dstRowStridePixels, dstImageStridePixels,
610 srcFormat, srcType,
611 srcPacking, srcAddr, dstAddr);
612 assert(b);
613 }
614 }
615 else {
616 /* software format */
617 assert(!makeTemp);
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);
623 }
624
625 if (freeSourceData)
626 FREE((void *) srcAddr); /* the temp image */
627 }
628
629
630 /*
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.
635 *
636 */
637 void
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)
645 {
646 GLint postConvWidth = width;
647 GLint texelBytes, sizeInBytes;
648
649 if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
650 _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
651 }
652
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;
659
660 texelBytes = texImage->TexFormat->TexelBytes;
661
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;
668 }
669 else {
670 sizeInBytes = postConvWidth * texelBytes;
671 }
672
673 /* allocate memory */
674 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
675 if (!texImage->Data) {
676 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
677 return;
678 }
679
680 if (pixels) {
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);
689
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],
694 texObj);
695 }
696 }
697 }
698
699
700 /*
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.
705 *
706 * NOTE: if real texture compression is supported, this whole function
707 * will need to be overridden.
708 */
709 void
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)
717 {
718 GLint postConvWidth = width, postConvHeight = height;
719 GLint texelBytes, sizeInBytes;
720
721 if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
722 _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
723 &postConvHeight);
724 }
725
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;
732
733 texelBytes = texImage->TexFormat->TexelBytes;
734
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;
741 }
742 else {
743 sizeInBytes = postConvWidth * postConvHeight * texelBytes;
744 }
745
746 /* allocate memory */
747 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
748 if (!texImage->Data) {
749 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
750 return;
751 }
752
753 if (pixels) {
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);
762
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],
767 texObj);
768 }
769 }
770 }
771
772
773
774 /*
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.
779 *
780 */
781 void
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)
789 {
790 GLint texelBytes, sizeInBytes;
791
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;
798
799 texelBytes = texImage->TexFormat->TexelBytes;
800
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;
807 }
808 else {
809 sizeInBytes = width * height * depth * texelBytes;
810 }
811
812 /* allocate memory */
813 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
814 if (!texImage->Data) {
815 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
816 return;
817 }
818
819 if (pixels) {
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);
828
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],
833 texObj);
834 }
835 }
836 }
837
838
839
840
841 /*
842 * This is the software fallback for Driver.TexSubImage1D().
843 */
844 void
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)
851 {
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);
860
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],
865 texObj);
866 }
867 }
868
869
870 /*
871 * This is the software fallback for Driver.TexSubImage2D().
872 */
873 void
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)
881 {
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);
890
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],
895 texObj);
896 }
897 }
898
899
900 /*
901 * This is the software fallback for Driver.TexSubImage3D().
902 */
903 void
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)
911 {
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],
925 texObj);
926 }
927 }
928
929
930
931
932 /*
933 * Fallback for Driver.CompressedTexImage1D()
934 */
935 void
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)
942 {
943 /* Nothing here.
944 * The device driver has to do it all.
945 */
946 }
947
948
949
950 /*
951 * Fallback for Driver.CompressedTexImage2D()
952 */
953 void
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)
960 {
961 /* Nothing here.
962 * The device driver has to do it all.
963 */
964 }
965
966
967
968 /*
969 * Fallback for Driver.CompressedTexImage3D()
970 */
971 void
972 _mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
973 GLint internalFormat,
974 GLint width, GLint height, GLint depth,
975 GLint border,
976 GLsizei imageSize, const GLvoid *data,
977 struct gl_texture_object *texObj,
978 struct gl_texture_image *texImage)
979 {
980 /* Nothing here.
981 * The device driver has to do it all.
982 */
983 }
984
985
986
987 /*
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.
992 */
993 void
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)
998 {
999 assert(texImage->IsCompressed);
1000 assert(texImage->CompressedSize > 0);
1001 MEMCPY(image, texImage->Data, texImage->CompressedSize);
1002 }
1003
1004
1005
1006 /*
1007 * This is the fallback for Driver.TestProxyTexImage().
1008 */
1009 GLboolean
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)
1013 {
1014 struct gl_texture_unit *texUnit;
1015 struct gl_texture_object *texObj;
1016 struct gl_texture_image *texImage;
1017
1018 (void) format;
1019 (void) type;
1020
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);
1024
1025 /* We always pass.
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.
1029 */
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);
1035
1036 return GL_TRUE;
1037 }
1038
1039
1040
1041 /*
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.
1046 */
1047 static void
1048 do_row(const struct gl_texture_format *format, GLint srcWidth,
1049 const GLvoid *srcRowA, const GLvoid *srcRowB,
1050 GLint dstWidth, GLvoid *dstRow)
1051 {
1052 const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
1053 const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
1054
1055 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
1056
1057 switch (format->MesaFormat) {
1058 case MESA_FORMAT_RGBA:
1059 {
1060 GLuint i, j, k;
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;
1074 }
1075 }
1076 return;
1077 case MESA_FORMAT_RGB:
1078 {
1079 GLuint i, j, k;
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;
1091 }
1092 }
1093 return;
1094 case MESA_FORMAT_ALPHA:
1095 case MESA_FORMAT_LUMINANCE:
1096 case MESA_FORMAT_INTENSITY:
1097 case MESA_FORMAT_COLOR_INDEX:
1098 {
1099 GLuint i, j, k;
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;
1106 }
1107 }
1108 return;
1109 case MESA_FORMAT_LUMINANCE_ALPHA:
1110 {
1111 GLuint i, j, k;
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;
1121 }
1122 }
1123 return;
1124 case MESA_FORMAT_DEPTH_COMPONENT:
1125 {
1126 GLuint i, j, k;
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;
1133 }
1134 }
1135 return;
1136 /* Begin hardware formats */
1137 case MESA_FORMAT_RGBA8888:
1138 case MESA_FORMAT_ARGB8888:
1139 {
1140 GLuint i, j, k;
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;
1154 }
1155 }
1156 return;
1157 case MESA_FORMAT_RGB888:
1158 {
1159 GLuint i, j, k;
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;
1171 }
1172 }
1173 return;
1174 case MESA_FORMAT_RGB565:
1175 {
1176 GLuint i, j, k;
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;
1198 }
1199 }
1200 return;
1201 case MESA_FORMAT_ARGB4444:
1202 {
1203 GLuint i, j, k;
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;
1230 }
1231 }
1232 return;
1233 case MESA_FORMAT_ARGB1555:
1234 {
1235 GLuint i, j, k;
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;
1262 }
1263 }
1264 return;
1265 case MESA_FORMAT_AL88:
1266 {
1267 GLuint i, j, k;
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;
1277 }
1278 }
1279 return;
1280 case MESA_FORMAT_RGB332:
1281 {
1282 GLuint i, j, k;
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;
1304 }
1305 }
1306 return;
1307 case MESA_FORMAT_A8:
1308 case MESA_FORMAT_L8:
1309 case MESA_FORMAT_I8:
1310 case MESA_FORMAT_CI8:
1311 {
1312 GLuint i, j, k;
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;
1319 }
1320 }
1321 return;
1322 default:
1323 _mesa_problem(NULL, "bad format in do_row()");
1324 }
1325 }
1326
1327
1328 /*
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.
1332 */
1333
1334 static void
1335 make_1d_mipmap(const struct gl_texture_format *format, GLint border,
1336 GLint srcWidth, const GLubyte *srcPtr,
1337 GLint dstWidth, GLubyte *dstPtr)
1338 {
1339 const GLint bpt = format->TexelBytes;
1340 const GLubyte *src;
1341 GLubyte *dst;
1342
1343 /* skip the border pixel, if any */
1344 src = srcPtr + border * bpt;
1345 dst = dstPtr + border * bpt;
1346
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);
1350
1351 if (border) {
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,
1357 bpt);
1358 }
1359 }
1360
1361
1362 static void
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)
1366 {
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;
1374 GLubyte *dst;
1375 GLint row, colStride;
1376
1377 colStride = (srcWidth == dstWidth) ? 1 : 2;
1378
1379 /* Compute src and dst pointers, skipping any border */
1380 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
1381 if (srcHeight > 1)
1382 srcB = srcA + srcRowStride;
1383 else
1384 srcB = srcA;
1385 dst = dstPtr + border * ((dstWidth + 1) * bpt);
1386
1387 for (row = 0; row < dstHeightNB; row++) {
1388 do_row(format, srcWidthNB, srcA, srcB,
1389 dstWidthNB, dst);
1390 srcA += 2 * srcRowStride;
1391 srcB += 2 * srcRowStride;
1392 dst += dstRowStride;
1393 }
1394
1395 /* This is ugly but probably won't be used much */
1396 if (border > 0) {
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);
1409 /* lower border */
1410 do_row(format, srcWidthNB,
1411 srcPtr + bpt,
1412 srcPtr + bpt,
1413 dstWidthNB, dstPtr + bpt);
1414 /* upper border */
1415 do_row(format, srcWidthNB,
1416 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1417 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1418 dstWidthNB,
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);
1428 }
1429 }
1430 else {
1431 /* average two src pixels each dest pixel */
1432 for (row = 0; row < dstHeightNB; row += 2) {
1433 do_row(format, 1,
1434 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
1435 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
1436 1, dstPtr + (dstWidth * row + 1) * bpt);
1437 do_row(format, 1,
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);
1441 }
1442 }
1443 }
1444 }
1445
1446
1447 static void
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,
1452 GLubyte *dstPtr)
1453 {
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;
1461 GLint img, row;
1462 GLint bytesPerSrcImage, bytesPerDstImage;
1463 GLint bytesPerSrcRow, bytesPerDstRow;
1464 GLint srcImageOffset, srcRowOffset;
1465
1466 (void) srcDepthNB; /* silence warnings */
1467
1468 /* Need two temporary row buffers */
1469 tmpRowA = MALLOC(srcWidth * bpt);
1470 if (!tmpRowA)
1471 return;
1472 tmpRowB = MALLOC(srcWidth * bpt);
1473 if (!tmpRowB) {
1474 FREE(tmpRowA);
1475 return;
1476 }
1477
1478 bytesPerSrcImage = srcWidth * srcHeight * bpt;
1479 bytesPerDstImage = dstWidth * dstHeight * bpt;
1480
1481 bytesPerSrcRow = srcWidth * bpt;
1482 bytesPerDstRow = dstWidth * bpt;
1483
1484 /* Offset between adjacent src images to be averaged together */
1485 srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
1486
1487 /* Offset between adjacent src rows to be averaged together */
1488 srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
1489
1490 /*
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.
1496 */
1497
1498 /*
1499 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
1500 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
1501 */
1502
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;
1514
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;
1521
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;
1538 }
1539 }
1540
1541 FREE(tmpRowA);
1542 FREE(tmpRowB);
1543
1544 /* Luckily we can leverage the make_2d_mipmap() function here! */
1545 if (border > 0) {
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++) {
1558 const GLubyte *src;
1559 GLubyte *dst;
1560
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);
1565
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);
1572
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);
1579
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);
1586 }
1587 }
1588 else {
1589 /* average border pixels from adjacent src image pairs */
1590 ASSERT(srcDepthNB == 2 * dstDepthNB);
1591 for (img = 0; img < dstDepthNB; img++) {
1592 const GLubyte *src;
1593 GLubyte *dst;
1594
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);
1599
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);
1606
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);
1613
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);
1620 }
1621 }
1622 }
1623 }
1624
1625
1626 /*
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.
1630 */
1631 void
1632 _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
1633 const struct gl_texture_unit *texUnit,
1634 struct gl_texture_object *texObj)
1635 {
1636 GLint level;
1637 GLint maxLevels = 0;
1638
1639 ASSERT(texObj);
1640 ASSERT(texObj->Image[texObj->BaseLevel]);
1641
1642 switch (texObj->Target) {
1643 case GL_TEXTURE_1D:
1644 maxLevels = ctx->Const.MaxTextureLevels;
1645 break;
1646 case GL_TEXTURE_2D:
1647 maxLevels = ctx->Const.MaxTextureLevels;
1648 break;
1649 case GL_TEXTURE_3D:
1650 maxLevels = ctx->Const.Max3DTextureLevels;
1651 break;
1652 case GL_TEXTURE_CUBE_MAP_ARB:
1653 maxLevels = ctx->Const.MaxCubeTextureLevels;
1654 break;
1655 case GL_TEXTURE_RECTANGLE_NV:
1656 maxLevels = 1;
1657 break;
1658 default:
1659 _mesa_problem(ctx,
1660 "Bad texture object dimension in _mesa_generate_mipmaps");
1661 return;
1662 }
1663
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;
1672
1673 srcImage = texObj->Image[level];
1674 ASSERT(srcImage);
1675 srcWidth = srcImage->Width;
1676 srcHeight = srcImage->Height;
1677 srcDepth = srcImage->Depth;
1678 border = srcImage->Border;
1679 bytesPerTexel = srcImage->TexFormat->TexelBytes;
1680
1681 /* compute next (level+1) image size */
1682 if (srcWidth - 2 * border > 1) {
1683 dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1684 }
1685 else {
1686 dstWidth = srcWidth; /* can't go smaller */
1687 }
1688 if (srcHeight - 2 * border > 1) {
1689 dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1690 }
1691 else {
1692 dstHeight = srcHeight; /* can't go smaller */
1693 }
1694 if (srcDepth - 2 * border > 1) {
1695 dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1696 }
1697 else {
1698 dstDepth = srcDepth; /* can't go smaller */
1699 }
1700
1701 if (dstWidth == srcWidth &&
1702 dstHeight == srcHeight &&
1703 dstDepth == srcDepth) {
1704 /* all done */
1705 return;
1706 }
1707
1708 /* get dest gl_texture_image */
1709 dstImage = _mesa_select_tex_image(ctx, texUnit, target, level+1);
1710 if (!dstImage) {
1711 dstImage = _mesa_alloc_texture_image();
1712 if (!dstImage) {
1713 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1714 return;
1715 }
1716 _mesa_set_tex_image(texObj, target, level + 1, dstImage);
1717 }
1718
1719 /* Free old image data */
1720 if (dstImage->Data)
1721 MESA_PBUFFER_FREE(dstImage->Data);
1722
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);
1731
1732 ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
1733
1734 /* alloc new image buffer */
1735 dstImage->Data = MESA_PBUFFER_ALLOC(dstWidth * dstHeight * dstDepth
1736 * bytesPerTexel);
1737 if (!dstImage->Data) {
1738 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1739 return;
1740 }
1741
1742 /*
1743 * We use simple 2x2 averaging to compute the next mipmap level.
1744 */
1745 switch (target) {
1746 case GL_TEXTURE_1D:
1747 make_1d_mipmap(srcImage->TexFormat, border,
1748 srcWidth, (const GLubyte *) srcImage->Data,
1749 dstWidth, (GLubyte *) dstImage->Data);
1750 break;
1751 case GL_TEXTURE_2D:
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);
1761 break;
1762 case GL_TEXTURE_3D:
1763 make_3d_mipmap(srcImage->TexFormat, border,
1764 srcWidth, srcHeight, srcDepth,
1765 (const GLubyte *) srcImage->Data,
1766 dstWidth, dstHeight, dstDepth,
1767 (GLubyte *) dstImage->Data);
1768 break;
1769 case GL_TEXTURE_RECTANGLE_NV:
1770 /* no mipmaps, do nothing */
1771 break;
1772 default:
1773 _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
1774 return;
1775 }
1776 } /* loop over mipmap levels */
1777 }