2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * \file mipmap.c mipmap generation and teximage resizing functions.
32 #include "texcompress.h"
33 #include "texformat.h"
40 bytes_per_pixel(GLenum datatype
, GLuint comps
)
42 GLint b
= _mesa_sizeof_packed_type(datatype
);
49 * Average together two rows of a source image to produce a single new
50 * row in the dest image. It's legal for the two source rows to point
51 * to the same data. The source width must be equal to either the
52 * dest width or two times the dest width.
53 * \param datatype GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
54 * \param comps number of components per pixel (1..4)
57 do_row(GLenum datatype
, GLuint comps
, GLint srcWidth
,
58 const GLvoid
*srcRowA
, const GLvoid
*srcRowB
,
59 GLint dstWidth
, GLvoid
*dstRow
)
61 const GLuint k0
= (srcWidth
== dstWidth
) ? 0 : 1;
62 const GLuint colStride
= (srcWidth
== dstWidth
) ? 1 : 2;
67 /* This assertion is no longer valid with non-power-of-2 textures
68 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
71 if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 4) {
73 const GLubyte(*rowA
)[4] = (const GLubyte(*)[4]) srcRowA
;
74 const GLubyte(*rowB
)[4] = (const GLubyte(*)[4]) srcRowB
;
75 GLubyte(*dst
)[4] = (GLubyte(*)[4]) dstRow
;
76 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
77 i
++, j
+= colStride
, k
+= colStride
) {
78 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
79 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
80 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
81 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
84 else if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 3) {
86 const GLubyte(*rowA
)[3] = (const GLubyte(*)[3]) srcRowA
;
87 const GLubyte(*rowB
)[3] = (const GLubyte(*)[3]) srcRowB
;
88 GLubyte(*dst
)[3] = (GLubyte(*)[3]) dstRow
;
89 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
90 i
++, j
+= colStride
, k
+= colStride
) {
91 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
92 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
93 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
96 else if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 2) {
98 const GLubyte(*rowA
)[2] = (const GLubyte(*)[2]) srcRowA
;
99 const GLubyte(*rowB
)[2] = (const GLubyte(*)[2]) srcRowB
;
100 GLubyte(*dst
)[2] = (GLubyte(*)[2]) dstRow
;
101 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
102 i
++, j
+= colStride
, k
+= colStride
) {
103 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) >> 2;
104 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) >> 2;
107 else if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 1) {
109 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
110 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
111 GLubyte
*dst
= (GLubyte
*) dstRow
;
112 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
113 i
++, j
+= colStride
, k
+= colStride
) {
114 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) >> 2;
118 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 4) {
120 const GLushort(*rowA
)[4] = (const GLushort(*)[4]) srcRowA
;
121 const GLushort(*rowB
)[4] = (const GLushort(*)[4]) srcRowB
;
122 GLushort(*dst
)[4] = (GLushort(*)[4]) dstRow
;
123 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
124 i
++, j
+= colStride
, k
+= colStride
) {
125 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
126 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
127 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
128 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
131 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 3) {
133 const GLushort(*rowA
)[3] = (const GLushort(*)[3]) srcRowA
;
134 const GLushort(*rowB
)[3] = (const GLushort(*)[3]) srcRowB
;
135 GLushort(*dst
)[3] = (GLushort(*)[3]) dstRow
;
136 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
137 i
++, j
+= colStride
, k
+= colStride
) {
138 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
139 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
140 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
143 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 2) {
145 const GLushort(*rowA
)[2] = (const GLushort(*)[2]) srcRowA
;
146 const GLushort(*rowB
)[2] = (const GLushort(*)[2]) srcRowB
;
147 GLushort(*dst
)[2] = (GLushort(*)[2]) dstRow
;
148 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
149 i
++, j
+= colStride
, k
+= colStride
) {
150 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
151 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
154 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 1) {
156 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
157 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
158 GLushort
*dst
= (GLushort
*) dstRow
;
159 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
160 i
++, j
+= colStride
, k
+= colStride
) {
161 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) / 4;
165 else if (datatype
== GL_FLOAT
&& comps
== 4) {
167 const GLfloat(*rowA
)[4] = (const GLfloat(*)[4]) srcRowA
;
168 const GLfloat(*rowB
)[4] = (const GLfloat(*)[4]) srcRowB
;
169 GLfloat(*dst
)[4] = (GLfloat(*)[4]) dstRow
;
170 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
171 i
++, j
+= colStride
, k
+= colStride
) {
172 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
173 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
174 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
175 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
176 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
177 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
178 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
179 rowB
[j
][3] + rowB
[k
][3]) * 0.25F
;
182 else if (datatype
== GL_FLOAT
&& comps
== 3) {
184 const GLfloat(*rowA
)[3] = (const GLfloat(*)[3]) srcRowA
;
185 const GLfloat(*rowB
)[3] = (const GLfloat(*)[3]) srcRowB
;
186 GLfloat(*dst
)[3] = (GLfloat(*)[3]) dstRow
;
187 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
188 i
++, j
+= colStride
, k
+= colStride
) {
189 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
190 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
191 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
192 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
193 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
194 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
197 else if (datatype
== GL_FLOAT
&& comps
== 2) {
199 const GLfloat(*rowA
)[2] = (const GLfloat(*)[2]) srcRowA
;
200 const GLfloat(*rowB
)[2] = (const GLfloat(*)[2]) srcRowB
;
201 GLfloat(*dst
)[2] = (GLfloat(*)[2]) dstRow
;
202 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
203 i
++, j
+= colStride
, k
+= colStride
) {
204 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
205 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
206 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
207 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
210 else if (datatype
== GL_FLOAT
&& comps
== 1) {
212 const GLfloat
*rowA
= (const GLfloat
*) srcRowA
;
213 const GLfloat
*rowB
= (const GLfloat
*) srcRowB
;
214 GLfloat
*dst
= (GLfloat
*) dstRow
;
215 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
216 i
++, j
+= colStride
, k
+= colStride
) {
217 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) * 0.25F
;
221 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 4) {
222 GLuint i
, j
, k
, comp
;
223 const GLhalfARB(*rowA
)[4] = (const GLhalfARB(*)[4]) srcRowA
;
224 const GLhalfARB(*rowB
)[4] = (const GLhalfARB(*)[4]) srcRowB
;
225 GLhalfARB(*dst
)[4] = (GLhalfARB(*)[4]) dstRow
;
226 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
227 i
++, j
+= colStride
, k
+= colStride
) {
228 for (comp
= 0; comp
< 4; comp
++) {
229 GLfloat aj
, ak
, bj
, bk
;
230 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
231 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
232 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
233 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
234 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
238 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 3) {
239 GLuint i
, j
, k
, comp
;
240 const GLhalfARB(*rowA
)[3] = (const GLhalfARB(*)[3]) srcRowA
;
241 const GLhalfARB(*rowB
)[3] = (const GLhalfARB(*)[3]) srcRowB
;
242 GLhalfARB(*dst
)[3] = (GLhalfARB(*)[3]) dstRow
;
243 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
244 i
++, j
+= colStride
, k
+= colStride
) {
245 for (comp
= 0; comp
< 3; comp
++) {
246 GLfloat aj
, ak
, bj
, bk
;
247 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
248 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
249 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
250 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
251 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
255 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 2) {
256 GLuint i
, j
, k
, comp
;
257 const GLhalfARB(*rowA
)[2] = (const GLhalfARB(*)[2]) srcRowA
;
258 const GLhalfARB(*rowB
)[2] = (const GLhalfARB(*)[2]) srcRowB
;
259 GLhalfARB(*dst
)[2] = (GLhalfARB(*)[2]) dstRow
;
260 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
261 i
++, j
+= colStride
, k
+= colStride
) {
262 for (comp
= 0; comp
< 2; comp
++) {
263 GLfloat aj
, ak
, bj
, bk
;
264 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
265 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
266 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
267 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
268 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
272 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 1) {
274 const GLhalfARB
*rowA
= (const GLhalfARB
*) srcRowA
;
275 const GLhalfARB
*rowB
= (const GLhalfARB
*) srcRowB
;
276 GLhalfARB
*dst
= (GLhalfARB
*) dstRow
;
277 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
278 i
++, j
+= colStride
, k
+= colStride
) {
279 GLfloat aj
, ak
, bj
, bk
;
280 aj
= _mesa_half_to_float(rowA
[j
]);
281 ak
= _mesa_half_to_float(rowA
[k
]);
282 bj
= _mesa_half_to_float(rowB
[j
]);
283 bk
= _mesa_half_to_float(rowB
[k
]);
284 dst
[i
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
288 else if (datatype
== GL_UNSIGNED_INT
&& comps
== 1) {
290 const GLuint
*rowA
= (const GLuint
*) srcRowA
;
291 const GLuint
*rowB
= (const GLuint
*) srcRowB
;
292 GLfloat
*dst
= (GLfloat
*) dstRow
;
293 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
294 i
++, j
+= colStride
, k
+= colStride
) {
295 dst
[i
] = (GLfloat
)(rowA
[j
] / 4 + rowA
[k
] / 4 + rowB
[j
] / 4 + rowB
[k
] / 4);
299 else if (datatype
== GL_UNSIGNED_SHORT_5_6_5
&& comps
== 3) {
301 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
302 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
303 GLushort
*dst
= (GLushort
*) dstRow
;
304 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
305 i
++, j
+= colStride
, k
+= colStride
) {
306 const GLint rowAr0
= rowA
[j
] & 0x1f;
307 const GLint rowAr1
= rowA
[k
] & 0x1f;
308 const GLint rowBr0
= rowB
[j
] & 0x1f;
309 const GLint rowBr1
= rowB
[k
] & 0x1f;
310 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x3f;
311 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x3f;
312 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x3f;
313 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x3f;
314 const GLint rowAb0
= (rowA
[j
] >> 11) & 0x1f;
315 const GLint rowAb1
= (rowA
[k
] >> 11) & 0x1f;
316 const GLint rowBb0
= (rowB
[j
] >> 11) & 0x1f;
317 const GLint rowBb1
= (rowB
[k
] >> 11) & 0x1f;
318 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
319 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
320 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
321 dst
[i
] = (blue
<< 11) | (green
<< 5) | red
;
324 else if (datatype
== GL_UNSIGNED_SHORT_4_4_4_4
&& comps
== 4) {
326 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
327 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
328 GLushort
*dst
= (GLushort
*) dstRow
;
329 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
330 i
++, j
+= colStride
, k
+= colStride
) {
331 const GLint rowAr0
= rowA
[j
] & 0xf;
332 const GLint rowAr1
= rowA
[k
] & 0xf;
333 const GLint rowBr0
= rowB
[j
] & 0xf;
334 const GLint rowBr1
= rowB
[k
] & 0xf;
335 const GLint rowAg0
= (rowA
[j
] >> 4) & 0xf;
336 const GLint rowAg1
= (rowA
[k
] >> 4) & 0xf;
337 const GLint rowBg0
= (rowB
[j
] >> 4) & 0xf;
338 const GLint rowBg1
= (rowB
[k
] >> 4) & 0xf;
339 const GLint rowAb0
= (rowA
[j
] >> 8) & 0xf;
340 const GLint rowAb1
= (rowA
[k
] >> 8) & 0xf;
341 const GLint rowBb0
= (rowB
[j
] >> 8) & 0xf;
342 const GLint rowBb1
= (rowB
[k
] >> 8) & 0xf;
343 const GLint rowAa0
= (rowA
[j
] >> 12) & 0xf;
344 const GLint rowAa1
= (rowA
[k
] >> 12) & 0xf;
345 const GLint rowBa0
= (rowB
[j
] >> 12) & 0xf;
346 const GLint rowBa1
= (rowB
[k
] >> 12) & 0xf;
347 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
348 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
349 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
350 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
351 dst
[i
] = (alpha
<< 12) | (blue
<< 8) | (green
<< 4) | red
;
354 else if (datatype
== GL_UNSIGNED_SHORT_1_5_5_5_REV
&& comps
== 4) {
356 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
357 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
358 GLushort
*dst
= (GLushort
*) dstRow
;
359 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
360 i
++, j
+= colStride
, k
+= colStride
) {
361 const GLint rowAr0
= rowA
[j
] & 0x1f;
362 const GLint rowAr1
= rowA
[k
] & 0x1f;
363 const GLint rowBr0
= rowB
[j
] & 0x1f;
364 const GLint rowBr1
= rowB
[k
] & 0xf;
365 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x1f;
366 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x1f;
367 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x1f;
368 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x1f;
369 const GLint rowAb0
= (rowA
[j
] >> 10) & 0x1f;
370 const GLint rowAb1
= (rowA
[k
] >> 10) & 0x1f;
371 const GLint rowBb0
= (rowB
[j
] >> 10) & 0x1f;
372 const GLint rowBb1
= (rowB
[k
] >> 10) & 0x1f;
373 const GLint rowAa0
= (rowA
[j
] >> 15) & 0x1;
374 const GLint rowAa1
= (rowA
[k
] >> 15) & 0x1;
375 const GLint rowBa0
= (rowB
[j
] >> 15) & 0x1;
376 const GLint rowBa1
= (rowB
[k
] >> 15) & 0x1;
377 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
378 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
379 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
380 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
381 dst
[i
] = (alpha
<< 15) | (blue
<< 10) | (green
<< 5) | red
;
384 else if (datatype
== GL_UNSIGNED_BYTE_3_3_2
&& comps
== 3) {
386 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
387 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
388 GLubyte
*dst
= (GLubyte
*) dstRow
;
389 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
390 i
++, j
+= colStride
, k
+= colStride
) {
391 const GLint rowAr0
= rowA
[j
] & 0x3;
392 const GLint rowAr1
= rowA
[k
] & 0x3;
393 const GLint rowBr0
= rowB
[j
] & 0x3;
394 const GLint rowBr1
= rowB
[k
] & 0x3;
395 const GLint rowAg0
= (rowA
[j
] >> 2) & 0x7;
396 const GLint rowAg1
= (rowA
[k
] >> 2) & 0x7;
397 const GLint rowBg0
= (rowB
[j
] >> 2) & 0x7;
398 const GLint rowBg1
= (rowB
[k
] >> 2) & 0x7;
399 const GLint rowAb0
= (rowA
[j
] >> 5) & 0x7;
400 const GLint rowAb1
= (rowA
[k
] >> 5) & 0x7;
401 const GLint rowBb0
= (rowB
[j
] >> 5) & 0x7;
402 const GLint rowBb1
= (rowB
[k
] >> 5) & 0x7;
403 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
404 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
405 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
406 dst
[i
] = (blue
<< 5) | (green
<< 2) | red
;
410 _mesa_problem(NULL
, "bad format in do_row()");
416 * These functions generate a 1/2-size mipmap image from a source image.
417 * Texture borders are handled by copying or averaging the source image's
418 * border texels, depending on the scale-down factor.
422 make_1d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
423 GLint srcWidth
, const GLubyte
*srcPtr
,
424 GLint dstWidth
, GLubyte
*dstPtr
)
426 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
430 /* skip the border pixel, if any */
431 src
= srcPtr
+ border
* bpt
;
432 dst
= dstPtr
+ border
* bpt
;
434 /* we just duplicate the input row, kind of hack, saves code */
435 do_row(datatype
, comps
, srcWidth
- 2 * border
, src
, src
,
436 dstWidth
- 2 * border
, dst
);
439 /* copy left-most pixel from source */
440 MEMCPY(dstPtr
, srcPtr
, bpt
);
441 /* copy right-most pixel from source */
442 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
443 srcPtr
+ (srcWidth
- 1) * bpt
,
450 make_2d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
451 GLint srcWidth
, GLint srcHeight
,
452 const GLubyte
*srcPtr
, GLint srcRowStride
,
453 GLint dstWidth
, GLint dstHeight
,
454 GLubyte
*dstPtr
, GLint dstRowStride
)
456 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
457 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
458 const GLint dstWidthNB
= dstWidth
- 2 * border
;
459 const GLint dstHeightNB
= dstHeight
- 2 * border
;
460 const GLint srcRowBytes
= bpt
* srcRowStride
;
461 const GLint dstRowBytes
= bpt
* dstRowStride
;
462 const GLubyte
*srcA
, *srcB
;
466 /* Compute src and dst pointers, skipping any border */
467 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
469 srcB
= srcA
+ srcRowBytes
;
472 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
474 for (row
= 0; row
< dstHeightNB
; row
++) {
475 do_row(datatype
, comps
, srcWidthNB
, srcA
, srcB
,
477 srcA
+= 2 * srcRowBytes
;
478 srcB
+= 2 * srcRowBytes
;
482 /* This is ugly but probably won't be used much */
484 /* fill in dest border */
485 /* lower-left border pixel */
486 MEMCPY(dstPtr
, srcPtr
, bpt
);
487 /* lower-right border pixel */
488 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
489 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
490 /* upper-left border pixel */
491 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
492 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
493 /* upper-right border pixel */
494 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
495 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
497 do_row(datatype
, comps
, srcWidthNB
,
500 dstWidthNB
, dstPtr
+ bpt
);
502 do_row(datatype
, comps
, srcWidthNB
,
503 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
504 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
506 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
507 /* left and right borders */
508 if (srcHeight
== dstHeight
) {
509 /* copy border pixel from src to dst */
510 for (row
= 1; row
< srcHeight
; row
++) {
511 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
512 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
513 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
514 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
518 /* average two src pixels each dest pixel */
519 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
520 do_row(datatype
, comps
, 1,
521 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
522 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
523 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
524 do_row(datatype
, comps
, 1,
525 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
526 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
527 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
535 make_3d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
536 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
537 const GLubyte
*srcPtr
, GLint srcRowStride
,
538 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
539 GLubyte
*dstPtr
, GLint dstRowStride
)
541 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
542 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
543 const GLint srcDepthNB
= srcDepth
- 2 * border
;
544 const GLint dstWidthNB
= dstWidth
- 2 * border
;
545 const GLint dstHeightNB
= dstHeight
- 2 * border
;
546 const GLint dstDepthNB
= dstDepth
- 2 * border
;
547 GLvoid
*tmpRowA
, *tmpRowB
;
549 GLint bytesPerSrcImage
, bytesPerDstImage
;
550 GLint bytesPerSrcRow
, bytesPerDstRow
;
551 GLint srcImageOffset
, srcRowOffset
;
553 (void) srcDepthNB
; /* silence warnings */
555 /* Need two temporary row buffers */
556 tmpRowA
= _mesa_malloc(srcWidth
* bpt
);
559 tmpRowB
= _mesa_malloc(srcWidth
* bpt
);
565 bytesPerSrcImage
= srcWidth
* srcHeight
* bpt
;
566 bytesPerDstImage
= dstWidth
* dstHeight
* bpt
;
568 bytesPerSrcRow
= srcWidth
* bpt
;
569 bytesPerDstRow
= dstWidth
* bpt
;
571 /* Offset between adjacent src images to be averaged together */
572 srcImageOffset
= (srcDepth
== dstDepth
) ? 0 : bytesPerSrcImage
;
574 /* Offset between adjacent src rows to be averaged together */
575 srcRowOffset
= (srcHeight
== dstHeight
) ? 0 : srcWidth
* bpt
;
578 * Need to average together up to 8 src pixels for each dest pixel.
579 * Break that down into 3 operations:
580 * 1. take two rows from source image and average them together.
581 * 2. take two rows from next source image and average them together.
582 * 3. take the two averaged rows and average them for the final dst row.
586 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
587 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
590 for (img
= 0; img
< dstDepthNB
; img
++) {
591 /* first source image pointer, skipping border */
592 const GLubyte
*imgSrcA
= srcPtr
593 + (bytesPerSrcImage
+ bytesPerSrcRow
+ border
) * bpt
* border
594 + img
* (bytesPerSrcImage
+ srcImageOffset
);
595 /* second source image pointer, skipping border */
596 const GLubyte
*imgSrcB
= imgSrcA
+ srcImageOffset
;
597 /* address of the dest image, skipping border */
598 GLubyte
*imgDst
= dstPtr
599 + (bytesPerDstImage
+ bytesPerDstRow
+ border
) * bpt
* border
600 + img
* bytesPerDstImage
;
602 /* setup the four source row pointers and the dest row pointer */
603 const GLubyte
*srcImgARowA
= imgSrcA
;
604 const GLubyte
*srcImgARowB
= imgSrcA
+ srcRowOffset
;
605 const GLubyte
*srcImgBRowA
= imgSrcB
;
606 const GLubyte
*srcImgBRowB
= imgSrcB
+ srcRowOffset
;
607 GLubyte
*dstImgRow
= imgDst
;
609 for (row
= 0; row
< dstHeightNB
; row
++) {
610 /* Average together two rows from first src image */
611 do_row(datatype
, comps
, srcWidthNB
, srcImgARowA
, srcImgARowB
,
612 srcWidthNB
, tmpRowA
);
613 /* Average together two rows from second src image */
614 do_row(datatype
, comps
, srcWidthNB
, srcImgBRowA
, srcImgBRowB
,
615 srcWidthNB
, tmpRowB
);
616 /* Average together the temp rows to make the final row */
617 do_row(datatype
, comps
, srcWidthNB
, tmpRowA
, tmpRowB
,
618 dstWidthNB
, dstImgRow
);
619 /* advance to next rows */
620 srcImgARowA
+= bytesPerSrcRow
+ srcRowOffset
;
621 srcImgARowB
+= bytesPerSrcRow
+ srcRowOffset
;
622 srcImgBRowA
+= bytesPerSrcRow
+ srcRowOffset
;
623 srcImgBRowB
+= bytesPerSrcRow
+ srcRowOffset
;
624 dstImgRow
+= bytesPerDstRow
;
631 /* Luckily we can leverage the make_2d_mipmap() function here! */
633 /* do front border image */
634 make_2d_mipmap(datatype
, comps
, 1, srcWidth
, srcHeight
, srcPtr
, srcRowStride
,
635 dstWidth
, dstHeight
, dstPtr
, dstRowStride
);
636 /* do back border image */
637 make_2d_mipmap(datatype
, comps
, 1, srcWidth
, srcHeight
,
638 srcPtr
+ bytesPerSrcImage
* (srcDepth
- 1), srcRowStride
,
640 dstPtr
+ bytesPerDstImage
* (dstDepth
- 1), dstRowStride
);
641 /* do four remaining border edges that span the image slices */
642 if (srcDepth
== dstDepth
) {
643 /* just copy border pixels from src to dst */
644 for (img
= 0; img
< dstDepthNB
; img
++) {
648 /* do border along [img][row=0][col=0] */
649 src
= srcPtr
+ (img
+ 1) * bytesPerSrcImage
;
650 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
651 MEMCPY(dst
, src
, bpt
);
653 /* do border along [img][row=dstHeight-1][col=0] */
654 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
655 + (srcHeight
- 1) * bytesPerSrcRow
;
656 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
657 + (dstHeight
- 1) * bytesPerDstRow
;
658 MEMCPY(dst
, src
, bpt
);
660 /* do border along [img][row=0][col=dstWidth-1] */
661 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
662 + (srcWidth
- 1) * bpt
;
663 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
664 + (dstWidth
- 1) * bpt
;
665 MEMCPY(dst
, src
, bpt
);
667 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
668 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
669 + (bytesPerSrcImage
- bpt
);
670 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
671 + (bytesPerDstImage
- bpt
);
672 MEMCPY(dst
, src
, bpt
);
676 /* average border pixels from adjacent src image pairs */
677 ASSERT(srcDepthNB
== 2 * dstDepthNB
);
678 for (img
= 0; img
< dstDepthNB
; img
++) {
682 /* do border along [img][row=0][col=0] */
683 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
;
684 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
685 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
687 /* do border along [img][row=dstHeight-1][col=0] */
688 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
689 + (srcHeight
- 1) * bytesPerSrcRow
;
690 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
691 + (dstHeight
- 1) * bytesPerDstRow
;
692 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
694 /* do border along [img][row=0][col=dstWidth-1] */
695 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
696 + (srcWidth
- 1) * bpt
;
697 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
698 + (dstWidth
- 1) * bpt
;
699 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
701 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
702 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
703 + (bytesPerSrcImage
- bpt
);
704 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
705 + (bytesPerDstImage
- bpt
);
706 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
714 make_1d_stack_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
715 GLint srcWidth
, const GLubyte
*srcPtr
, GLuint srcRowStride
,
716 GLint dstWidth
, GLint dstHeight
,
717 GLubyte
*dstPtr
, GLuint dstRowStride
)
719 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
720 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
721 const GLint dstWidthNB
= dstWidth
- 2 * border
;
722 const GLint dstHeightNB
= dstHeight
- 2 * border
;
723 const GLint srcRowBytes
= bpt
* srcRowStride
;
724 const GLint dstRowBytes
= bpt
* dstRowStride
;
729 /* Compute src and dst pointers, skipping any border */
730 src
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
731 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
733 for (row
= 0; row
< dstHeightNB
; row
++) {
734 do_row(datatype
, comps
, srcWidthNB
, src
, src
,
741 /* copy left-most pixel from source */
742 MEMCPY(dstPtr
, srcPtr
, bpt
);
743 /* copy right-most pixel from source */
744 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
745 srcPtr
+ (srcWidth
- 1) * bpt
,
753 * There is quite a bit of refactoring that could be done with this function
754 * and \c make_2d_mipmap.
757 make_2d_stack_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
758 GLint srcWidth
, GLint srcHeight
,
759 const GLubyte
*srcPtr
, GLint srcRowStride
,
760 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
761 GLubyte
*dstPtr
, GLint dstRowStride
)
763 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
764 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
765 const GLint dstWidthNB
= dstWidth
- 2 * border
;
766 const GLint dstHeightNB
= dstHeight
- 2 * border
;
767 const GLint dstDepthNB
= dstDepth
- 2 * border
;
768 const GLint srcRowBytes
= bpt
* srcRowStride
;
769 const GLint dstRowBytes
= bpt
* dstRowStride
;
770 const GLubyte
*srcA
, *srcB
;
775 /* Compute src and dst pointers, skipping any border */
776 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
778 srcB
= srcA
+ srcRowBytes
;
781 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
783 for (layer
= 0; layer
< dstDepthNB
; layer
++) {
784 for (row
= 0; row
< dstHeightNB
; row
++) {
785 do_row(datatype
, comps
, srcWidthNB
, srcA
, srcB
,
787 srcA
+= 2 * srcRowBytes
;
788 srcB
+= 2 * srcRowBytes
;
792 /* This is ugly but probably won't be used much */
794 /* fill in dest border */
795 /* lower-left border pixel */
796 MEMCPY(dstPtr
, srcPtr
, bpt
);
797 /* lower-right border pixel */
798 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
799 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
800 /* upper-left border pixel */
801 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
802 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
803 /* upper-right border pixel */
804 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
805 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
807 do_row(datatype
, comps
, srcWidthNB
,
810 dstWidthNB
, dstPtr
+ bpt
);
812 do_row(datatype
, comps
, srcWidthNB
,
813 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
814 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
816 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
817 /* left and right borders */
818 if (srcHeight
== dstHeight
) {
819 /* copy border pixel from src to dst */
820 for (row
= 1; row
< srcHeight
; row
++) {
821 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
822 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
823 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
824 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
828 /* average two src pixels each dest pixel */
829 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
830 do_row(datatype
, comps
, 1,
831 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
832 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
833 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
834 do_row(datatype
, comps
, 1,
835 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
836 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
837 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
846 * Down-sample a texture image to produce the next lower mipmap level.
849 _mesa_generate_mipmap_level(GLenum target
,
850 GLenum datatype
, GLuint comps
,
852 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
853 const GLubyte
*srcData
,
855 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
860 * We use simple 2x2 averaging to compute the next mipmap level.
864 make_1d_mipmap(datatype
, comps
, border
,
869 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
:
870 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
:
871 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
:
872 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
:
873 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
:
874 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
:
875 make_2d_mipmap(datatype
, comps
, border
,
876 srcWidth
, srcHeight
, srcData
, srcRowStride
,
877 dstWidth
, dstHeight
, dstData
, dstRowStride
);
880 make_3d_mipmap(datatype
, comps
, border
,
881 srcWidth
, srcHeight
, srcDepth
,
882 srcData
, srcRowStride
,
883 dstWidth
, dstHeight
, dstDepth
,
884 dstData
, dstRowStride
);
886 case GL_TEXTURE_1D_ARRAY_EXT
:
887 make_1d_stack_mipmap(datatype
, comps
, border
,
888 srcWidth
, srcData
, srcRowStride
,
890 dstData
, dstRowStride
);
892 case GL_TEXTURE_2D_ARRAY_EXT
:
893 make_2d_stack_mipmap(datatype
, comps
, border
,
895 srcData
, srcRowStride
,
897 dstDepth
, dstData
, dstRowStride
);
899 case GL_TEXTURE_RECTANGLE_NV
:
900 /* no mipmaps, do nothing */
903 _mesa_problem(NULL
, "bad dimensions in _mesa_generate_mipmaps");
910 * compute next (level+1) image size
911 * \return GL_FALSE if no smaller size can be generated (eg. src is 1x1x1 size)
914 next_mipmap_level_size(GLenum target
, GLint border
,
915 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
916 GLint
*dstWidth
, GLint
*dstHeight
, GLint
*dstDepth
)
918 if (srcWidth
- 2 * border
> 1) {
919 *dstWidth
= (srcWidth
- 2 * border
) / 2 + 2 * border
;
922 *dstWidth
= srcWidth
; /* can't go smaller */
925 if ((srcHeight
- 2 * border
> 1) &&
926 (target
!= GL_TEXTURE_1D_ARRAY_EXT
)) {
927 *dstHeight
= (srcHeight
- 2 * border
) / 2 + 2 * border
;
930 *dstHeight
= srcHeight
; /* can't go smaller */
933 if ((srcDepth
- 2 * border
> 1) &&
934 (target
!= GL_TEXTURE_2D_ARRAY_EXT
)) {
935 *dstDepth
= (srcDepth
- 2 * border
) / 2 + 2 * border
;
938 *dstDepth
= srcDepth
; /* can't go smaller */
941 if (*dstWidth
== srcWidth
&&
942 *dstHeight
== srcHeight
&&
943 *dstDepth
== srcDepth
) {
955 * For GL_SGIX_generate_mipmap:
956 * Generate a complete set of mipmaps from texObj's base-level image.
957 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
960 _mesa_generate_mipmap(GLcontext
*ctx
, GLenum target
,
961 struct gl_texture_object
*texObj
)
963 const struct gl_texture_image
*srcImage
;
964 const struct gl_texture_format
*convertFormat
;
965 const GLubyte
*srcData
= NULL
;
966 GLubyte
*dstData
= NULL
;
967 GLint level
, maxLevels
;
972 /* XXX choose cube map face here??? */
973 srcImage
= texObj
->Image
[0][texObj
->BaseLevel
];
976 maxLevels
= _mesa_max_texture_levels(ctx
, texObj
->Target
);
977 ASSERT(maxLevels
> 0); /* bad target */
979 /* Find convertFormat - the format that do_row() will process */
980 if (srcImage
->IsCompressed
) {
981 /* setup for compressed textures */
983 GLint components
, size
;
986 assert(texObj
->Target
== GL_TEXTURE_2D
||
987 texObj
->Target
== GL_TEXTURE_CUBE_MAP_ARB
);
989 if (srcImage
->_BaseFormat
== GL_RGB
) {
990 convertFormat
= &_mesa_texformat_rgb
;
993 else if (srcImage
->_BaseFormat
== GL_RGBA
) {
994 convertFormat
= &_mesa_texformat_rgba
;
998 _mesa_problem(ctx
, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
1002 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
1003 size
= _mesa_bytes_per_pixel(srcImage
->_BaseFormat
, CHAN_TYPE
)
1004 * srcImage
->Width
* srcImage
->Height
* srcImage
->Depth
+ 20;
1005 /* 20 extra bytes, just be safe when calling last FetchTexel */
1006 srcData
= (GLubyte
*) _mesa_malloc(size
);
1008 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
1011 dstData
= (GLubyte
*) _mesa_malloc(size
/ 2); /* 1/4 would probably be OK */
1013 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
1014 _mesa_free((void *) srcData
);
1018 /* decompress base image here */
1019 dst
= (GLchan
*) srcData
;
1020 for (row
= 0; row
< srcImage
->Height
; row
++) {
1022 for (col
= 0; col
< srcImage
->Width
; col
++) {
1023 srcImage
->FetchTexelc(srcImage
, col
, row
, 0, dst
);
1030 convertFormat
= srcImage
->TexFormat
;
1033 _mesa_format_to_type_and_comps(convertFormat
, &datatype
, &comps
);
1035 for (level
= texObj
->BaseLevel
; level
< texObj
->MaxLevel
1036 && level
< maxLevels
- 1; level
++) {
1037 /* generate image[level+1] from image[level] */
1038 const struct gl_texture_image
*srcImage
;
1039 struct gl_texture_image
*dstImage
;
1040 GLint srcWidth
, srcHeight
, srcDepth
;
1041 GLint dstWidth
, dstHeight
, dstDepth
;
1042 GLint border
, bytesPerTexel
;
1043 GLboolean nextLevel
;
1045 /* get src image parameters */
1046 srcImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
1048 srcWidth
= srcImage
->Width
;
1049 srcHeight
= srcImage
->Height
;
1050 srcDepth
= srcImage
->Depth
;
1051 border
= srcImage
->Border
;
1053 nextLevel
= next_mipmap_level_size(target
, border
,
1054 srcWidth
, srcHeight
, srcDepth
,
1055 &dstWidth
, &dstHeight
, &dstDepth
);
1058 if (srcImage
->IsCompressed
) {
1059 _mesa_free((void *) srcData
);
1060 _mesa_free(dstData
);
1065 /* get dest gl_texture_image */
1066 dstImage
= _mesa_get_tex_image(ctx
, texObj
, target
, level
+ 1);
1068 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1072 if (dstImage
->ImageOffsets
)
1073 _mesa_free(dstImage
->ImageOffsets
);
1075 /* Free old image data */
1077 ctx
->Driver
.FreeTexImageData(ctx
, dstImage
);
1079 /* initialize new image */
1080 _mesa_init_teximage_fields(ctx
, target
, dstImage
, dstWidth
, dstHeight
,
1081 dstDepth
, border
, srcImage
->InternalFormat
);
1082 dstImage
->DriverData
= NULL
;
1083 dstImage
->TexFormat
= srcImage
->TexFormat
;
1084 dstImage
->FetchTexelc
= srcImage
->FetchTexelc
;
1085 dstImage
->FetchTexelf
= srcImage
->FetchTexelf
;
1086 dstImage
->IsCompressed
= srcImage
->IsCompressed
;
1087 if (dstImage
->IsCompressed
) {
1088 dstImage
->CompressedSize
1089 = ctx
->Driver
.CompressedTextureSize(ctx
, dstImage
->Width
,
1092 dstImage
->TexFormat
->MesaFormat
);
1093 ASSERT(dstImage
->CompressedSize
> 0);
1096 ASSERT(dstImage
->TexFormat
);
1097 ASSERT(dstImage
->FetchTexelc
);
1098 ASSERT(dstImage
->FetchTexelf
);
1100 /* Alloc new teximage data buffer.
1101 * Setup src and dest data pointers.
1103 if (dstImage
->IsCompressed
) {
1104 dstImage
->Data
= _mesa_alloc_texmemory(dstImage
->CompressedSize
);
1105 if (!dstImage
->Data
) {
1106 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1109 /* srcData and dstData are already set */
1114 bytesPerTexel
= dstImage
->TexFormat
->TexelBytes
;
1115 ASSERT(dstWidth
* dstHeight
* dstDepth
* bytesPerTexel
> 0);
1116 dstImage
->Data
= _mesa_alloc_texmemory(dstWidth
* dstHeight
1117 * dstDepth
* bytesPerTexel
);
1118 if (!dstImage
->Data
) {
1119 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1122 srcData
= (const GLubyte
*) srcImage
->Data
;
1123 dstData
= (GLubyte
*) dstImage
->Data
;
1126 _mesa_generate_mipmap_level(target
, datatype
, comps
, border
,
1127 srcWidth
, srcHeight
, srcDepth
,
1128 srcData
, srcImage
->RowStride
,
1129 dstWidth
, dstHeight
, dstDepth
,
1130 dstData
, dstImage
->RowStride
);
1133 if (dstImage
->IsCompressed
) {
1135 /* compress image from dstData into dstImage->Data */
1136 const GLenum srcFormat
= convertFormat
->BaseFormat
;
1138 = _mesa_compressed_row_stride(dstImage
->TexFormat
->MesaFormat
, dstWidth
);
1139 ASSERT(srcFormat
== GL_RGB
|| srcFormat
== GL_RGBA
);
1140 dstImage
->TexFormat
->StoreImage(ctx
, 2, dstImage
->_BaseFormat
,
1141 dstImage
->TexFormat
,
1143 0, 0, 0, /* dstX/Y/Zoffset */
1144 dstRowStride
, 0, /* strides */
1145 dstWidth
, dstHeight
, 1, /* size */
1146 srcFormat
, CHAN_TYPE
,
1147 dstData
, /* src data, actually */
1148 &ctx
->DefaultPacking
);
1149 /* swap src and dest pointers */
1150 temp
= (GLubyte
*) srcData
;
1155 } /* loop over mipmap levels */
1160 * Helper function for drivers which need to rescale texture images to
1161 * certain aspect ratios.
1162 * Nearest filtering only (for broken hardware that can't support
1163 * all aspect ratios). This can be made a lot faster, but I don't
1164 * really care enough...
1167 _mesa_rescale_teximage2d(GLuint bytesPerPixel
,
1168 GLuint srcStrideInPixels
,
1169 GLuint dstRowStride
,
1170 GLint srcWidth
, GLint srcHeight
,
1171 GLint dstWidth
, GLint dstHeight
,
1172 const GLvoid
*srcImage
, GLvoid
*dstImage
)
1176 #define INNER_LOOP( TYPE, HOP, WOP ) \
1177 for ( row = 0 ; row < dstHeight ; row++ ) { \
1178 GLint srcRow = row HOP hScale; \
1179 for ( col = 0 ; col < dstWidth ; col++ ) { \
1180 GLint srcCol = col WOP wScale; \
1181 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1183 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1186 #define RESCALE_IMAGE( TYPE ) \
1188 const TYPE *src = (const TYPE *)srcImage; \
1189 TYPE *dst = (TYPE *)dstImage; \
1191 if ( srcHeight < dstHeight ) { \
1192 const GLint hScale = dstHeight / srcHeight; \
1193 if ( srcWidth < dstWidth ) { \
1194 const GLint wScale = dstWidth / srcWidth; \
1195 INNER_LOOP( TYPE, /, / ); \
1198 const GLint wScale = srcWidth / dstWidth; \
1199 INNER_LOOP( TYPE, /, * ); \
1203 const GLint hScale = srcHeight / dstHeight; \
1204 if ( srcWidth < dstWidth ) { \
1205 const GLint wScale = dstWidth / srcWidth; \
1206 INNER_LOOP( TYPE, *, / ); \
1209 const GLint wScale = srcWidth / dstWidth; \
1210 INNER_LOOP( TYPE, *, * ); \
1215 switch ( bytesPerPixel
) {
1217 RESCALE_IMAGE( GLuint
);
1221 RESCALE_IMAGE( GLushort
);
1225 RESCALE_IMAGE( GLubyte
);
1228 _mesa_problem(NULL
,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1234 * Upscale an image by replication, not (typical) stretching.
1235 * We use this when the image width or height is less than a
1236 * certain size (4, 8) and we need to upscale an image.
1239 _mesa_upscale_teximage2d(GLsizei inWidth
, GLsizei inHeight
,
1240 GLsizei outWidth
, GLsizei outHeight
,
1241 GLint comps
, const GLchan
*src
, GLint srcRowStride
,
1246 ASSERT(outWidth
>= inWidth
);
1247 ASSERT(outHeight
>= inHeight
);
1249 ASSERT(inWidth
== 1 || inWidth
== 2 || inHeight
== 1 || inHeight
== 2);
1250 ASSERT((outWidth
& 3) == 0);
1251 ASSERT((outHeight
& 3) == 0);
1254 for (i
= 0; i
< outHeight
; i
++) {
1255 const GLint ii
= i
% inHeight
;
1256 for (j
= 0; j
< outWidth
; j
++) {
1257 const GLint jj
= j
% inWidth
;
1258 for (k
= 0; k
< comps
; k
++) {
1259 dest
[(i
* outWidth
+ j
) * comps
+ k
]
1260 = src
[ii
* srcRowStride
+ jj
* comps
+ k
];