899cf044fa7ae57f03f5a38707beaac49a3a32bd
[mesa.git] / src / mesa / main / texstore.c
1 /* $Id: texstore.c,v 1.42 2002/09/27 02:45:38 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 GLenum dstFormat, GLubyte *dest,
678 GLint dstRowStride)
679 {
680 GLchan *tempImage = NULL;
681 GLint srcRowStride;
682 GLenum baseFormat;
683
684 ASSERT(dimensions == 2);
685
686 baseFormat = _mesa_base_tex_format(ctx, dstFormat);
687
688 if (srcFormat != baseFormat || srcType != CHAN_TYPE ||
689 ctx->_ImageTransferState != 0 || unpacking->SwapBytes) {
690 /* need to convert user's image to texImage->Format, GLchan */
691 GLint comps = components_in_intformat(baseFormat);
692 GLint postConvWidth = width, postConvHeight = height;
693
694 /* XXX convolution untested */
695 if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
696 _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth,
697 &postConvHeight);
698 }
699
700 tempImage = (GLchan*) MALLOC(width * height * comps * sizeof(GLchan));
701 if (!tempImage) {
702 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
703 return;
704 }
705 transfer_teximage(ctx, dimensions,
706 baseFormat, /* dest format */
707 tempImage, /* dst address */
708 width, height, depth, /* src size */
709 0, 0, 0, /* x/y/zoffset */
710 comps * width, /* dst row stride */
711 comps * width * height, /* dst image stride */
712 srcFormat, srcType, /* src format, type */
713 source, unpacking, /* src and src packing */
714 ctx->_ImageTransferState);
715 source = tempImage;
716 width = postConvWidth;
717 height = postConvHeight;
718 srcRowStride = width;
719 }
720 else {
721 if (unpacking->RowLength)
722 srcRowStride = unpacking->RowLength;
723 else
724 srcRowStride = width;
725 }
726
727 _mesa_compress_teximage(ctx, width, height, baseFormat,
728 (const GLchan *) source, srcRowStride,
729 dstFormat, dest, dstRowStride);
730 if (tempImage) {
731 FREE(tempImage);
732 }
733 }
734
735
736
737 /*
738 * This is the software fallback for Driver.TexImage1D()
739 * and Driver.CopyTexImage2D().
740 * The texture image type will be GLchan.
741 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
742 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
743 */
744 void
745 _mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level,
746 GLint internalFormat,
747 GLint width, GLint border,
748 GLenum format, GLenum type, const GLvoid *pixels,
749 const struct gl_pixelstore_attrib *packing,
750 struct gl_texture_object *texObj,
751 struct gl_texture_image *texImage)
752 {
753 GLint postConvWidth = width;
754 GLint texelBytes, sizeInBytes;
755
756 if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
757 _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
758 }
759
760 /* choose the texture format */
761 assert(ctx->Driver.ChooseTextureFormat);
762 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
763 internalFormat, format, type);
764 assert(texImage->TexFormat);
765 texImage->FetchTexel = texImage->TexFormat->FetchTexel1D;
766
767 texelBytes = texImage->TexFormat->TexelBytes;
768
769 /* allocate memory */
770 if (texImage->IsCompressed)
771 sizeInBytes = texImage->CompressedSize;
772 else
773 sizeInBytes = postConvWidth * texelBytes;
774 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
775 if (!texImage->Data) {
776 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
777 return;
778 }
779
780 if (!pixels)
781 return;
782
783 /* unpack image, apply transfer ops and store in texImage->Data */
784 if (texImage->IsCompressed) {
785 GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
786 width);
787 transfer_compressed_teximage(ctx, 1, width, 1, 1,
788 format, type, packing,
789 pixels, texImage->IntFormat,
790 (GLubyte *) texImage->Data, dstRowStride);
791 }
792 else {
793 _mesa_transfer_teximage(ctx, 1,
794 texImage->Format, /* base format */
795 texImage->TexFormat, texImage->Data,
796 width, 1, 1, /* src size */
797 0, 0, 0, /* dstX/Y/Zoffset */
798 0, /* dstRowStride */
799 0, /* dstImageStride */
800 format, type, pixels, packing);
801 }
802
803 /* GL_SGIS_generate_mipmap */
804 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
805 _mesa_generate_mipmap(ctx, target,
806 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
807 texObj);
808 }
809 }
810
811
812 /*
813 * This is the software fallback for Driver.TexImage2D()
814 * and Driver.CopyTexImage2D().
815 * The texture image type will be GLchan.
816 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
817 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
818 */
819 void
820 _mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level,
821 GLint internalFormat,
822 GLint width, GLint height, GLint border,
823 GLenum format, GLenum type, const void *pixels,
824 const struct gl_pixelstore_attrib *packing,
825 struct gl_texture_object *texObj,
826 struct gl_texture_image *texImage)
827 {
828 GLint postConvWidth = width, postConvHeight = height;
829 GLint texelBytes, sizeInBytes;
830
831 if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
832 _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
833 &postConvHeight);
834 }
835
836 /* choose the texture format */
837 assert(ctx->Driver.ChooseTextureFormat);
838 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
839 internalFormat, format, type);
840 assert(texImage->TexFormat);
841 texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
842
843 texelBytes = texImage->TexFormat->TexelBytes;
844
845 /* allocate memory */
846 if (texImage->IsCompressed)
847 sizeInBytes = texImage->CompressedSize;
848 else
849 sizeInBytes = postConvWidth * postConvHeight * texelBytes;
850 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
851 if (!texImage->Data) {
852 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
853 return;
854 }
855
856 if (!pixels)
857 return;
858
859 /* unpack image, apply transfer ops and store in texImage->Data */
860 if (texImage->IsCompressed) {
861 GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
862 width);
863 transfer_compressed_teximage(ctx, 2, width, height, 1,
864 format, type, packing,
865 pixels, texImage->IntFormat,
866 (GLubyte *) texImage->Data, dstRowStride);
867 }
868 else {
869 _mesa_transfer_teximage(ctx, 2,
870 texImage->Format,
871 texImage->TexFormat, texImage->Data,
872 width, height, 1, /* src size */
873 0, 0, 0, /* dstX/Y/Zoffset */
874 texImage->Width * texelBytes, /* dstRowStride */
875 0, /* dstImageStride */
876 format, type, pixels, packing);
877 }
878
879 /* GL_SGIS_generate_mipmap */
880 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
881 _mesa_generate_mipmap(ctx, target,
882 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
883 texObj);
884 }
885 }
886
887
888
889 /*
890 * This is the software fallback for Driver.TexImage3D()
891 * and Driver.CopyTexImage3D().
892 * The texture image type will be GLchan.
893 * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY,
894 * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA.
895 */
896 void
897 _mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level,
898 GLint internalFormat,
899 GLint width, GLint height, GLint depth, GLint border,
900 GLenum format, GLenum type, const void *pixels,
901 const struct gl_pixelstore_attrib *packing,
902 struct gl_texture_object *texObj,
903 struct gl_texture_image *texImage)
904 {
905 GLint texelBytes, sizeInBytes;
906
907 /* choose the texture format */
908 assert(ctx->Driver.ChooseTextureFormat);
909 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
910 internalFormat, format, type);
911 assert(texImage->TexFormat);
912 texImage->FetchTexel = texImage->TexFormat->FetchTexel3D;
913
914 texelBytes = texImage->TexFormat->TexelBytes;
915
916 /* allocate memory */
917 if (texImage->IsCompressed)
918 sizeInBytes = texImage->CompressedSize;
919 else
920 sizeInBytes = width * height * depth * texelBytes;
921 texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes);
922 if (!texImage->Data) {
923 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
924 return;
925 }
926
927 if (!pixels)
928 return;
929
930 /* unpack image, apply transfer ops and store in texImage->Data */
931 if (texImage->IsCompressed) {
932 GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
933 width);
934 transfer_compressed_teximage(ctx, 3, width, height, depth,
935 format, type, packing,
936 pixels, texImage->IntFormat,
937 (GLubyte *) texImage->Data, dstRowStride);
938 }
939 else {
940 _mesa_transfer_teximage(ctx, 3,
941 texImage->Format,
942 texImage->TexFormat, texImage->Data,
943 width, height, depth, /* src size */
944 0, 0, 0, /* dstX/Y/Zoffset */
945 texImage->Width * texelBytes, /* dstRowStride */
946 texImage->Width * texImage->Height * texelBytes,
947 format, type, pixels, packing);
948 }
949
950 /* GL_SGIS_generate_mipmap */
951 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
952 _mesa_generate_mipmap(ctx, target,
953 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
954 texObj);
955 }
956 }
957
958
959
960
961 /*
962 * This is the software fallback for Driver.TexSubImage1D()
963 * and Driver.CopyTexSubImage1D().
964 */
965 void
966 _mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level,
967 GLint xoffset, GLint width,
968 GLenum format, GLenum type, const void *pixels,
969 const struct gl_pixelstore_attrib *packing,
970 struct gl_texture_object *texObj,
971 struct gl_texture_image *texImage)
972 {
973 if (texImage->IsCompressed) {
974 GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
975 texImage->Width);
976 GLubyte *dest = _mesa_compressed_image_address(xoffset, 0, 0,
977 texImage->IntFormat,
978 texImage->Width,
979 texImage->Data);
980 transfer_compressed_teximage(ctx, 1, /* dimensions */
981 width, 1, 1, /* size to replace */
982 format, type, /* source format/type */
983 packing, /* source packing */
984 pixels, /* source data */
985 texImage->IntFormat,/* dest format */
986 dest, dstRowStride);
987 }
988 else {
989 _mesa_transfer_teximage(ctx, 1,
990 texImage->Format,
991 texImage->TexFormat, texImage->Data,
992 width, 1, 1, /* src size */
993 xoffset, 0, 0, /* dest offsets */
994 0, /* dstRowStride */
995 0, /* dstImageStride */
996 format, type, pixels, packing);
997 }
998
999 /* GL_SGIS_generate_mipmap */
1000 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1001 _mesa_generate_mipmap(ctx, target,
1002 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1003 texObj);
1004 }
1005 }
1006
1007
1008
1009 /*
1010 * This is the software fallback for Driver.TexSubImage2D()
1011 * and Driver.CopyTexSubImage2D().
1012 */
1013 void
1014 _mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level,
1015 GLint xoffset, GLint yoffset,
1016 GLint width, GLint height,
1017 GLenum format, GLenum type, const void *pixels,
1018 const struct gl_pixelstore_attrib *packing,
1019 struct gl_texture_object *texObj,
1020 struct gl_texture_image *texImage)
1021 {
1022 if (texImage->IsCompressed) {
1023 GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1024 texImage->Width);
1025 GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
1026 texImage->IntFormat,
1027 texImage->Width,
1028 texImage->Data);
1029 transfer_compressed_teximage(ctx, 2, /* dimensions */
1030 width, height, 1, /* size to replace */
1031 format, type, /* source format/type */
1032 packing, /* source packing */
1033 pixels, /* source data */
1034 texImage->IntFormat,/* dest format */
1035 dest, dstRowStride);
1036 }
1037 else {
1038 _mesa_transfer_teximage(ctx, 2,
1039 texImage->Format,
1040 texImage->TexFormat, texImage->Data,
1041 width, height, 1, /* src size */
1042 xoffset, yoffset, 0, /* dest offsets */
1043 texImage->Width *texImage->TexFormat->TexelBytes,
1044 0, /* dstImageStride */
1045 format, type, pixels, packing);
1046 }
1047
1048 /* GL_SGIS_generate_mipmap */
1049 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1050 _mesa_generate_mipmap(ctx, target,
1051 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1052 texObj);
1053 }
1054 }
1055
1056
1057 /*
1058 * This is the software fallback for Driver.TexSubImage3D().
1059 * and Driver.CopyTexSubImage3D().
1060 */
1061 void
1062 _mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level,
1063 GLint xoffset, GLint yoffset, GLint zoffset,
1064 GLint width, GLint height, GLint depth,
1065 GLenum format, GLenum type, const void *pixels,
1066 const struct gl_pixelstore_attrib *packing,
1067 struct gl_texture_object *texObj,
1068 struct gl_texture_image *texImage)
1069 {
1070 if (texImage->IsCompressed) {
1071 GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1072 texImage->Width);
1073 GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, zoffset,
1074 texImage->IntFormat,
1075 texImage->Width,
1076 texImage->Data);
1077 transfer_compressed_teximage(ctx, 3, /* dimensions */
1078 width, height, depth,/* size to replace */
1079 format, type, /* source format/type */
1080 packing, /* source packing */
1081 pixels, /* source data */
1082 texImage->IntFormat,/* dest format */
1083 dest, dstRowStride);
1084 }
1085 else {
1086 const GLint texelBytes = texImage->TexFormat->TexelBytes;
1087 _mesa_transfer_teximage(ctx, 3,
1088 texImage->Format,
1089 texImage->TexFormat, texImage->Data,
1090 width, height, depth, /* src size */
1091 xoffset, yoffset, xoffset, /* dest offsets */
1092 texImage->Width * texelBytes, /* dst row stride */
1093 texImage->Width * texImage->Height * texelBytes,
1094 format, type, pixels, packing);
1095 }
1096
1097 /* GL_SGIS_generate_mipmap */
1098 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1099 _mesa_generate_mipmap(ctx, target,
1100 &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
1101 texObj);
1102 }
1103 }
1104
1105
1106
1107
1108 /*
1109 * Fallback for Driver.CompressedTexImage1D()
1110 */
1111 void
1112 _mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level,
1113 GLint internalFormat,
1114 GLint width, GLint border,
1115 GLsizei imageSize, const GLvoid *data,
1116 struct gl_texture_object *texObj,
1117 struct gl_texture_image *texImage)
1118 {
1119 /* this space intentionally left blank */
1120 }
1121
1122
1123
1124 /*
1125 * Fallback for Driver.CompressedTexImage2D()
1126 */
1127 void
1128 _mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level,
1129 GLint internalFormat,
1130 GLint width, GLint height, GLint border,
1131 GLsizei imageSize, const GLvoid *data,
1132 struct gl_texture_object *texObj,
1133 struct gl_texture_image *texImage)
1134 {
1135 /* This is pretty simple, basically just do a memcpy without worrying
1136 * about the usual image unpacking or image transfer operations.
1137 */
1138 ASSERT(texObj);
1139 ASSERT(texImage);
1140 ASSERT(texImage->Width > 0);
1141 ASSERT(texImage->Height > 0);
1142 ASSERT(texImage->Depth == 1);
1143 ASSERT(texImage->Data == NULL); /* was freed in glCompressedTexImage2DARB */
1144
1145 /* choose the texture format */
1146 assert(ctx->Driver.ChooseTextureFormat);
1147 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1148 internalFormat, 0, 0);
1149 assert(texImage->TexFormat);
1150 texImage->FetchTexel = texImage->TexFormat->FetchTexel2D;
1151
1152 /* allocate storage */
1153 texImage->Data = MESA_PBUFFER_ALLOC(imageSize);
1154 if (!texImage->Data) {
1155 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2DARB");
1156 return;
1157 }
1158
1159 /* copy the data */
1160 ASSERT(texImage->CompressedSize == imageSize);
1161 MEMCPY(texImage->Data, data, imageSize);
1162 }
1163
1164
1165
1166 /*
1167 * Fallback for Driver.CompressedTexImage3D()
1168 */
1169 void
1170 _mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level,
1171 GLint internalFormat,
1172 GLint width, GLint height, GLint depth,
1173 GLint border,
1174 GLsizei imageSize, const GLvoid *data,
1175 struct gl_texture_object *texObj,
1176 struct gl_texture_image *texImage)
1177 {
1178 /* this space intentionally left blank */
1179 }
1180
1181
1182
1183 /**
1184 * Fallback for Driver.CompressedTexSubImage1D()
1185 */
1186 void
1187 _mesa_store_compressed_texsubimage1d(GLcontext *ctx, GLenum target,
1188 GLint level,
1189 GLint xoffset, GLsizei width,
1190 GLenum format,
1191 GLsizei imageSize, const GLvoid *data,
1192 struct gl_texture_object *texObj,
1193 struct gl_texture_image *texImage)
1194 {
1195 /* this space intentionally left blank */
1196 }
1197
1198
1199 /**
1200 * Fallback for Driver.CompressedTexSubImage2D()
1201 */
1202 void
1203 _mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target,
1204 GLint level,
1205 GLint xoffset, GLint yoffset,
1206 GLsizei width, GLsizei height,
1207 GLenum format,
1208 GLsizei imageSize, const GLvoid *data,
1209 struct gl_texture_object *texObj,
1210 struct gl_texture_image *texImage)
1211 {
1212 GLint bytesPerRow, destRowStride, srcRowStride;
1213 GLint i, rows;
1214 GLubyte *dest;
1215 const GLubyte *src;
1216
1217 /* these should have been caught sooner */
1218 ASSERT((width & 3) == 0 || width == 2 || width == 1);
1219 ASSERT((height & 3) == 0 || height == 2 || height == 1);
1220 ASSERT((xoffset & 3) == 0);
1221 ASSERT((yoffset & 3) == 0);
1222
1223 srcRowStride = _mesa_compressed_row_stride(texImage->IntFormat, width);
1224 src = (const GLubyte *) data;
1225
1226 destRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1227 texImage->Width);
1228 dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
1229 texImage->IntFormat,
1230 texImage->Width, texImage->Data);
1231
1232 bytesPerRow = srcRowStride;
1233 rows = height / 4;
1234
1235 for (i = 0; i < rows; i++) {
1236 MEMCPY(dest, src, bytesPerRow);
1237 dest += destRowStride;
1238 src += srcRowStride;
1239 }
1240 }
1241
1242
1243 /**
1244 * Fallback for Driver.CompressedTexSubImage3D()
1245 */
1246 void
1247 _mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target,
1248 GLint level,
1249 GLint xoffset, GLint yoffset, GLint zoffset,
1250 GLsizei width, GLsizei height, GLsizei depth,
1251 GLenum format,
1252 GLsizei imageSize, const GLvoid *data,
1253 struct gl_texture_object *texObj,
1254 struct gl_texture_image *texImage)
1255 {
1256 /* this space intentionally left blank */
1257 }
1258
1259
1260
1261
1262
1263 /*
1264 * This is the fallback for Driver.TestProxyTexImage().
1265 */
1266 GLboolean
1267 _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
1268 GLint internalFormat, GLenum format, GLenum type,
1269 GLint width, GLint height, GLint depth, GLint border)
1270 {
1271 struct gl_texture_unit *texUnit;
1272 struct gl_texture_object *texObj;
1273 struct gl_texture_image *texImage;
1274
1275 (void) format;
1276 (void) type;
1277
1278 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1279 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1280 texImage = _mesa_select_tex_image(ctx, texUnit, target, level);
1281
1282 /* We always pass.
1283 * The core Mesa code will have already tested the image size, etc.
1284 * If a driver has more stringent texture limits to enforce it will
1285 * have to override this function.
1286 */
1287 /* choose the texture format */
1288 assert(ctx->Driver.ChooseTextureFormat);
1289 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1290 internalFormat, format, type);
1291 assert(texImage->TexFormat);
1292
1293 return GL_TRUE;
1294 }
1295
1296
1297
1298 /*
1299 * Average together two rows of a source image to produce a single new
1300 * row in the dest image. It's legal for the two source rows to point
1301 * to the same data. The source width must be equal to either the
1302 * dest width or two times the dest width.
1303 */
1304 static void
1305 do_row(const struct gl_texture_format *format, GLint srcWidth,
1306 const GLvoid *srcRowA, const GLvoid *srcRowB,
1307 GLint dstWidth, GLvoid *dstRow)
1308 {
1309 const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
1310 const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
1311
1312 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
1313
1314 switch (format->MesaFormat) {
1315 case MESA_FORMAT_RGBA:
1316 {
1317 GLuint i, j, k;
1318 const GLchan (*rowA)[4] = (const GLchan (*)[4]) srcRowA;
1319 const GLchan (*rowB)[4] = (const GLchan (*)[4]) srcRowB;
1320 GLchan (*dst)[4] = (GLchan (*)[4]) dstRow;
1321 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1322 i++, j += colStride, k += colStride) {
1323 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1324 rowB[j][0] + rowB[k][0]) / 4;
1325 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1326 rowB[j][1] + rowB[k][1]) / 4;
1327 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1328 rowB[j][2] + rowB[k][2]) / 4;
1329 dst[i][3] = (rowA[j][3] + rowA[k][3] +
1330 rowB[j][3] + rowB[k][3]) / 4;
1331 }
1332 }
1333 return;
1334 case MESA_FORMAT_RGB:
1335 {
1336 GLuint i, j, k;
1337 const GLchan (*rowA)[3] = (const GLchan (*)[3]) srcRowA;
1338 const GLchan (*rowB)[3] = (const GLchan (*)[3]) srcRowB;
1339 GLchan (*dst)[3] = (GLchan (*)[3]) dstRow;
1340 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1341 i++, j += colStride, k += colStride) {
1342 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1343 rowB[j][0] + rowB[k][0]) / 4;
1344 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1345 rowB[j][1] + rowB[k][1]) / 4;
1346 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1347 rowB[j][2] + rowB[k][2]) / 4;
1348 }
1349 }
1350 return;
1351 case MESA_FORMAT_ALPHA:
1352 case MESA_FORMAT_LUMINANCE:
1353 case MESA_FORMAT_INTENSITY:
1354 case MESA_FORMAT_COLOR_INDEX:
1355 {
1356 GLuint i, j, k;
1357 const GLchan *rowA = (const GLchan *) srcRowA;
1358 const GLchan *rowB = (const GLchan *) srcRowB;
1359 GLchan *dst = (GLchan *) dstRow;
1360 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1361 i++, j += colStride, k += colStride) {
1362 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
1363 }
1364 }
1365 return;
1366 case MESA_FORMAT_LUMINANCE_ALPHA:
1367 {
1368 GLuint i, j, k;
1369 const GLchan (*rowA)[2] = (const GLchan (*)[2]) srcRowA;
1370 const GLchan (*rowB)[2] = (const GLchan (*)[2]) srcRowB;
1371 GLchan (*dst)[2] = (GLchan (*)[2]) dstRow;
1372 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1373 i++, j += colStride, k += colStride) {
1374 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1375 rowB[j][0] + rowB[k][0]) / 4;
1376 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1377 rowB[j][1] + rowB[k][1]) / 4;
1378 }
1379 }
1380 return;
1381 case MESA_FORMAT_DEPTH_COMPONENT:
1382 {
1383 GLuint i, j, k;
1384 const GLfloat *rowA = (const GLfloat *) srcRowA;
1385 const GLfloat *rowB = (const GLfloat *) srcRowB;
1386 GLfloat *dst = (GLfloat *) dstRow;
1387 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1388 i++, j += colStride, k += colStride) {
1389 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
1390 }
1391 }
1392 return;
1393 /* Begin hardware formats */
1394 case MESA_FORMAT_RGBA8888:
1395 case MESA_FORMAT_ARGB8888:
1396 {
1397 GLuint i, j, k;
1398 const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA;
1399 const GLubyte (*rowB)[4] = (const GLubyte (*)[4]) srcRowB;
1400 GLubyte (*dst)[4] = (GLubyte (*)[4]) dstRow;
1401 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1402 i++, j += colStride, k += colStride) {
1403 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1404 rowB[j][0] + rowB[k][0]) / 4;
1405 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1406 rowB[j][1] + rowB[k][1]) / 4;
1407 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1408 rowB[j][2] + rowB[k][2]) / 4;
1409 dst[i][3] = (rowA[j][3] + rowA[k][3] +
1410 rowB[j][3] + rowB[k][3]) / 4;
1411 }
1412 }
1413 return;
1414 case MESA_FORMAT_RGB888:
1415 {
1416 GLuint i, j, k;
1417 const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA;
1418 const GLubyte (*rowB)[3] = (const GLubyte (*)[3]) srcRowB;
1419 GLubyte (*dst)[3] = (GLubyte (*)[3]) dstRow;
1420 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1421 i++, j += colStride, k += colStride) {
1422 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1423 rowB[j][0] + rowB[k][0]) / 4;
1424 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1425 rowB[j][1] + rowB[k][1]) / 4;
1426 dst[i][2] = (rowA[j][2] + rowA[k][2] +
1427 rowB[j][2] + rowB[k][2]) / 4;
1428 }
1429 }
1430 return;
1431 case MESA_FORMAT_RGB565:
1432 {
1433 GLuint i, j, k;
1434 const GLushort *rowA = (const GLushort *) srcRowA;
1435 const GLushort *rowB = (const GLushort *) srcRowB;
1436 GLushort *dst = (GLushort *) dstRow;
1437 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1438 i++, j += colStride, k += colStride) {
1439 const GLint rowAr0 = rowA[j] & 0x1f;
1440 const GLint rowAr1 = rowA[k] & 0x1f;
1441 const GLint rowBr0 = rowB[j] & 0x1f;
1442 const GLint rowBr1 = rowB[k] & 0x1f;
1443 const GLint rowAg0 = (rowA[j] >> 5) & 0x3f;
1444 const GLint rowAg1 = (rowA[k] >> 5) & 0x3f;
1445 const GLint rowBg0 = (rowB[j] >> 5) & 0x3f;
1446 const GLint rowBg1 = (rowB[k] >> 5) & 0x3f;
1447 const GLint rowAb0 = (rowA[j] >> 11) & 0x1f;
1448 const GLint rowAb1 = (rowA[k] >> 11) & 0x1f;
1449 const GLint rowBb0 = (rowB[j] >> 11) & 0x1f;
1450 const GLint rowBb1 = (rowB[k] >> 11) & 0x1f;
1451 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1452 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1453 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1454 dst[i] = (blue << 11) | (green << 5) | red;
1455 }
1456 }
1457 return;
1458 case MESA_FORMAT_ARGB4444:
1459 {
1460 GLuint i, j, k;
1461 const GLushort *rowA = (const GLushort *) srcRowA;
1462 const GLushort *rowB = (const GLushort *) srcRowB;
1463 GLushort *dst = (GLushort *) dstRow;
1464 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1465 i++, j += colStride, k += colStride) {
1466 const GLint rowAr0 = rowA[j] & 0xf;
1467 const GLint rowAr1 = rowA[k] & 0xf;
1468 const GLint rowBr0 = rowB[j] & 0xf;
1469 const GLint rowBr1 = rowB[k] & 0xf;
1470 const GLint rowAg0 = (rowA[j] >> 4) & 0xf;
1471 const GLint rowAg1 = (rowA[k] >> 4) & 0xf;
1472 const GLint rowBg0 = (rowB[j] >> 4) & 0xf;
1473 const GLint rowBg1 = (rowB[k] >> 4) & 0xf;
1474 const GLint rowAb0 = (rowA[j] >> 8) & 0xf;
1475 const GLint rowAb1 = (rowA[k] >> 8) & 0xf;
1476 const GLint rowBb0 = (rowB[j] >> 8) & 0xf;
1477 const GLint rowBb1 = (rowB[k] >> 8) & 0xf;
1478 const GLint rowAa0 = (rowA[j] >> 12) & 0xf;
1479 const GLint rowAa1 = (rowA[k] >> 12) & 0xf;
1480 const GLint rowBa0 = (rowB[j] >> 12) & 0xf;
1481 const GLint rowBa1 = (rowB[k] >> 12) & 0xf;
1482 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1483 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1484 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1485 const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
1486 dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
1487 }
1488 }
1489 return;
1490 case MESA_FORMAT_ARGB1555:
1491 {
1492 GLuint i, j, k;
1493 const GLushort *rowA = (const GLushort *) srcRowA;
1494 const GLushort *rowB = (const GLushort *) srcRowB;
1495 GLushort *dst = (GLushort *) dstRow;
1496 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1497 i++, j += colStride, k += colStride) {
1498 const GLint rowAr0 = rowA[j] & 0x1f;
1499 const GLint rowAr1 = rowA[k] & 0x1f;
1500 const GLint rowBr0 = rowB[j] & 0x1f;
1501 const GLint rowBr1 = rowB[k] & 0xf;
1502 const GLint rowAg0 = (rowA[j] >> 5) & 0x1f;
1503 const GLint rowAg1 = (rowA[k] >> 5) & 0x1f;
1504 const GLint rowBg0 = (rowB[j] >> 5) & 0x1f;
1505 const GLint rowBg1 = (rowB[k] >> 5) & 0x1f;
1506 const GLint rowAb0 = (rowA[j] >> 10) & 0x1f;
1507 const GLint rowAb1 = (rowA[k] >> 10) & 0x1f;
1508 const GLint rowBb0 = (rowB[j] >> 10) & 0x1f;
1509 const GLint rowBb1 = (rowB[k] >> 10) & 0x1f;
1510 const GLint rowAa0 = (rowA[j] >> 15) & 0x1;
1511 const GLint rowAa1 = (rowA[k] >> 15) & 0x1;
1512 const GLint rowBa0 = (rowB[j] >> 15) & 0x1;
1513 const GLint rowBa1 = (rowB[k] >> 15) & 0x1;
1514 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1515 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1516 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1517 const GLint alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 4;
1518 dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
1519 }
1520 }
1521 return;
1522 case MESA_FORMAT_AL88:
1523 {
1524 GLuint i, j, k;
1525 const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA;
1526 const GLubyte (*rowB)[2] = (const GLubyte (*)[2]) srcRowB;
1527 GLubyte (*dst)[2] = (GLubyte (*)[2]) dstRow;
1528 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1529 i++, j += colStride, k += colStride) {
1530 dst[i][0] = (rowA[j][0] + rowA[k][0] +
1531 rowB[j][0] + rowB[k][0]) >> 2;
1532 dst[i][1] = (rowA[j][1] + rowA[k][1] +
1533 rowB[j][1] + rowB[k][1]) >> 2;
1534 }
1535 }
1536 return;
1537 case MESA_FORMAT_RGB332:
1538 {
1539 GLuint i, j, k;
1540 const GLubyte *rowA = (const GLubyte *) srcRowA;
1541 const GLubyte *rowB = (const GLubyte *) srcRowB;
1542 GLubyte *dst = (GLubyte *) dstRow;
1543 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1544 i++, j += colStride, k += colStride) {
1545 const GLint rowAr0 = rowA[j] & 0x3;
1546 const GLint rowAr1 = rowA[k] & 0x3;
1547 const GLint rowBr0 = rowB[j] & 0x3;
1548 const GLint rowBr1 = rowB[k] & 0x3;
1549 const GLint rowAg0 = (rowA[j] >> 2) & 0x7;
1550 const GLint rowAg1 = (rowA[k] >> 2) & 0x7;
1551 const GLint rowBg0 = (rowB[j] >> 2) & 0x7;
1552 const GLint rowBg1 = (rowB[k] >> 2) & 0x7;
1553 const GLint rowAb0 = (rowA[j] >> 5) & 0x7;
1554 const GLint rowAb1 = (rowA[k] >> 5) & 0x7;
1555 const GLint rowBb0 = (rowB[j] >> 5) & 0x7;
1556 const GLint rowBb1 = (rowB[k] >> 5) & 0x7;
1557 const GLint red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 4;
1558 const GLint green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 4;
1559 const GLint blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 4;
1560 dst[i] = (blue << 5) | (green << 2) | red;
1561 }
1562 }
1563 return;
1564 case MESA_FORMAT_A8:
1565 case MESA_FORMAT_L8:
1566 case MESA_FORMAT_I8:
1567 case MESA_FORMAT_CI8:
1568 {
1569 GLuint i, j, k;
1570 const GLubyte *rowA = (const GLubyte *) srcRowA;
1571 const GLubyte *rowB = (const GLubyte *) srcRowB;
1572 GLubyte *dst = (GLubyte *) dstRow;
1573 for (i = j = 0, k = k0; i < (GLuint) dstWidth;
1574 i++, j += colStride, k += colStride) {
1575 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
1576 }
1577 }
1578 return;
1579 default:
1580 _mesa_problem(NULL, "bad format in do_row()");
1581 }
1582 }
1583
1584
1585 /*
1586 * These functions generate a 1/2-size mipmap image from a source image.
1587 * Texture borders are handled by copying or averaging the source image's
1588 * border texels, depending on the scale-down factor.
1589 */
1590
1591 static void
1592 make_1d_mipmap(const struct gl_texture_format *format, GLint border,
1593 GLint srcWidth, const GLubyte *srcPtr,
1594 GLint dstWidth, GLubyte *dstPtr)
1595 {
1596 const GLint bpt = format->TexelBytes;
1597 const GLubyte *src;
1598 GLubyte *dst;
1599
1600 /* skip the border pixel, if any */
1601 src = srcPtr + border * bpt;
1602 dst = dstPtr + border * bpt;
1603
1604 /* we just duplicate the input row, kind of hack, saves code */
1605 do_row(format, srcWidth - 2 * border, src, src,
1606 dstWidth - 2 * border, dst);
1607
1608 if (border) {
1609 /* copy left-most pixel from source */
1610 MEMCPY(dstPtr, srcPtr, bpt);
1611 /* copy right-most pixel from source */
1612 MEMCPY(dstPtr + (dstWidth - 1) * bpt,
1613 srcPtr + (srcWidth - 1) * bpt,
1614 bpt);
1615 }
1616 }
1617
1618
1619 static void
1620 make_2d_mipmap(const struct gl_texture_format *format, GLint border,
1621 GLint srcWidth, GLint srcHeight, const GLubyte *srcPtr,
1622 GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
1623 {
1624 const GLint bpt = format->TexelBytes;
1625 const GLint srcWidthNB = srcWidth - 2 * border; /* sizes w/out border */
1626 const GLint dstWidthNB = dstWidth - 2 * border;
1627 const GLint dstHeightNB = dstHeight - 2 * border;
1628 const GLint srcRowStride = bpt * srcWidth;
1629 const GLint dstRowStride = bpt * dstWidth;
1630 const GLubyte *srcA, *srcB;
1631 GLubyte *dst;
1632 GLint row, colStride;
1633
1634 colStride = (srcWidth == dstWidth) ? 1 : 2;
1635
1636 /* Compute src and dst pointers, skipping any border */
1637 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
1638 if (srcHeight > 1)
1639 srcB = srcA + srcRowStride;
1640 else
1641 srcB = srcA;
1642 dst = dstPtr + border * ((dstWidth + 1) * bpt);
1643
1644 for (row = 0; row < dstHeightNB; row++) {
1645 do_row(format, srcWidthNB, srcA, srcB,
1646 dstWidthNB, dst);
1647 srcA += 2 * srcRowStride;
1648 srcB += 2 * srcRowStride;
1649 dst += dstRowStride;
1650 }
1651
1652 /* This is ugly but probably won't be used much */
1653 if (border > 0) {
1654 /* fill in dest border */
1655 /* lower-left border pixel */
1656 MEMCPY(dstPtr, srcPtr, bpt);
1657 /* lower-right border pixel */
1658 MEMCPY(dstPtr + (dstWidth - 1) * bpt,
1659 srcPtr + (srcWidth - 1) * bpt, bpt);
1660 /* upper-left border pixel */
1661 MEMCPY(dstPtr + dstWidth * (dstHeight - 1) * bpt,
1662 srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
1663 /* upper-right border pixel */
1664 MEMCPY(dstPtr + (dstWidth * dstHeight - 1) * bpt,
1665 srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
1666 /* lower border */
1667 do_row(format, srcWidthNB,
1668 srcPtr + bpt,
1669 srcPtr + bpt,
1670 dstWidthNB, dstPtr + bpt);
1671 /* upper border */
1672 do_row(format, srcWidthNB,
1673 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1674 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
1675 dstWidthNB,
1676 dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
1677 /* left and right borders */
1678 if (srcHeight == dstHeight) {
1679 /* copy border pixel from src to dst */
1680 for (row = 1; row < srcHeight; row++) {
1681 MEMCPY(dstPtr + dstWidth * row * bpt,
1682 srcPtr + srcWidth * row * bpt, bpt);
1683 MEMCPY(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
1684 srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
1685 }
1686 }
1687 else {
1688 /* average two src pixels each dest pixel */
1689 for (row = 0; row < dstHeightNB; row += 2) {
1690 do_row(format, 1,
1691 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
1692 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
1693 1, dstPtr + (dstWidth * row + 1) * bpt);
1694 do_row(format, 1,
1695 srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
1696 srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
1697 1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
1698 }
1699 }
1700 }
1701 }
1702
1703
1704 static void
1705 make_3d_mipmap(const struct gl_texture_format *format, GLint border,
1706 GLint srcWidth, GLint srcHeight, GLint srcDepth,
1707 const GLubyte *srcPtr,
1708 GLint dstWidth, GLint dstHeight, GLint dstDepth,
1709 GLubyte *dstPtr)
1710 {
1711 const GLint bpt = format->TexelBytes;
1712 const GLint srcWidthNB = srcWidth - 2 * border; /* sizes w/out border */
1713 const GLint srcDepthNB = srcDepth - 2 * border;
1714 const GLint dstWidthNB = dstWidth - 2 * border;
1715 const GLint dstHeightNB = dstHeight - 2 * border;
1716 const GLint dstDepthNB = dstDepth - 2 * border;
1717 GLvoid *tmpRowA, *tmpRowB;
1718 GLint img, row;
1719 GLint bytesPerSrcImage, bytesPerDstImage;
1720 GLint bytesPerSrcRow, bytesPerDstRow;
1721 GLint srcImageOffset, srcRowOffset;
1722
1723 (void) srcDepthNB; /* silence warnings */
1724
1725 /* Need two temporary row buffers */
1726 tmpRowA = MALLOC(srcWidth * bpt);
1727 if (!tmpRowA)
1728 return;
1729 tmpRowB = MALLOC(srcWidth * bpt);
1730 if (!tmpRowB) {
1731 FREE(tmpRowA);
1732 return;
1733 }
1734
1735 bytesPerSrcImage = srcWidth * srcHeight * bpt;
1736 bytesPerDstImage = dstWidth * dstHeight * bpt;
1737
1738 bytesPerSrcRow = srcWidth * bpt;
1739 bytesPerDstRow = dstWidth * bpt;
1740
1741 /* Offset between adjacent src images to be averaged together */
1742 srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
1743
1744 /* Offset between adjacent src rows to be averaged together */
1745 srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
1746
1747 /*
1748 * Need to average together up to 8 src pixels for each dest pixel.
1749 * Break that down into 3 operations:
1750 * 1. take two rows from source image and average them together.
1751 * 2. take two rows from next source image and average them together.
1752 * 3. take the two averaged rows and average them for the final dst row.
1753 */
1754
1755 /*
1756 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
1757 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
1758 */
1759
1760 for (img = 0; img < dstDepthNB; img++) {
1761 /* first source image pointer, skipping border */
1762 const GLubyte *imgSrcA = srcPtr
1763 + (bytesPerSrcImage + bytesPerSrcRow + border) * bpt * border
1764 + img * (bytesPerSrcImage + srcImageOffset);
1765 /* second source image pointer, skipping border */
1766 const GLubyte *imgSrcB = imgSrcA + srcImageOffset;
1767 /* address of the dest image, skipping border */
1768 GLubyte *imgDst = dstPtr
1769 + (bytesPerDstImage + bytesPerDstRow + border) * bpt * border
1770 + img * bytesPerDstImage;
1771
1772 /* setup the four source row pointers and the dest row pointer */
1773 const GLubyte *srcImgARowA = imgSrcA;
1774 const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
1775 const GLubyte *srcImgBRowA = imgSrcB;
1776 const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
1777 GLubyte *dstImgRow = imgDst;
1778
1779 for (row = 0; row < dstHeightNB; row++) {
1780 /* Average together two rows from first src image */
1781 do_row(format, srcWidthNB, srcImgARowA, srcImgARowB,
1782 srcWidthNB, tmpRowA);
1783 /* Average together two rows from second src image */
1784 do_row(format, srcWidthNB, srcImgBRowA, srcImgBRowB,
1785 srcWidthNB, tmpRowB);
1786 /* Average together the temp rows to make the final row */
1787 do_row(format, srcWidthNB, tmpRowA, tmpRowB,
1788 dstWidthNB, dstImgRow);
1789 /* advance to next rows */
1790 srcImgARowA += bytesPerSrcRow + srcRowOffset;
1791 srcImgARowB += bytesPerSrcRow + srcRowOffset;
1792 srcImgBRowA += bytesPerSrcRow + srcRowOffset;
1793 srcImgBRowB += bytesPerSrcRow + srcRowOffset;
1794 dstImgRow += bytesPerDstRow;
1795 }
1796 }
1797
1798 FREE(tmpRowA);
1799 FREE(tmpRowB);
1800
1801 /* Luckily we can leverage the make_2d_mipmap() function here! */
1802 if (border > 0) {
1803 /* do front border image */
1804 make_2d_mipmap(format, 1, srcWidth, srcHeight, srcPtr,
1805 dstWidth, dstHeight, dstPtr);
1806 /* do back border image */
1807 make_2d_mipmap(format, 1, srcWidth, srcHeight,
1808 srcPtr + bytesPerSrcImage * (srcDepth - 1),
1809 dstWidth, dstHeight,
1810 dstPtr + bytesPerDstImage * (dstDepth - 1));
1811 /* do four remaining border edges that span the image slices */
1812 if (srcDepth == dstDepth) {
1813 /* just copy border pixels from src to dst */
1814 for (img = 0; img < dstDepthNB; img++) {
1815 const GLubyte *src;
1816 GLubyte *dst;
1817
1818 /* do border along [img][row=0][col=0] */
1819 src = srcPtr + (img + 1) * bytesPerSrcImage;
1820 dst = dstPtr + (img + 1) * bytesPerDstImage;
1821 MEMCPY(dst, src, bpt);
1822
1823 /* do border along [img][row=dstHeight-1][col=0] */
1824 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1825 + (srcHeight - 1) * bytesPerSrcRow;
1826 dst = dstPtr + (img + 1) * bytesPerDstImage
1827 + (dstHeight - 1) * bytesPerDstRow;
1828 MEMCPY(dst, src, bpt);
1829
1830 /* do border along [img][row=0][col=dstWidth-1] */
1831 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1832 + (srcWidth - 1) * bpt;
1833 dst = dstPtr + (img + 1) * bytesPerDstImage
1834 + (dstWidth - 1) * bpt;
1835 MEMCPY(dst, src, bpt);
1836
1837 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1838 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1839 + (bytesPerSrcImage - bpt);
1840 dst = dstPtr + (img + 1) * bytesPerDstImage
1841 + (bytesPerDstImage - bpt);
1842 MEMCPY(dst, src, bpt);
1843 }
1844 }
1845 else {
1846 /* average border pixels from adjacent src image pairs */
1847 ASSERT(srcDepthNB == 2 * dstDepthNB);
1848 for (img = 0; img < dstDepthNB; img++) {
1849 const GLubyte *src;
1850 GLubyte *dst;
1851
1852 /* do border along [img][row=0][col=0] */
1853 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage;
1854 dst = dstPtr + (img + 1) * bytesPerDstImage;
1855 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1856
1857 /* do border along [img][row=dstHeight-1][col=0] */
1858 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1859 + (srcHeight - 1) * bytesPerSrcRow;
1860 dst = dstPtr + (img + 1) * bytesPerDstImage
1861 + (dstHeight - 1) * bytesPerDstRow;
1862 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1863
1864 /* do border along [img][row=0][col=dstWidth-1] */
1865 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1866 + (srcWidth - 1) * bpt;
1867 dst = dstPtr + (img + 1) * bytesPerDstImage
1868 + (dstWidth - 1) * bpt;
1869 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1870
1871 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
1872 src = srcPtr + (img * 2 + 1) * bytesPerSrcImage
1873 + (bytesPerSrcImage - bpt);
1874 dst = dstPtr + (img + 1) * bytesPerDstImage
1875 + (bytesPerDstImage - bpt);
1876 do_row(format, 1, src, src + srcImageOffset, 1, dst);
1877 }
1878 }
1879 }
1880 }
1881
1882
1883 /*
1884 * For GL_SGIX_generate_mipmap:
1885 * Generate a complete set of mipmaps from texObj's base-level image.
1886 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
1887 */
1888 void
1889 _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
1890 const struct gl_texture_unit *texUnit,
1891 struct gl_texture_object *texObj)
1892 {
1893 const GLubyte *srcData;
1894 GLubyte *dstData;
1895 GLint level;
1896 GLint maxLevels = 0;
1897
1898 ASSERT(texObj);
1899 ASSERT(texObj->Image[texObj->BaseLevel]);
1900
1901 switch (texObj->Target) {
1902 case GL_TEXTURE_1D:
1903 maxLevels = ctx->Const.MaxTextureLevels;
1904 break;
1905 case GL_TEXTURE_2D:
1906 maxLevels = ctx->Const.MaxTextureLevels;
1907 break;
1908 case GL_TEXTURE_3D:
1909 maxLevels = ctx->Const.Max3DTextureLevels;
1910 break;
1911 case GL_TEXTURE_CUBE_MAP_ARB:
1912 maxLevels = ctx->Const.MaxCubeTextureLevels;
1913 break;
1914 case GL_TEXTURE_RECTANGLE_NV:
1915 maxLevels = 1;
1916 break;
1917 default:
1918 _mesa_problem(ctx,
1919 "Bad texture object dimension in _mesa_generate_mipmaps");
1920 return;
1921 }
1922
1923 /* setup for compressed textures */
1924 {
1925 const struct gl_texture_image *srcImage;
1926 srcImage = texObj->Image[texObj->BaseLevel];
1927 if (srcImage->IsCompressed) {
1928 /* allocate storage for uncompressed images */
1929 GLint size = _mesa_bytes_per_pixel(srcImage->Format, CHAN_TYPE)
1930 * srcImage->Width * srcImage->Height * srcImage->Depth;
1931 srcData = MALLOC(size);
1932 if (!srcData) {
1933 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
1934 return;
1935 }
1936 dstData = MALLOC(size / 2); /* 1/4 would probably be OK */
1937 if (!dstData) {
1938 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
1939 FREE((void *) srcData);
1940 return;
1941 }
1942 /* XXX decompress base image here */
1943 }
1944 }
1945
1946 for (level = texObj->BaseLevel; level < texObj->MaxLevel
1947 && level < maxLevels - 1; level++) {
1948 /* generate image[level+1] from image[level] */
1949 const struct gl_texture_image *srcImage;
1950 struct gl_texture_image *dstImage;
1951 GLint srcWidth, srcHeight, srcDepth;
1952 GLint dstWidth, dstHeight, dstDepth;
1953 GLint border, bytesPerTexel;
1954
1955 /* get src image parameters */
1956 srcImage = texObj->Image[level];
1957 ASSERT(srcImage);
1958 srcWidth = srcImage->Width;
1959 srcHeight = srcImage->Height;
1960 srcDepth = srcImage->Depth;
1961 border = srcImage->Border;
1962
1963 /* compute next (level+1) image size */
1964 if (srcWidth - 2 * border > 1) {
1965 dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1966 }
1967 else {
1968 dstWidth = srcWidth; /* can't go smaller */
1969 }
1970 if (srcHeight - 2 * border > 1) {
1971 dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1972 }
1973 else {
1974 dstHeight = srcHeight; /* can't go smaller */
1975 }
1976 if (srcDepth - 2 * border > 1) {
1977 dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1978 }
1979 else {
1980 dstDepth = srcDepth; /* can't go smaller */
1981 }
1982
1983 if (dstWidth == srcWidth &&
1984 dstHeight == srcHeight &&
1985 dstDepth == srcDepth) {
1986 /* all done */
1987 if (srcImage->IsCompressed) {
1988 FREE((void *) srcData);
1989 FREE(dstData);
1990 }
1991 return;
1992 }
1993
1994 /* get dest gl_texture_image */
1995 dstImage = _mesa_select_tex_image(ctx, texUnit, target, level+1);
1996 if (!dstImage) {
1997 dstImage = _mesa_alloc_texture_image();
1998 if (!dstImage) {
1999 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
2000 return;
2001 }
2002 _mesa_set_tex_image(texObj, target, level + 1, dstImage);
2003 }
2004
2005 /* Free old image data */
2006 if (dstImage->Data)
2007 MESA_PBUFFER_FREE(dstImage->Data);
2008
2009 /* initialize new image */
2010 _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
2011 dstDepth, border, srcImage->IntFormat);
2012 dstImage->DriverData = NULL;
2013 dstImage->TexFormat = srcImage->TexFormat;
2014 dstImage->FetchTexel = srcImage->FetchTexel;
2015 ASSERT(dstImage->TexFormat);
2016 ASSERT(dstImage->FetchTexel);
2017
2018 /* Alloc new teximage data buffer.
2019 * Setup src and dest data pointers.
2020 */
2021 if (dstImage->IsCompressed) {
2022 ASSERT(dstImage->CompressedSize > 0); /* set by init_teximage_fields*/
2023 dstImage->Data = MESA_PBUFFER_ALLOC(dstImage->CompressedSize);
2024 if (!dstImage->Data) {
2025 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
2026 return;
2027 }
2028 /* srcData and dstData are all set */
2029 ASSERT(srcData);
2030 ASSERT(dstData);
2031 }
2032 else {
2033 bytesPerTexel = srcImage->TexFormat->TexelBytes;
2034 ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
2035 dstImage->Data = MESA_PBUFFER_ALLOC(dstWidth * dstHeight * dstDepth
2036 * bytesPerTexel);
2037 if (!dstImage->Data) {
2038 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
2039 return;
2040 }
2041 srcData = (const GLubyte *) srcImage->Data;
2042 dstData = (GLubyte *) dstImage->Data;
2043 }
2044
2045 /*
2046 * We use simple 2x2 averaging to compute the next mipmap level.
2047 */
2048 switch (target) {
2049 case GL_TEXTURE_1D:
2050 make_1d_mipmap(srcImage->TexFormat, border,
2051 srcWidth, srcData,
2052 dstWidth, dstData);
2053 break;
2054 case GL_TEXTURE_2D:
2055 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
2056 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
2057 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
2058 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
2059 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
2060 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
2061 make_2d_mipmap(srcImage->TexFormat, border,
2062 srcWidth, srcHeight, srcData,
2063 dstWidth, dstHeight, dstData);
2064 break;
2065 case GL_TEXTURE_3D:
2066 make_3d_mipmap(srcImage->TexFormat, border,
2067 srcWidth, srcHeight, srcDepth, srcData,
2068 dstWidth, dstHeight, dstDepth, dstData);
2069 break;
2070 case GL_TEXTURE_RECTANGLE_NV:
2071 /* no mipmaps, do nothing */
2072 break;
2073 default:
2074 _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
2075 return;
2076 }
2077
2078 if (dstImage->IsCompressed) {
2079 GLubyte *temp;
2080 /* XXX compress from dstData into dstImage->Data */
2081
2082 /* swap src and dest pointers */
2083 temp = (GLubyte *) srcData;
2084 srcData = dstData;
2085 dstData = temp;
2086 }
2087
2088 } /* loop over mipmap levels */
2089 }