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