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