1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * \file mipmap.c mipmap generation and teximage resizing functions.
28 */
29
30 #include "errors.h"
31
32 #include "formats.h"
33 #include "glformats.h"
34 #include "mipmap.h"
35 #include "mtypes.h"
36 #include "teximage.h"
37 #include "texobj.h"
38 #include "texstore.h"
39 #include "image.h"
40 #include "macros.h"
41 #include "util/half_float.h"
42 #include "util/format_rgb9e5.h"
43 #include "util/format_r11g11b10f.h"
44
45 #include "state_tracker/st_cb_texture.h"
46
47 /**
48 * Compute the expected number of mipmap levels in the texture given
49 * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
50 * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap
51 * levels should be generated.
52 */
53 unsigned
_mesa_compute_num_levels(struct gl_context * ctx,struct gl_texture_object * texObj,GLenum target)54 _mesa_compute_num_levels(struct gl_context *ctx,
55 struct gl_texture_object *texObj,
56 GLenum target)
57 {
58 const struct gl_texture_image *baseImage;
59 GLuint numLevels;
60
61 baseImage = _mesa_get_tex_image(ctx, texObj, target, texObj->Attrib.BaseLevel);
62
63 numLevels = texObj->Attrib.BaseLevel + baseImage->MaxNumLevels;
64 numLevels = MIN2(numLevels, (GLuint) texObj->Attrib.MaxLevel + 1);
65 if (texObj->Immutable)
66 numLevels = MIN2(numLevels, texObj->Attrib.NumLevels);
67 assert(numLevels >= 1);
68
69 return numLevels;
70 }
71
72 #define MAX_SPAN_WIDTH 64
73
74 static void
do_span_zs(enum pipe_format format,int srcWidth,const void * srcRowA,const void * srcRowB,int dstWidth,void * dstRow)75 do_span_zs(enum pipe_format format, int srcWidth,
76 const void *srcRowA, const void *srcRowB,
77 int dstWidth, void *dstRow)
78 {
79 ASSERTED const struct util_format_description *desc =
80 util_format_description(format);
81
82 assert(desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS);
83 assert(srcWidth <= MAX_SPAN_WIDTH);
84 assert(dstWidth <= MAX_SPAN_WIDTH);
85 assert(util_format_has_depth(desc) &&
86 !util_format_has_stencil(desc));
87
88 float rowA[MAX_SPAN_WIDTH], rowB[MAX_SPAN_WIDTH],
89 result[MAX_SPAN_WIDTH];
90
91 util_format_unpack_z_float(format, rowA, srcRowA, srcWidth);
92 util_format_unpack_z_float(format, rowB, srcRowB, srcWidth);
93
94 if (srcWidth == dstWidth) {
95 for (unsigned i = 0; i < dstWidth; ++i) {
96 result[i] = (rowA[i] + rowB[i]) / 2;
97 }
98 } else {
99 for (unsigned i = 0; i < dstWidth; ++i) {
100 result[i] = (rowA[i * 2 + 0] + rowA[i * 2 + 1] +
101 rowB[i * 2 + 0] + rowB[i * 2 + 1]) / 4;
102 }
103 }
104
105 util_format_pack_z_float(format, dstRow, result, dstWidth);
106 }
107
108 static void
do_span_rgba_unorm8(enum pipe_format format,int srcWidth,const void * srcRowA,const void * srcRowB,int dstWidth,void * dstRow)109 do_span_rgba_unorm8(enum pipe_format format, int srcWidth,
110 const void *srcRowA, const void *srcRowB,
111 int dstWidth, void *dstRow)
112 {
113 assert(util_format_description(format)->colorspace !=
114 UTIL_FORMAT_COLORSPACE_ZS);
115 assert(srcWidth <= MAX_SPAN_WIDTH);
116 assert(dstWidth <= MAX_SPAN_WIDTH);
117
118 const struct util_format_unpack_description *unpack =
119 util_format_unpack_description(format);
120
121 const struct util_format_pack_description *pack =
122 util_format_pack_description(format);
123
124 uint8_t rowA[MAX_SPAN_WIDTH * 4], rowB[MAX_SPAN_WIDTH * 4];
125 uint8_t result[MAX_SPAN_WIDTH * 4];
126
127 unpack->unpack_rgba_8unorm(rowA, srcRowA, srcWidth);
128 unpack->unpack_rgba_8unorm(rowB, srcRowB, srcWidth);
129
130 if (srcWidth == dstWidth) {
131 for (unsigned i = 0; i < dstWidth; ++i) {
132 int idx = i * 4;
133 for (unsigned c = 0; c < 4; ++c)
134 result[idx + c] = (rowA[idx + c] + rowB[idx + c]) / 2;
135 }
136 } else {
137 for (unsigned i = 0; i < dstWidth; ++i) {
138 int idx = i * 2 * 4;
139 for (unsigned c = 0; c < 4; ++c) {
140 result[i * 4 + c] = (rowA[idx + c] + rowA[idx + 4 + c] +
141 rowB[idx + c] + rowB[idx + 4 + c]) / 4;
142 }
143 }
144 }
145
146 pack->pack_rgba_8unorm(dstRow, 0, result, 0, dstWidth, 1);
147 }
148
149 static void
do_span_rgba_float(enum pipe_format format,int srcWidth,const void * srcRowA,const void * srcRowB,int dstWidth,void * dstRow)150 do_span_rgba_float(enum pipe_format format, int srcWidth,
151 const void *srcRowA, const void *srcRowB,
152 int dstWidth, void *dstRow)
153 {
154 assert(util_format_description(format)->colorspace !=
155 UTIL_FORMAT_COLORSPACE_ZS);
156 assert(srcWidth <= MAX_SPAN_WIDTH);
157 assert(dstWidth <= MAX_SPAN_WIDTH);
158
159 float rowA[MAX_SPAN_WIDTH][4], rowB[MAX_SPAN_WIDTH][4];
160 float result[MAX_SPAN_WIDTH][4];
161 util_format_unpack_rgba(format, rowA, srcRowA, srcWidth);
162 util_format_unpack_rgba(format, rowB, srcRowB, srcWidth);
163
164 if (srcWidth == dstWidth) {
165 for (unsigned i = 0; i < dstWidth; ++i) {
166 for (unsigned c = 0; c < 4; ++c)
167 result[i][c] = (rowA[i][c] + rowB[i][c]) / 2;
168 }
169 } else {
170 for (unsigned i = 0; i < dstWidth; ++i) {
171 int idx = i * 2;
172 for (unsigned c = 0; c < 4; ++c)
173 result[i][c] = (rowA[idx][c] + rowA[idx + 1][c] +
174 rowB[idx][c] + rowB[idx + 1][c]) / 4;
175 }
176 }
177
178 util_format_pack_rgba(format, dstRow, result, dstWidth);
179 }
180
181 /**
182 * Average together two spans of a source image to produce a single
183 * new span in the dest image. The difference between a row and a span
184 * is that a span is limited to MAX_SPAN_WIDTH pixels, which means
185 * that they can be processed with stack-allocated immediate buffers.
186 * The dest width must be equal to either the source width or half the
187 * source width.
188 */
189
190 static void
do_span(enum pipe_format format,int srcWidth,const void * srcRowA,const void * srcRowB,int dstWidth,void * dstRow)191 do_span(enum pipe_format format, int srcWidth,
192 const void *srcRowA, const void *srcRowB,
193 int dstWidth, void *dstRow)
194 {
195 assert(dstWidth == srcWidth || dstWidth == srcWidth / 2);
196 const struct util_format_description *desc =
197 util_format_description(format);
198
199 if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS)
200 do_span_zs(format, srcWidth, srcRowA, srcRowB, dstWidth, dstRow);
201 else if (util_format_fits_8unorm(desc))
202 do_span_rgba_unorm8(format, srcWidth, srcRowA, srcRowB, dstWidth,
203 dstRow);
204 else
205 do_span_rgba_float(format, srcWidth, srcRowA, srcRowB, dstWidth,
206 dstRow);
207 }
208
209 static void
do_span_3D(enum pipe_format format,int srcWidth,const void * srcRowA,const void * srcRowB,const void * srcRowC,const void * srcRowD,int dstWidth,void * dstRow)210 do_span_3D(enum pipe_format format, int srcWidth,
211 const void *srcRowA, const void *srcRowB,
212 const void *srcRowC, const void *srcRowD,
213 int dstWidth, void *dstRow)
214 {
215 uint32_t tmp1[MAX_SPAN_WIDTH * 4], tmp2[MAX_SPAN_WIDTH * 4];
216 do_span(format, srcWidth, srcRowA, srcRowB, dstWidth, tmp1);
217 do_span(format, srcWidth, srcRowC, srcRowD, dstWidth, tmp2);
218 do_span(format, dstWidth, tmp1, tmp2, dstWidth, dstRow);
219 }
220
221 /**
222 * Average together two rows of a source image to produce a single new
223 * row in the dest image. It's legal for the two source rows to point
224 * to the same data. The dest width must be equal to the largest of
225 * half the source width or one.
226 */
227 static void
do_row(enum pipe_format format,int srcWidth,const uint8_t * srcRowA,const uint8_t * srcRowB,int dstWidth,uint8_t * dstRow)228 do_row(enum pipe_format format, int srcWidth,
229 const uint8_t *srcRowA, const uint8_t *srcRowB,
230 int dstWidth, uint8_t *dstRow)
231 {
232 assert(dstWidth == MAX2(srcWidth / 2, 1));
233 assert(srcWidth > 0 && dstWidth > 0);
234
235 do {
236 unsigned blocksize = util_format_get_blocksize(format);
237 int w = MIN2(srcWidth, MAX_SPAN_WIDTH);
238 do_span(format, w, srcRowA, srcRowB, MAX2(w / 2, 1), dstRow);
239 srcWidth -= MAX_SPAN_WIDTH;
240 srcRowA += MAX_SPAN_WIDTH * blocksize;
241 srcRowB += MAX_SPAN_WIDTH * blocksize;
242 dstWidth -= MAX_SPAN_WIDTH / 2;
243 dstRow += (MAX_SPAN_WIDTH / 2) * blocksize;
244 } while (dstWidth > 0);
245 }
246
247 /**
248 * Average together four rows of a source image to produce a single new
249 * row in the dest image. It's legal for the two source rows to point
250 * to the same data. The source width must be equal to either the
251 * dest width or one.
252 *
253 * \param srcWidth Width of a row in the source data
254 * \param srcRowA Pointer to one of the rows of source data
255 * \param srcRowB Pointer to one of the rows of source data
256 * \param srcRowC Pointer to one of the rows of source data
257 * \param srcRowD Pointer to one of the rows of source data
258 * \param dstWidth Width of a row in the destination data
259 * \param srcRowA Pointer to the row of destination data
260 */
261 static void
do_row_3D(enum pipe_format format,int srcWidth,const uint8_t * srcRowA,const uint8_t * srcRowB,const uint8_t * srcRowC,const uint8_t * srcRowD,int dstWidth,uint8_t * dstRow)262 do_row_3D(enum pipe_format format, int srcWidth,
263 const uint8_t *srcRowA, const uint8_t *srcRowB,
264 const uint8_t *srcRowC, const uint8_t *srcRowD,
265 int dstWidth, uint8_t *dstRow)
266 {
267 assert(dstWidth == MAX2(srcWidth / 2, 1));
268 assert(srcWidth > 0 && dstWidth > 0);
269
270 do {
271 unsigned blocksize = util_format_get_blocksize(format);
272 int w = MIN2(srcWidth, MAX_SPAN_WIDTH);
273 do_span_3D(format, w, srcRowA, srcRowB, srcRowC, srcRowD, MAX2(w / 2, 1),
274 dstRow);
275 srcWidth -= MAX_SPAN_WIDTH;
276 srcRowA += MAX_SPAN_WIDTH * blocksize;
277 srcRowB += MAX_SPAN_WIDTH * blocksize;
278 dstWidth -= MAX_SPAN_WIDTH / 2;
279 dstRow += (MAX_SPAN_WIDTH / 2) * blocksize;
280 } while (dstWidth > 0);
281 }
282
283
284 /*
285 * These functions generate a 1/2-size mipmap image from a source image.
286 * Texture borders are handled by copying or averaging the source image's
287 * border texels, depending on the scale-down factor.
288 */
289
290 static void
make_1d_mipmap(enum pipe_format format,GLint border,GLint srcWidth,const GLubyte * srcPtr,GLint dstWidth,GLubyte * dstPtr)291 make_1d_mipmap(enum pipe_format format, GLint border,
292 GLint srcWidth, const GLubyte *srcPtr,
293 GLint dstWidth, GLubyte *dstPtr)
294 {
295 const GLint bpt = util_format_get_blocksize(format);
296 const GLubyte *src;
297 GLubyte *dst;
298
299 /* skip the border pixel, if any */
300 src = srcPtr + border * bpt;
301 dst = dstPtr + border * bpt;
302
303 /* we just duplicate the input row, kind of hack, saves code */
304 do_row(format, srcWidth - 2 * border, src, src,
305 dstWidth - 2 * border, dst);
306
307 if (border) {
308 /* copy left-most pixel from source */
309 assert(dstPtr);
310 assert(srcPtr);
311 memcpy(dstPtr, srcPtr, bpt);
312 /* copy right-most pixel from source */
313 memcpy(dstPtr + (dstWidth - 1) * bpt,
314 srcPtr + (srcWidth - 1) * bpt,
315 bpt);
316 }
317 }
318
319
320 static void
make_2d_mipmap(enum pipe_format format,GLint border,GLint srcWidth,GLint srcHeight,const GLubyte * srcPtr,GLint srcRowStride,GLint dstWidth,GLint dstHeight,GLubyte * dstPtr,GLint dstRowStride)321 make_2d_mipmap(enum pipe_format format, GLint border,
322 GLint srcWidth, GLint srcHeight,
323 const GLubyte *srcPtr, GLint srcRowStride,
324 GLint dstWidth, GLint dstHeight,
325 GLubyte *dstPtr, GLint dstRowStride)
326 {
327 const GLint bpt = util_format_get_blocksize(format);
328 const GLint srcWidthNB = srcWidth - 2 * border; /* sizes w/out border */
329 const GLint dstWidthNB = dstWidth - 2 * border;
330 const GLint dstHeightNB = dstHeight - 2 * border;
331 const GLubyte *srcA, *srcB;
332 GLubyte *dst;
333 GLint row, srcRowStep;
334
335 /* Compute src and dst pointers, skipping any border */
336 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
337 if (srcHeight > 1 && srcHeight > dstHeight) {
338 /* sample from two source rows */
339 srcB = srcA + srcRowStride;
340 srcRowStep = 2;
341 }
342 else {
343 /* sample from one source row */
344 srcB = srcA;
345 srcRowStep = 1;
346 }
347
348 dst = dstPtr + border * ((dstWidth + 1) * bpt);
349
350 for (row = 0; row < dstHeightNB; row++) {
351 do_row(format, srcWidthNB, srcA, srcB,
352 dstWidthNB, dst);
353 srcA += srcRowStep * srcRowStride;
354 srcB += srcRowStep * srcRowStride;
355 dst += dstRowStride;
356 }
357
358 /* This is ugly but probably won't be used much */
359 if (border > 0) {
360 /* fill in dest border */
361 /* lower-left border pixel */
362 assert(dstPtr);
363 assert(srcPtr);
364 memcpy(dstPtr, srcPtr, bpt);
365 /* lower-right border pixel */
366 memcpy(dstPtr + (dstWidth - 1) * bpt,
367 srcPtr + (srcWidth - 1) * bpt, bpt);
368 /* upper-left border pixel */
369 memcpy(dstPtr + dstWidth * (dstHeight - 1) * bpt,
370 srcPtr + srcWidth * (srcHeight - 1) * bpt, bpt);
371 /* upper-right border pixel */
372 memcpy(dstPtr + (dstWidth * dstHeight - 1) * bpt,
373 srcPtr + (srcWidth * srcHeight - 1) * bpt, bpt);
374 /* lower border */
375 do_row(format, srcWidthNB,
376 srcPtr + bpt,
377 srcPtr + bpt,
378 dstWidthNB, dstPtr + bpt);
379 /* upper border */
380 do_row(format, srcWidthNB,
381 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
382 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
383 dstWidthNB,
384 dstPtr + (dstWidth * (dstHeight - 1) + 1) * bpt);
385 /* left and right borders */
386 if (srcHeight == dstHeight) {
387 /* copy border pixel from src to dst */
388 for (row = 1; row < srcHeight; row++) {
389 memcpy(dstPtr + dstWidth * row * bpt,
390 srcPtr + srcWidth * row * bpt, bpt);
391 memcpy(dstPtr + (dstWidth * row + dstWidth - 1) * bpt,
392 srcPtr + (srcWidth * row + srcWidth - 1) * bpt, bpt);
393 }
394 }
395 else {
396 /* average two src pixels each dest pixel */
397 for (row = 0; row < dstHeightNB; row += 2) {
398 do_row(format, 1,
399 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
400 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
401 1, dstPtr + (dstWidth * row + 1) * bpt);
402 do_row(format, 1,
403 srcPtr + (srcWidth * (row * 2 + 1) + srcWidth - 1) * bpt,
404 srcPtr + (srcWidth * (row * 2 + 2) + srcWidth - 1) * bpt,
405 1, dstPtr + (dstWidth * row + 1 + dstWidth - 1) * bpt);
406 }
407 }
408 }
409 }
410
411
412 static void
make_3d_mipmap(enum pipe_format format,GLint border,GLint srcWidth,GLint srcHeight,GLint srcDepth,const GLubyte ** srcPtr,GLint srcRowStride,GLint dstWidth,GLint dstHeight,GLint dstDepth,GLubyte ** dstPtr,GLint dstRowStride)413 make_3d_mipmap(enum pipe_format format, GLint border,
414 GLint srcWidth, GLint srcHeight, GLint srcDepth,
415 const GLubyte **srcPtr, GLint srcRowStride,
416 GLint dstWidth, GLint dstHeight, GLint dstDepth,
417 GLubyte **dstPtr, GLint dstRowStride)
418 {
419 const GLint bpt = util_format_get_blocksize(format);
420 const GLint srcWidthNB = srcWidth - 2 * border; /* sizes w/out border */
421 const GLint srcDepthNB = srcDepth - 2 * border;
422 const GLint dstWidthNB = dstWidth - 2 * border;
423 const GLint dstHeightNB = dstHeight - 2 * border;
424 const GLint dstDepthNB = dstDepth - 2 * border;
425 GLint img, row;
426 GLint bytesPerSrcImage, bytesPerDstImage;
427 GLint srcImageOffset, srcRowOffset;
428
429 (void) srcDepthNB; /* silence warnings */
430
431 bytesPerSrcImage = srcRowStride * srcHeight * bpt;
432 bytesPerDstImage = dstRowStride * dstHeight * bpt;
433
434 /* Offset between adjacent src images to be averaged together */
435 srcImageOffset = (srcDepth == dstDepth) ? 0 : 1;
436
437 /* Offset between adjacent src rows to be averaged together */
438 srcRowOffset = (srcHeight == dstHeight) ? 0 : srcRowStride;
439
440 /*
441 * Need to average together up to 8 src pixels for each dest pixel.
442 * Break that down into 3 operations:
443 * 1. take two rows from source image and average them together.
444 * 2. take two rows from next source image and average them together.
445 * 3. take the two averaged rows and average them for the final dst row.
446 */
447
448 /*
449 printf("mip3d %d x %d x %d -> %d x %d x %d\n",
450 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
451 */
452
453 for (img = 0; img < dstDepthNB; img++) {
454 /* first source image pointer, skipping border */
455 const GLubyte *imgSrcA = srcPtr[img * 2 + border]
456 + srcRowStride * border + bpt * border;
457 /* second source image pointer, skipping border */
458 const GLubyte *imgSrcB = srcPtr[img * 2 + srcImageOffset + border]
459 + srcRowStride * border + bpt * border;
460
461 /* address of the dest image, skipping border */
462 GLubyte *imgDst = dstPtr[img + border]
463 + dstRowStride * border + bpt * border;
464
465 /* setup the four source row pointers and the dest row pointer */
466 const GLubyte *srcImgARowA = imgSrcA;
467 const GLubyte *srcImgARowB = imgSrcA + srcRowOffset;
468 const GLubyte *srcImgBRowA = imgSrcB;
469 const GLubyte *srcImgBRowB = imgSrcB + srcRowOffset;
470 GLubyte *dstImgRow = imgDst;
471
472 for (row = 0; row < dstHeightNB; row++) {
473 do_row_3D(format, srcWidthNB,
474 srcImgARowA, srcImgARowB,
475 srcImgBRowA, srcImgBRowB,
476 dstWidthNB, dstImgRow);
477
478 /* advance to next rows */
479 srcImgARowA += srcRowStride + srcRowOffset;
480 srcImgARowB += srcRowStride + srcRowOffset;
481 srcImgBRowA += srcRowStride + srcRowOffset;
482 srcImgBRowB += srcRowStride + srcRowOffset;
483 dstImgRow += dstRowStride;
484 }
485 }
486
487
488 /* Luckily we can leverage the make_2d_mipmap() function here! */
489 if (border > 0) {
490 /* do front border image */
491 make_2d_mipmap(format, 1,
492 srcWidth, srcHeight, srcPtr[0], srcRowStride,
493 dstWidth, dstHeight, dstPtr[0], dstRowStride);
494 /* do back border image */
495 make_2d_mipmap(format, 1,
496 srcWidth, srcHeight, srcPtr[srcDepth - 1], srcRowStride,
497 dstWidth, dstHeight, dstPtr[dstDepth - 1], dstRowStride);
498
499 /* do four remaining border edges that span the image slices */
500 if (srcDepth == dstDepth) {
501 /* just copy border pixels from src to dst */
502 for (img = 0; img < dstDepthNB; img++) {
503 const GLubyte *src;
504 GLubyte *dst;
505
506 /* do border along [img][row=0][col=0] */
507 src = srcPtr[img * 2];
508 dst = dstPtr[img];
509 memcpy(dst, src, bpt);
510
511 /* do border along [img][row=dstHeight-1][col=0] */
512 src = srcPtr[img * 2] + (srcHeight - 1) * srcRowStride;
513 dst = dstPtr[img] + (dstHeight - 1) * dstRowStride;
514 memcpy(dst, src, bpt);
515
516 /* do border along [img][row=0][col=dstWidth-1] */
517 src = srcPtr[img * 2] + (srcWidth - 1) * bpt;
518 dst = dstPtr[img] + (dstWidth - 1) * bpt;
519 memcpy(dst, src, bpt);
520
521 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
522 src = srcPtr[img * 2] + (bytesPerSrcImage - bpt);
523 dst = dstPtr[img] + (bytesPerDstImage - bpt);
524 memcpy(dst, src, bpt);
525 }
526 }
527 else {
528 /* average border pixels from adjacent src image pairs */
529 assert(srcDepthNB == 2 * dstDepthNB);
530 for (img = 0; img < dstDepthNB; img++) {
531 const GLubyte *srcA, *srcB;
532 GLubyte *dst;
533
534 /* do border along [img][row=0][col=0] */
535 srcA = srcPtr[img * 2 + 0];
536 srcB = srcPtr[img * 2 + srcImageOffset];
537 dst = dstPtr[img];
538 do_row(format, 1, srcA, srcB, 1, dst);
539
540 /* do border along [img][row=dstHeight-1][col=0] */
541 srcA = srcPtr[img * 2 + 0]
542 + (srcHeight - 1) * srcRowStride;
543 srcB = srcPtr[img * 2 + srcImageOffset]
544 + (srcHeight - 1) * srcRowStride;
545 dst = dstPtr[img] + (dstHeight - 1) * dstRowStride;
546 do_row(format, 1, srcA, srcB, 1, dst);
547
548 /* do border along [img][row=0][col=dstWidth-1] */
549 srcA = srcPtr[img * 2 + 0] + (srcWidth - 1) * bpt;
550 srcB = srcPtr[img * 2 + srcImageOffset] + (srcWidth - 1) * bpt;
551 dst = dstPtr[img] + (dstWidth - 1) * bpt;
552 do_row(format, 1, srcA, srcB, 1, dst);
553
554 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
555 srcA = srcPtr[img * 2 + 0] + (bytesPerSrcImage - bpt);
556 srcB = srcPtr[img * 2 + srcImageOffset] + (bytesPerSrcImage - bpt);
557 dst = dstPtr[img] + (bytesPerDstImage - bpt);
558 do_row(format, 1, srcA, srcB, 1, dst);
559 }
560 }
561 }
562 }
563
564
565 /**
566 * Down-sample a texture image to produce the next lower mipmap level.
567 * \param comps components per texel (1, 2, 3 or 4)
568 * \param srcData array[slice] of pointers to source image slices
569 * \param dstData array[slice] of pointers to dest image slices
570 * \param srcRowStride stride between source rows, in bytes
571 * \param dstRowStride stride between destination rows, in bytes
572 */
573 static void
_mesa_generate_mipmap_level(GLenum target,enum pipe_format format,GLint border,GLint srcWidth,GLint srcHeight,GLint srcDepth,const GLubyte ** srcData,GLint srcRowStride,GLint dstWidth,GLint dstHeight,GLint dstDepth,GLubyte ** dstData,GLint dstRowStride)574 _mesa_generate_mipmap_level(GLenum target,
575 enum pipe_format format,
576 GLint border,
577 GLint srcWidth, GLint srcHeight, GLint srcDepth,
578 const GLubyte **srcData,
579 GLint srcRowStride,
580 GLint dstWidth, GLint dstHeight, GLint dstDepth,
581 GLubyte **dstData,
582 GLint dstRowStride)
583 {
584 int i;
585
586 switch (target) {
587 case GL_TEXTURE_1D:
588 make_1d_mipmap(format, border,
589 srcWidth, srcData[0],
590 dstWidth, dstData[0]);
591 break;
592 case GL_TEXTURE_2D:
593 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
594 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
595 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
596 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
597 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
598 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
599 make_2d_mipmap(format, border,
600 srcWidth, srcHeight, srcData[0], srcRowStride,
601 dstWidth, dstHeight, dstData[0], dstRowStride);
602 break;
603 case GL_TEXTURE_3D:
604 make_3d_mipmap(format, border,
605 srcWidth, srcHeight, srcDepth,
606 srcData, srcRowStride,
607 dstWidth, dstHeight, dstDepth,
608 dstData, dstRowStride);
609 break;
610 case GL_TEXTURE_1D_ARRAY_EXT:
611 assert(srcHeight == 1);
612 assert(dstHeight == 1);
613 for (i = 0; i < dstDepth; i++) {
614 make_1d_mipmap(format, border,
615 srcWidth, srcData[i],
616 dstWidth, dstData[i]);
617 }
618 break;
619 case GL_TEXTURE_2D_ARRAY_EXT:
620 case GL_TEXTURE_CUBE_MAP_ARRAY:
621 for (i = 0; i < dstDepth; i++) {
622 make_2d_mipmap(format, border,
623 srcWidth, srcHeight, srcData[i], srcRowStride,
624 dstWidth, dstHeight, dstData[i], dstRowStride);
625 }
626 break;
627 case GL_TEXTURE_RECTANGLE_NV:
628 case GL_TEXTURE_EXTERNAL_OES:
629 /* no mipmaps, do nothing */
630 break;
631 default:
632 unreachable("bad tex target in _mesa_generate_mipmaps");
633 }
634 }
635
636
637 /**
638 * compute next (level+1) image size
639 * \return GL_FALSE if no smaller size can be generated (eg. src is 1x1x1 size)
640 */
641 GLboolean
_mesa_next_mipmap_level_size(GLenum target,GLint border,GLint srcWidth,GLint srcHeight,GLint srcDepth,GLint * dstWidth,GLint * dstHeight,GLint * dstDepth)642 _mesa_next_mipmap_level_size(GLenum target, GLint border,
643 GLint srcWidth, GLint srcHeight, GLint srcDepth,
644 GLint *dstWidth, GLint *dstHeight, GLint *dstDepth)
645 {
646 if (srcWidth - 2 * border > 1) {
647 *dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
648 }
649 else {
650 *dstWidth = srcWidth; /* can't go smaller */
651 }
652
653 if ((srcHeight - 2 * border > 1) &&
654 target != GL_TEXTURE_1D_ARRAY_EXT &&
655 target != GL_PROXY_TEXTURE_1D_ARRAY_EXT) {
656 *dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
657 }
658 else {
659 *dstHeight = srcHeight; /* can't go smaller */
660 }
661
662 if ((srcDepth - 2 * border > 1) &&
663 target != GL_TEXTURE_2D_ARRAY_EXT &&
664 target != GL_PROXY_TEXTURE_2D_ARRAY_EXT &&
665 target != GL_TEXTURE_CUBE_MAP_ARRAY &&
666 target != GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) {
667 *dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
668 }
669 else {
670 *dstDepth = srcDepth; /* can't go smaller */
671 }
672
673 if (*dstWidth == srcWidth &&
674 *dstHeight == srcHeight &&
675 *dstDepth == srcDepth) {
676 return GL_FALSE;
677 }
678 else {
679 return GL_TRUE;
680 }
681 }
682
683
684 /**
685 * Helper function for mipmap generation.
686 * Make sure the specified destination mipmap level is the right size/format
687 * for mipmap generation. If not, (re) allocate it.
688 * \return GL_TRUE if successful, GL_FALSE if mipmap generation should stop
689 */
690 static GLboolean
prepare_mipmap_level(struct gl_context * ctx,struct gl_texture_object * texObj,GLuint level,GLsizei width,GLsizei height,GLsizei depth,GLsizei border,GLenum intFormat,mesa_format format)691 prepare_mipmap_level(struct gl_context *ctx,
692 struct gl_texture_object *texObj, GLuint level,
693 GLsizei width, GLsizei height, GLsizei depth,
694 GLsizei border, GLenum intFormat, mesa_format format)
695 {
696 const GLuint numFaces = _mesa_num_tex_faces(texObj->Target);
697 GLuint face;
698
699 if (texObj->Immutable) {
700 /* The texture was created with glTexStorage() so the number/size of
701 * mipmap levels is fixed and the storage for all images is already
702 * allocated.
703 */
704 if (!texObj->Image[0][level]) {
705 /* No more levels to create - we're done */
706 return GL_FALSE;
707 }
708 else {
709 /* Nothing to do - the texture memory must have already been
710 * allocated to the right size so we're all set.
711 */
712 return GL_TRUE;
713 }
714 }
715
716 for (face = 0; face < numFaces; face++) {
717 struct gl_texture_image *dstImage;
718 const GLenum target = _mesa_cube_face_target(texObj->Target, face);
719
720 dstImage = _mesa_get_tex_image(ctx, texObj, target, level);
721 if (!dstImage) {
722 /* out of memory */
723 return GL_FALSE;
724 }
725
726 if (dstImage->Width != width ||
727 dstImage->Height != height ||
728 dstImage->Depth != depth ||
729 dstImage->Border != border ||
730 dstImage->InternalFormat != intFormat ||
731 dstImage->TexFormat != format) {
732 /* need to (re)allocate image */
733 st_FreeTextureImageBuffer(ctx, dstImage);
734
735 _mesa_init_teximage_fields(ctx, dstImage,
736 width, height, depth,
737 border, intFormat, format);
738
739 st_AllocTextureImageBuffer(ctx, dstImage);
740
741 /* in case the mipmap level is part of an FBO: */
742 _mesa_update_fbo_texture(ctx, texObj, face, level);
743
744 ctx->NewState |= _NEW_TEXTURE_OBJECT;
745 ctx->PopAttribState |= GL_TEXTURE_BIT;
746 }
747 }
748
749 return GL_TRUE;
750 }
751
752
753 /**
754 * Prepare all mipmap levels beyond 'baseLevel' for mipmap generation.
755 * When finished, all the gl_texture_image structures for the smaller
756 * mipmap levels will be consistent with the base level (in terms of
757 * dimensions, format, etc).
758 */
759 void
_mesa_prepare_mipmap_levels(struct gl_context * ctx,struct gl_texture_object * texObj,unsigned baseLevel,unsigned maxLevel)760 _mesa_prepare_mipmap_levels(struct gl_context *ctx,
761 struct gl_texture_object *texObj,
762 unsigned baseLevel, unsigned maxLevel)
763 {
764 const struct gl_texture_image *baseImage =
765 _mesa_select_tex_image(texObj, texObj->Target, baseLevel);
766
767 if (baseImage == NULL)
768 return;
769
770 const GLint border = 0;
771 GLint width = baseImage->Width;
772 GLint height = baseImage->Height;
773 GLint depth = baseImage->Depth;
774 const GLenum intFormat = baseImage->InternalFormat;
775 const mesa_format texFormat = baseImage->TexFormat;
776 GLint newWidth, newHeight, newDepth;
777
778 /* Prepare baseLevel + 1, baseLevel + 2, ... */
779 for (unsigned level = baseLevel + 1; level <= maxLevel; level++) {
780 if (!_mesa_next_mipmap_level_size(texObj->Target, border,
781 width, height, depth,
782 &newWidth, &newHeight, &newDepth)) {
783 /* all done */
784 break;
785 }
786
787 if (!prepare_mipmap_level(ctx, texObj, level,
788 newWidth, newHeight, newDepth,
789 border, intFormat, texFormat)) {
790 break;
791 }
792
793 width = newWidth;
794 height = newHeight;
795 depth = newDepth;
796 }
797 }
798
799
800 static void
generate_mipmap_uncompressed(struct gl_context * ctx,GLenum target,struct gl_texture_object * texObj,const struct gl_texture_image * srcImage,GLuint maxLevel)801 generate_mipmap_uncompressed(struct gl_context *ctx, GLenum target,
802 struct gl_texture_object *texObj,
803 const struct gl_texture_image *srcImage,
804 GLuint maxLevel)
805 {
806 GLuint level;
807
808 for (level = texObj->Attrib.BaseLevel; level < maxLevel; level++) {
809 /* generate image[level+1] from image[level] */
810 struct gl_texture_image *srcImage, *dstImage;
811 GLint srcRowStride, dstRowStride;
812 GLint srcWidth, srcHeight, srcDepth;
813 GLint dstWidth, dstHeight, dstDepth;
814 GLint border;
815 GLint slice;
816 GLubyte **srcMaps, **dstMaps;
817 GLboolean success = GL_TRUE;
818
819 /* get src image parameters */
820 srcImage = _mesa_select_tex_image(texObj, target, level);
821 assert(srcImage);
822 srcWidth = srcImage->Width;
823 srcHeight = srcImage->Height;
824 srcDepth = srcImage->Depth;
825 border = srcImage->Border;
826
827 /* get dest gl_texture_image */
828 dstImage = _mesa_select_tex_image(texObj, target, level + 1);
829 if (!dstImage) {
830 break;
831 }
832 dstWidth = dstImage->Width;
833 dstHeight = dstImage->Height;
834 dstDepth = dstImage->Depth;
835
836 if (target == GL_TEXTURE_1D_ARRAY) {
837 srcDepth = srcHeight;
838 dstDepth = dstHeight;
839 srcHeight = 1;
840 dstHeight = 1;
841 }
842
843 /* Map src texture image slices */
844 srcMaps = calloc(srcDepth, sizeof(GLubyte *));
845 if (srcMaps) {
846 for (slice = 0; slice < srcDepth; slice++) {
847 st_MapTextureImage(ctx, srcImage, slice,
848 0, 0, srcWidth, srcHeight,
849 GL_MAP_READ_BIT,
850 &srcMaps[slice], &srcRowStride);
851 if (!srcMaps[slice]) {
852 success = GL_FALSE;
853 break;
854 }
855 }
856 }
857 else {
858 success = GL_FALSE;
859 }
860
861 /* Map dst texture image slices */
862 dstMaps = calloc(dstDepth, sizeof(GLubyte *));
863 if (dstMaps) {
864 for (slice = 0; slice < dstDepth; slice++) {
865 st_MapTextureImage(ctx, dstImage, slice,
866 0, 0, dstWidth, dstHeight,
867 GL_MAP_WRITE_BIT,
868 &dstMaps[slice], &dstRowStride);
869 if (!dstMaps[slice]) {
870 success = GL_FALSE;
871 break;
872 }
873 }
874 }
875 else {
876 success = GL_FALSE;
877 }
878
879 if (success) {
880 /* generate one mipmap level (for 1D/2D/3D/array/etc texture) */
881 _mesa_generate_mipmap_level(target, srcImage->TexFormat, border,
882 srcWidth, srcHeight, srcDepth,
883 (const GLubyte **) srcMaps, srcRowStride,
884 dstWidth, dstHeight, dstDepth,
885 dstMaps, dstRowStride);
886 }
887
888 /* Unmap src image slices */
889 if (srcMaps) {
890 for (slice = 0; slice < srcDepth; slice++) {
891 if (srcMaps[slice]) {
892 st_UnmapTextureImage(ctx, srcImage, slice);
893 }
894 }
895 free(srcMaps);
896 }
897
898 /* Unmap dst image slices */
899 if (dstMaps) {
900 for (slice = 0; slice < dstDepth; slice++) {
901 if (dstMaps[slice]) {
902 st_UnmapTextureImage(ctx, dstImage, slice);
903 }
904 }
905 free(dstMaps);
906 }
907
908 if (!success) {
909 _mesa_error(ctx, GL_OUT_OF_MEMORY, "mipmap generation");
910 break;
911 }
912 } /* loop over mipmap levels */
913 }
914
915
916 static void
generate_mipmap_compressed(struct gl_context * ctx,GLenum target,struct gl_texture_object * texObj,struct gl_texture_image * srcImage,GLuint maxLevel)917 generate_mipmap_compressed(struct gl_context *ctx, GLenum target,
918 struct gl_texture_object *texObj,
919 struct gl_texture_image *srcImage,
920 GLuint maxLevel)
921 {
922 GLuint level;
923 mesa_format temp_format;
924 GLuint temp_src_row_stride, temp_src_img_stride; /* in bytes */
925 GLubyte *temp_src = NULL, *temp_dst = NULL;
926 GLenum temp_datatype;
927 GLenum temp_base_format;
928 GLubyte **temp_src_slices = NULL, **temp_dst_slices = NULL;
929
930 /* only two types of compressed textures at this time */
931 assert(texObj->Target == GL_TEXTURE_2D ||
932 texObj->Target == GL_TEXTURE_2D_ARRAY ||
933 texObj->Target == GL_TEXTURE_CUBE_MAP ||
934 texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY);
935
936 /*
937 * Choose a format for the temporary, uncompressed base image.
938 * Then, get number of components, choose temporary image datatype,
939 * and get base format.
940 */
941 temp_format = _mesa_get_uncompressed_format(srcImage->TexFormat);
942
943 switch (_mesa_get_format_datatype(srcImage->TexFormat)) {
944 case GL_FLOAT:
945 temp_datatype = GL_FLOAT;
946 break;
947 case GL_SIGNED_NORMALIZED:
948 /* Revisit this if we get compressed formats with >8 bits per component */
949 temp_datatype = GL_BYTE;
950 break;
951 default:
952 temp_datatype = GL_UNSIGNED_BYTE;
953 }
954
955 temp_base_format = _mesa_get_format_base_format(temp_format);
956
957
958 /* allocate storage for the temporary, uncompressed image */
959 temp_src_row_stride = _mesa_format_row_stride(temp_format, srcImage->Width);
960 temp_src_img_stride = _mesa_format_image_size(temp_format, srcImage->Width,
961 srcImage->Height, 1);
962 temp_src = malloc(temp_src_img_stride * srcImage->Depth);
963
964 /* Allocate storage for arrays of slice pointers */
965 temp_src_slices = malloc(srcImage->Depth * sizeof(GLubyte *));
966 temp_dst_slices = malloc(srcImage->Depth * sizeof(GLubyte *));
967
968 if (!temp_src || !temp_src_slices || !temp_dst_slices) {
969 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
970 goto end;
971 }
972
973 /* decompress base image to the temporary src buffer */
974 {
975 /* save pixel packing mode */
976 struct gl_pixelstore_attrib save = ctx->Pack;
977 /* use default/tight packing parameters */
978 ctx->Pack = ctx->DefaultPacking;
979
980 /* Get the uncompressed image */
981 assert(srcImage->Level == texObj->Attrib.BaseLevel);
982 st_GetTexSubImage(ctx,
983 0, 0, 0,
984 srcImage->Width, srcImage->Height,
985 srcImage->Depth,
986 temp_base_format, temp_datatype,
987 temp_src, srcImage);
988 /* restore packing mode */
989 ctx->Pack = save;
990 }
991
992 for (level = texObj->Attrib.BaseLevel; level < maxLevel; level++) {
993 /* generate image[level+1] from image[level] */
994 const struct gl_texture_image *srcImage;
995 struct gl_texture_image *dstImage;
996 GLint srcWidth, srcHeight, srcDepth;
997 GLint dstWidth, dstHeight, dstDepth;
998 GLint border;
999 GLuint temp_dst_row_stride, temp_dst_img_stride; /* in bytes */
1000 GLint i;
1001
1002 /* get src image parameters */
1003 srcImage = _mesa_select_tex_image(texObj, target, level);
1004 assert(srcImage);
1005 srcWidth = srcImage->Width;
1006 srcHeight = srcImage->Height;
1007 srcDepth = srcImage->Depth;
1008 border = srcImage->Border;
1009
1010 /* get dest gl_texture_image */
1011 dstImage = _mesa_select_tex_image(texObj, target, level + 1);
1012 if (!dstImage) {
1013 break;
1014 }
1015 dstWidth = dstImage->Width;
1016 dstHeight = dstImage->Height;
1017 dstDepth = dstImage->Depth;
1018
1019 /* Compute dst image strides and alloc memory on first iteration */
1020 temp_dst_row_stride = _mesa_format_row_stride(temp_format, dstWidth);
1021 temp_dst_img_stride = _mesa_format_image_size(temp_format, dstWidth,
1022 dstHeight, 1);
1023 if (!temp_dst) {
1024 temp_dst = malloc(temp_dst_img_stride * dstDepth);
1025 if (!temp_dst) {
1026 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
1027 goto end;
1028 }
1029 }
1030
1031 /* for 2D arrays, setup array[depth] of slice pointers */
1032 for (i = 0; i < srcDepth; i++) {
1033 temp_src_slices[i] = temp_src + temp_src_img_stride * i;
1034 }
1035 for (i = 0; i < dstDepth; i++) {
1036 temp_dst_slices[i] = temp_dst + temp_dst_img_stride * i;
1037 }
1038
1039 /* Rescale src image to dest image.
1040 * This will loop over the slices of a 2D array.
1041 */
1042 _mesa_generate_mipmap_level(target, temp_format, border,
1043 srcWidth, srcHeight, srcDepth,
1044 (const GLubyte **) temp_src_slices,
1045 temp_src_row_stride,
1046 dstWidth, dstHeight, dstDepth,
1047 temp_dst_slices, temp_dst_row_stride);
1048
1049 /* The image space was allocated above so use glTexSubImage now */
1050 st_TexSubImage(ctx, 2, dstImage,
1051 0, 0, 0, dstWidth, dstHeight, dstDepth,
1052 temp_base_format, temp_datatype,
1053 temp_dst, &ctx->DefaultPacking);
1054
1055 /* swap src and dest pointers */
1056 {
1057 GLubyte *temp = temp_src;
1058 temp_src = temp_dst;
1059 temp_dst = temp;
1060 temp_src_row_stride = temp_dst_row_stride;
1061 temp_src_img_stride = temp_dst_img_stride;
1062 }
1063 } /* loop over mipmap levels */
1064
1065 end:
1066 free(temp_src);
1067 free(temp_dst);
1068 free(temp_src_slices);
1069 free(temp_dst_slices);
1070 }
1071
1072 /**
1073 * Automatic mipmap generation.
1074 * This is the fallback/default function for mipmap generation.
1075 * Generate a complete set of mipmaps from texObj's BaseLevel image.
1076 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
1077 * For cube maps, target will be one of
1078 * GL_TEXTURE_CUBE_MAP_POSITIVE/NEGATIVE_X/Y/Z; never GL_TEXTURE_CUBE_MAP.
1079 */
1080 void
_mesa_generate_mipmap(struct gl_context * ctx,GLenum target,struct gl_texture_object * texObj)1081 _mesa_generate_mipmap(struct gl_context *ctx, GLenum target,
1082 struct gl_texture_object *texObj)
1083 {
1084 struct gl_texture_image *srcImage;
1085 GLint maxLevel;
1086
1087 assert(texObj);
1088 srcImage = _mesa_select_tex_image(texObj, target, texObj->Attrib.BaseLevel);
1089 assert(srcImage);
1090
1091 maxLevel = _mesa_max_texture_levels(ctx, texObj->Target) - 1;
1092 assert(maxLevel >= 0); /* bad target */
1093
1094 maxLevel = MIN2(maxLevel, texObj->Attrib.MaxLevel);
1095
1096 _mesa_prepare_mipmap_levels(ctx, texObj, texObj->Attrib.BaseLevel, maxLevel);
1097
1098 if (_mesa_is_format_compressed(srcImage->TexFormat)) {
1099 generate_mipmap_compressed(ctx, target, texObj, srcImage, maxLevel);
1100 } else {
1101 generate_mipmap_uncompressed(ctx, target, texObj, srcImage, maxLevel);
1102 }
1103 }
1104