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