xref: /aosp_15_r20/external/mesa3d/src/mesa/main/mipmap.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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