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 * Average together two rows of a source image to produce a single new
41 * row in the dest image. It's legal for the two source rows to point
42 * to the same data. The source width must be equal to either the
43 * dest width or two times the dest width.
46 do_row(const struct gl_texture_format
*format
, GLint srcWidth
,
47 const GLvoid
*srcRowA
, const GLvoid
*srcRowB
,
48 GLint dstWidth
, GLvoid
*dstRow
)
50 const GLuint k0
= (srcWidth
== dstWidth
) ? 0 : 1;
51 const GLuint colStride
= (srcWidth
== dstWidth
) ? 1 : 2;
53 /* This assertion is no longer valid with non-power-of-2 textures
54 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
57 switch (format
->MesaFormat
) {
58 case MESA_FORMAT_RGBA
:
61 const GLchan (*rowA
)[4] = (const GLchan (*)[4]) srcRowA
;
62 const GLchan (*rowB
)[4] = (const GLchan (*)[4]) srcRowB
;
63 GLchan (*dst
)[4] = (GLchan (*)[4]) dstRow
;
64 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
65 i
++, j
+= colStride
, k
+= colStride
) {
66 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
67 rowB
[j
][0] + rowB
[k
][0]) / 4;
68 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
69 rowB
[j
][1] + rowB
[k
][1]) / 4;
70 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
71 rowB
[j
][2] + rowB
[k
][2]) / 4;
72 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
73 rowB
[j
][3] + rowB
[k
][3]) / 4;
80 const GLchan (*rowA
)[3] = (const GLchan (*)[3]) srcRowA
;
81 const GLchan (*rowB
)[3] = (const GLchan (*)[3]) srcRowB
;
82 GLchan (*dst
)[3] = (GLchan (*)[3]) dstRow
;
83 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
84 i
++, j
+= colStride
, k
+= colStride
) {
85 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
86 rowB
[j
][0] + rowB
[k
][0]) / 4;
87 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
88 rowB
[j
][1] + rowB
[k
][1]) / 4;
89 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
90 rowB
[j
][2] + rowB
[k
][2]) / 4;
94 case MESA_FORMAT_ALPHA
:
95 case MESA_FORMAT_LUMINANCE
:
96 case MESA_FORMAT_INTENSITY
:
99 const GLchan
*rowA
= (const GLchan
*) srcRowA
;
100 const GLchan
*rowB
= (const GLchan
*) srcRowB
;
101 GLchan
*dst
= (GLchan
*) dstRow
;
102 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
103 i
++, j
+= colStride
, k
+= colStride
) {
104 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) / 4;
108 case MESA_FORMAT_LUMINANCE_ALPHA
:
111 const GLchan (*rowA
)[2] = (const GLchan (*)[2]) srcRowA
;
112 const GLchan (*rowB
)[2] = (const GLchan (*)[2]) srcRowB
;
113 GLchan (*dst
)[2] = (GLchan (*)[2]) dstRow
;
114 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
115 i
++, j
+= colStride
, k
+= colStride
) {
116 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
117 rowB
[j
][0] + rowB
[k
][0]) / 4;
118 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
119 rowB
[j
][1] + rowB
[k
][1]) / 4;
123 case MESA_FORMAT_Z32
:
126 const GLuint
*rowA
= (const GLuint
*) srcRowA
;
127 const GLuint
*rowB
= (const GLuint
*) srcRowB
;
128 GLfloat
*dst
= (GLfloat
*) dstRow
;
129 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
130 i
++, j
+= colStride
, k
+= colStride
) {
131 dst
[i
] = rowA
[j
] / 4 + rowA
[k
] / 4 + rowB
[j
] / 4 + rowB
[k
] / 4;
135 case MESA_FORMAT_Z16
:
138 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
139 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
140 GLushort
*dst
= (GLushort
*) dstRow
;
141 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
142 i
++, j
+= colStride
, k
+= colStride
) {
143 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) / 4;
147 /* Begin hardware formats */
148 case MESA_FORMAT_RGBA8888
:
149 case MESA_FORMAT_RGBA8888_REV
:
150 case MESA_FORMAT_ARGB8888
:
151 case MESA_FORMAT_ARGB8888_REV
:
152 #if FEATURE_EXT_texture_sRGB
153 case MESA_FORMAT_SRGBA8
:
157 const GLubyte (*rowA
)[4] = (const GLubyte (*)[4]) srcRowA
;
158 const GLubyte (*rowB
)[4] = (const GLubyte (*)[4]) srcRowB
;
159 GLubyte (*dst
)[4] = (GLubyte (*)[4]) dstRow
;
160 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
161 i
++, j
+= colStride
, k
+= colStride
) {
162 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
163 rowB
[j
][0] + rowB
[k
][0]) / 4;
164 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
165 rowB
[j
][1] + rowB
[k
][1]) / 4;
166 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
167 rowB
[j
][2] + rowB
[k
][2]) / 4;
168 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
169 rowB
[j
][3] + rowB
[k
][3]) / 4;
173 case MESA_FORMAT_RGB888
:
174 case MESA_FORMAT_BGR888
:
175 #if FEATURE_EXT_texture_sRGB
176 case MESA_FORMAT_SRGB8
:
180 const GLubyte (*rowA
)[3] = (const GLubyte (*)[3]) srcRowA
;
181 const GLubyte (*rowB
)[3] = (const GLubyte (*)[3]) srcRowB
;
182 GLubyte (*dst
)[3] = (GLubyte (*)[3]) dstRow
;
183 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
184 i
++, j
+= colStride
, k
+= colStride
) {
185 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
186 rowB
[j
][0] + rowB
[k
][0]) / 4;
187 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
188 rowB
[j
][1] + rowB
[k
][1]) / 4;
189 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
190 rowB
[j
][2] + rowB
[k
][2]) / 4;
194 case MESA_FORMAT_RGB565
:
195 case MESA_FORMAT_RGB565_REV
:
198 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
199 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
200 GLushort
*dst
= (GLushort
*) dstRow
;
201 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
202 i
++, j
+= colStride
, k
+= colStride
) {
203 const GLint rowAr0
= rowA
[j
] & 0x1f;
204 const GLint rowAr1
= rowA
[k
] & 0x1f;
205 const GLint rowBr0
= rowB
[j
] & 0x1f;
206 const GLint rowBr1
= rowB
[k
] & 0x1f;
207 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x3f;
208 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x3f;
209 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x3f;
210 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x3f;
211 const GLint rowAb0
= (rowA
[j
] >> 11) & 0x1f;
212 const GLint rowAb1
= (rowA
[k
] >> 11) & 0x1f;
213 const GLint rowBb0
= (rowB
[j
] >> 11) & 0x1f;
214 const GLint rowBb1
= (rowB
[k
] >> 11) & 0x1f;
215 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
216 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
217 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
218 dst
[i
] = (blue
<< 11) | (green
<< 5) | red
;
222 case MESA_FORMAT_ARGB4444
:
223 case MESA_FORMAT_ARGB4444_REV
:
226 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
227 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
228 GLushort
*dst
= (GLushort
*) dstRow
;
229 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
230 i
++, j
+= colStride
, k
+= colStride
) {
231 const GLint rowAr0
= rowA
[j
] & 0xf;
232 const GLint rowAr1
= rowA
[k
] & 0xf;
233 const GLint rowBr0
= rowB
[j
] & 0xf;
234 const GLint rowBr1
= rowB
[k
] & 0xf;
235 const GLint rowAg0
= (rowA
[j
] >> 4) & 0xf;
236 const GLint rowAg1
= (rowA
[k
] >> 4) & 0xf;
237 const GLint rowBg0
= (rowB
[j
] >> 4) & 0xf;
238 const GLint rowBg1
= (rowB
[k
] >> 4) & 0xf;
239 const GLint rowAb0
= (rowA
[j
] >> 8) & 0xf;
240 const GLint rowAb1
= (rowA
[k
] >> 8) & 0xf;
241 const GLint rowBb0
= (rowB
[j
] >> 8) & 0xf;
242 const GLint rowBb1
= (rowB
[k
] >> 8) & 0xf;
243 const GLint rowAa0
= (rowA
[j
] >> 12) & 0xf;
244 const GLint rowAa1
= (rowA
[k
] >> 12) & 0xf;
245 const GLint rowBa0
= (rowB
[j
] >> 12) & 0xf;
246 const GLint rowBa1
= (rowB
[k
] >> 12) & 0xf;
247 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
248 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
249 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
250 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
251 dst
[i
] = (alpha
<< 12) | (blue
<< 8) | (green
<< 4) | red
;
255 case MESA_FORMAT_ARGB1555
:
256 case MESA_FORMAT_ARGB1555_REV
: /* XXX broken? */
259 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
260 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
261 GLushort
*dst
= (GLushort
*) dstRow
;
262 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
263 i
++, j
+= colStride
, k
+= colStride
) {
264 const GLint rowAr0
= rowA
[j
] & 0x1f;
265 const GLint rowAr1
= rowA
[k
] & 0x1f;
266 const GLint rowBr0
= rowB
[j
] & 0x1f;
267 const GLint rowBr1
= rowB
[k
] & 0xf;
268 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x1f;
269 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x1f;
270 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x1f;
271 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x1f;
272 const GLint rowAb0
= (rowA
[j
] >> 10) & 0x1f;
273 const GLint rowAb1
= (rowA
[k
] >> 10) & 0x1f;
274 const GLint rowBb0
= (rowB
[j
] >> 10) & 0x1f;
275 const GLint rowBb1
= (rowB
[k
] >> 10) & 0x1f;
276 const GLint rowAa0
= (rowA
[j
] >> 15) & 0x1;
277 const GLint rowAa1
= (rowA
[k
] >> 15) & 0x1;
278 const GLint rowBa0
= (rowB
[j
] >> 15) & 0x1;
279 const GLint rowBa1
= (rowB
[k
] >> 15) & 0x1;
280 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
281 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
282 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
283 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
284 dst
[i
] = (alpha
<< 15) | (blue
<< 10) | (green
<< 5) | red
;
288 case MESA_FORMAT_AL88
:
289 case MESA_FORMAT_AL88_REV
:
290 #if FEATURE_EXT_texture_sRGB
291 case MESA_FORMAT_SLA8
:
295 const GLubyte (*rowA
)[2] = (const GLubyte (*)[2]) srcRowA
;
296 const GLubyte (*rowB
)[2] = (const GLubyte (*)[2]) srcRowB
;
297 GLubyte (*dst
)[2] = (GLubyte (*)[2]) dstRow
;
298 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
299 i
++, j
+= colStride
, k
+= colStride
) {
300 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
301 rowB
[j
][0] + rowB
[k
][0]) >> 2;
302 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
303 rowB
[j
][1] + rowB
[k
][1]) >> 2;
307 case MESA_FORMAT_RGB332
:
310 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
311 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
312 GLubyte
*dst
= (GLubyte
*) dstRow
;
313 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
314 i
++, j
+= colStride
, k
+= colStride
) {
315 const GLint rowAr0
= rowA
[j
] & 0x3;
316 const GLint rowAr1
= rowA
[k
] & 0x3;
317 const GLint rowBr0
= rowB
[j
] & 0x3;
318 const GLint rowBr1
= rowB
[k
] & 0x3;
319 const GLint rowAg0
= (rowA
[j
] >> 2) & 0x7;
320 const GLint rowAg1
= (rowA
[k
] >> 2) & 0x7;
321 const GLint rowBg0
= (rowB
[j
] >> 2) & 0x7;
322 const GLint rowBg1
= (rowB
[k
] >> 2) & 0x7;
323 const GLint rowAb0
= (rowA
[j
] >> 5) & 0x7;
324 const GLint rowAb1
= (rowA
[k
] >> 5) & 0x7;
325 const GLint rowBb0
= (rowB
[j
] >> 5) & 0x7;
326 const GLint rowBb1
= (rowB
[k
] >> 5) & 0x7;
327 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
328 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
329 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
330 dst
[i
] = (blue
<< 5) | (green
<< 2) | red
;
337 case MESA_FORMAT_CI8
:
338 #if FEATURE_EXT_texture_sRGB
339 case MESA_FORMAT_SL8
:
343 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
344 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
345 GLubyte
*dst
= (GLubyte
*) dstRow
;
346 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
347 i
++, j
+= colStride
, k
+= colStride
) {
348 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) >> 2;
352 case MESA_FORMAT_RGBA_FLOAT32
:
355 const GLfloat (*rowA
)[4] = (const GLfloat (*)[4]) srcRowA
;
356 const GLfloat (*rowB
)[4] = (const GLfloat (*)[4]) srcRowB
;
357 GLfloat (*dst
)[4] = (GLfloat (*)[4]) dstRow
;
358 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
359 i
++, j
+= colStride
, k
+= colStride
) {
360 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
361 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
362 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
363 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
364 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
365 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
366 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
367 rowB
[j
][3] + rowB
[k
][3]) * 0.25F
;
371 case MESA_FORMAT_RGBA_FLOAT16
:
373 GLuint i
, j
, k
, comp
;
374 const GLhalfARB (*rowA
)[4] = (const GLhalfARB (*)[4]) srcRowA
;
375 const GLhalfARB (*rowB
)[4] = (const GLhalfARB (*)[4]) srcRowB
;
376 GLhalfARB (*dst
)[4] = (GLhalfARB (*)[4]) dstRow
;
377 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
378 i
++, j
+= colStride
, k
+= colStride
) {
379 for (comp
= 0; comp
< 4; comp
++) {
380 GLfloat aj
, ak
, bj
, bk
;
381 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
382 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
383 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
384 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
385 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
390 case MESA_FORMAT_RGB_FLOAT32
:
393 const GLfloat (*rowA
)[3] = (const GLfloat (*)[3]) srcRowA
;
394 const GLfloat (*rowB
)[3] = (const GLfloat (*)[3]) srcRowB
;
395 GLfloat (*dst
)[3] = (GLfloat (*)[3]) dstRow
;
396 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
397 i
++, j
+= colStride
, k
+= colStride
) {
398 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
399 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
400 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
401 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
402 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
403 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
407 case MESA_FORMAT_RGB_FLOAT16
:
409 GLuint i
, j
, k
, comp
;
410 const GLhalfARB (*rowA
)[3] = (const GLhalfARB (*)[3]) srcRowA
;
411 const GLhalfARB (*rowB
)[3] = (const GLhalfARB (*)[3]) srcRowB
;
412 GLhalfARB (*dst
)[3] = (GLhalfARB (*)[3]) dstRow
;
413 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
414 i
++, j
+= colStride
, k
+= colStride
) {
415 for (comp
= 0; comp
< 3; comp
++) {
416 GLfloat aj
, ak
, bj
, bk
;
417 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
418 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
419 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
420 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
421 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
426 case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32
:
429 const GLfloat (*rowA
)[2] = (const GLfloat (*)[2]) srcRowA
;
430 const GLfloat (*rowB
)[2] = (const GLfloat (*)[2]) srcRowB
;
431 GLfloat (*dst
)[2] = (GLfloat (*)[2]) dstRow
;
432 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
433 i
++, j
+= colStride
, k
+= colStride
) {
434 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
435 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
436 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
437 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
441 case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16
:
443 GLuint i
, j
, k
, comp
;
444 const GLhalfARB (*rowA
)[2] = (const GLhalfARB (*)[2]) srcRowA
;
445 const GLhalfARB (*rowB
)[2] = (const GLhalfARB (*)[2]) srcRowB
;
446 GLhalfARB (*dst
)[2] = (GLhalfARB (*)[2]) dstRow
;
447 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
448 i
++, j
+= colStride
, k
+= colStride
) {
449 for (comp
= 0; comp
< 2; comp
++) {
450 GLfloat aj
, ak
, bj
, bk
;
451 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
452 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
453 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
454 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
455 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
460 case MESA_FORMAT_ALPHA_FLOAT32
:
461 case MESA_FORMAT_LUMINANCE_FLOAT32
:
462 case MESA_FORMAT_INTENSITY_FLOAT32
:
465 const GLfloat
*rowA
= (const GLfloat
*) srcRowA
;
466 const GLfloat
*rowB
= (const GLfloat
*) srcRowB
;
467 GLfloat
*dst
= (GLfloat
*) dstRow
;
468 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
469 i
++, j
+= colStride
, k
+= colStride
) {
470 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) * 0.25F
;
474 case MESA_FORMAT_ALPHA_FLOAT16
:
475 case MESA_FORMAT_LUMINANCE_FLOAT16
:
476 case MESA_FORMAT_INTENSITY_FLOAT16
:
479 const GLhalfARB
*rowA
= (const GLhalfARB
*) srcRowA
;
480 const GLhalfARB
*rowB
= (const GLhalfARB
*) srcRowB
;
481 GLhalfARB
*dst
= (GLhalfARB
*) dstRow
;
482 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
483 i
++, j
+= colStride
, k
+= colStride
) {
484 GLfloat aj
, ak
, bj
, bk
;
485 aj
= _mesa_half_to_float(rowA
[j
]);
486 ak
= _mesa_half_to_float(rowA
[k
]);
487 bj
= _mesa_half_to_float(rowB
[j
]);
488 bk
= _mesa_half_to_float(rowB
[k
]);
489 dst
[i
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
495 _mesa_problem(NULL
, "bad format in do_row()");
501 * These functions generate a 1/2-size mipmap image from a source image.
502 * Texture borders are handled by copying or averaging the source image's
503 * border texels, depending on the scale-down factor.
507 make_1d_mipmap(const struct gl_texture_format
*format
, GLint border
,
508 GLint srcWidth
, const GLubyte
*srcPtr
,
509 GLint dstWidth
, GLubyte
*dstPtr
)
511 const GLint bpt
= format
->TexelBytes
;
515 /* skip the border pixel, if any */
516 src
= srcPtr
+ border
* bpt
;
517 dst
= dstPtr
+ border
* bpt
;
519 /* we just duplicate the input row, kind of hack, saves code */
520 do_row(format
, srcWidth
- 2 * border
, src
, src
,
521 dstWidth
- 2 * border
, dst
);
524 /* copy left-most pixel from source */
525 MEMCPY(dstPtr
, srcPtr
, bpt
);
526 /* copy right-most pixel from source */
527 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
528 srcPtr
+ (srcWidth
- 1) * bpt
,
535 make_2d_mipmap(const struct gl_texture_format
*format
, GLint border
,
536 GLint srcWidth
, GLint srcHeight
,
537 const GLubyte
*srcPtr
, GLint srcRowStride
,
538 GLint dstWidth
, GLint dstHeight
,
539 GLubyte
*dstPtr
, GLint dstRowStride
)
541 const GLint bpt
= format
->TexelBytes
;
542 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
543 const GLint dstWidthNB
= dstWidth
- 2 * border
;
544 const GLint dstHeightNB
= dstHeight
- 2 * border
;
545 const GLint srcRowBytes
= bpt
* srcRowStride
;
546 const GLint dstRowBytes
= bpt
* dstRowStride
;
547 const GLubyte
*srcA
, *srcB
;
551 /* Compute src and dst pointers, skipping any border */
552 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
554 srcB
= srcA
+ srcRowBytes
;
557 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
559 for (row
= 0; row
< dstHeightNB
; row
++) {
560 do_row(format
, srcWidthNB
, srcA
, srcB
,
562 srcA
+= 2 * srcRowBytes
;
563 srcB
+= 2 * srcRowBytes
;
567 /* This is ugly but probably won't be used much */
569 /* fill in dest border */
570 /* lower-left border pixel */
571 MEMCPY(dstPtr
, srcPtr
, bpt
);
572 /* lower-right border pixel */
573 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
574 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
575 /* upper-left border pixel */
576 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
577 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
578 /* upper-right border pixel */
579 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
580 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
582 do_row(format
, srcWidthNB
,
585 dstWidthNB
, dstPtr
+ bpt
);
587 do_row(format
, srcWidthNB
,
588 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
589 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
591 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
592 /* left and right borders */
593 if (srcHeight
== dstHeight
) {
594 /* copy border pixel from src to dst */
595 for (row
= 1; row
< srcHeight
; row
++) {
596 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
597 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
598 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
599 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
603 /* average two src pixels each dest pixel */
604 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
606 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
607 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
608 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
610 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
611 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
612 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
620 make_3d_mipmap(const struct gl_texture_format
*format
, GLint border
,
621 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
622 const GLubyte
*srcPtr
, GLint srcRowStride
,
623 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
624 GLubyte
*dstPtr
, GLint dstRowStride
)
626 const GLint bpt
= format
->TexelBytes
;
627 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
628 const GLint srcDepthNB
= srcDepth
- 2 * border
;
629 const GLint dstWidthNB
= dstWidth
- 2 * border
;
630 const GLint dstHeightNB
= dstHeight
- 2 * border
;
631 const GLint dstDepthNB
= dstDepth
- 2 * border
;
632 GLvoid
*tmpRowA
, *tmpRowB
;
634 GLint bytesPerSrcImage
, bytesPerDstImage
;
635 GLint bytesPerSrcRow
, bytesPerDstRow
;
636 GLint srcImageOffset
, srcRowOffset
;
638 (void) srcDepthNB
; /* silence warnings */
640 /* Need two temporary row buffers */
641 tmpRowA
= _mesa_malloc(srcWidth
* bpt
);
644 tmpRowB
= _mesa_malloc(srcWidth
* bpt
);
650 bytesPerSrcImage
= srcWidth
* srcHeight
* bpt
;
651 bytesPerDstImage
= dstWidth
* dstHeight
* bpt
;
653 bytesPerSrcRow
= srcWidth
* bpt
;
654 bytesPerDstRow
= dstWidth
* bpt
;
656 /* Offset between adjacent src images to be averaged together */
657 srcImageOffset
= (srcDepth
== dstDepth
) ? 0 : bytesPerSrcImage
;
659 /* Offset between adjacent src rows to be averaged together */
660 srcRowOffset
= (srcHeight
== dstHeight
) ? 0 : srcWidth
* bpt
;
663 * Need to average together up to 8 src pixels for each dest pixel.
664 * Break that down into 3 operations:
665 * 1. take two rows from source image and average them together.
666 * 2. take two rows from next source image and average them together.
667 * 3. take the two averaged rows and average them for the final dst row.
671 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
672 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
675 for (img
= 0; img
< dstDepthNB
; img
++) {
676 /* first source image pointer, skipping border */
677 const GLubyte
*imgSrcA
= srcPtr
678 + (bytesPerSrcImage
+ bytesPerSrcRow
+ border
) * bpt
* border
679 + img
* (bytesPerSrcImage
+ srcImageOffset
);
680 /* second source image pointer, skipping border */
681 const GLubyte
*imgSrcB
= imgSrcA
+ srcImageOffset
;
682 /* address of the dest image, skipping border */
683 GLubyte
*imgDst
= dstPtr
684 + (bytesPerDstImage
+ bytesPerDstRow
+ border
) * bpt
* border
685 + img
* bytesPerDstImage
;
687 /* setup the four source row pointers and the dest row pointer */
688 const GLubyte
*srcImgARowA
= imgSrcA
;
689 const GLubyte
*srcImgARowB
= imgSrcA
+ srcRowOffset
;
690 const GLubyte
*srcImgBRowA
= imgSrcB
;
691 const GLubyte
*srcImgBRowB
= imgSrcB
+ srcRowOffset
;
692 GLubyte
*dstImgRow
= imgDst
;
694 for (row
= 0; row
< dstHeightNB
; row
++) {
695 /* Average together two rows from first src image */
696 do_row(format
, srcWidthNB
, srcImgARowA
, srcImgARowB
,
697 srcWidthNB
, tmpRowA
);
698 /* Average together two rows from second src image */
699 do_row(format
, srcWidthNB
, srcImgBRowA
, srcImgBRowB
,
700 srcWidthNB
, tmpRowB
);
701 /* Average together the temp rows to make the final row */
702 do_row(format
, srcWidthNB
, tmpRowA
, tmpRowB
,
703 dstWidthNB
, dstImgRow
);
704 /* advance to next rows */
705 srcImgARowA
+= bytesPerSrcRow
+ srcRowOffset
;
706 srcImgARowB
+= bytesPerSrcRow
+ srcRowOffset
;
707 srcImgBRowA
+= bytesPerSrcRow
+ srcRowOffset
;
708 srcImgBRowB
+= bytesPerSrcRow
+ srcRowOffset
;
709 dstImgRow
+= bytesPerDstRow
;
716 /* Luckily we can leverage the make_2d_mipmap() function here! */
718 /* do front border image */
719 make_2d_mipmap(format
, 1, srcWidth
, srcHeight
, srcPtr
, srcRowStride
,
720 dstWidth
, dstHeight
, dstPtr
, dstRowStride
);
721 /* do back border image */
722 make_2d_mipmap(format
, 1, srcWidth
, srcHeight
,
723 srcPtr
+ bytesPerSrcImage
* (srcDepth
- 1), srcRowStride
,
725 dstPtr
+ bytesPerDstImage
* (dstDepth
- 1), dstRowStride
);
726 /* do four remaining border edges that span the image slices */
727 if (srcDepth
== dstDepth
) {
728 /* just copy border pixels from src to dst */
729 for (img
= 0; img
< dstDepthNB
; img
++) {
733 /* do border along [img][row=0][col=0] */
734 src
= srcPtr
+ (img
+ 1) * bytesPerSrcImage
;
735 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
736 MEMCPY(dst
, src
, bpt
);
738 /* do border along [img][row=dstHeight-1][col=0] */
739 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
740 + (srcHeight
- 1) * bytesPerSrcRow
;
741 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
742 + (dstHeight
- 1) * bytesPerDstRow
;
743 MEMCPY(dst
, src
, bpt
);
745 /* do border along [img][row=0][col=dstWidth-1] */
746 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
747 + (srcWidth
- 1) * bpt
;
748 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
749 + (dstWidth
- 1) * bpt
;
750 MEMCPY(dst
, src
, bpt
);
752 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
753 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
754 + (bytesPerSrcImage
- bpt
);
755 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
756 + (bytesPerDstImage
- bpt
);
757 MEMCPY(dst
, src
, bpt
);
761 /* average border pixels from adjacent src image pairs */
762 ASSERT(srcDepthNB
== 2 * dstDepthNB
);
763 for (img
= 0; img
< dstDepthNB
; img
++) {
767 /* do border along [img][row=0][col=0] */
768 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
;
769 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
770 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
772 /* do border along [img][row=dstHeight-1][col=0] */
773 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
774 + (srcHeight
- 1) * bytesPerSrcRow
;
775 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
776 + (dstHeight
- 1) * bytesPerDstRow
;
777 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
779 /* do border along [img][row=0][col=dstWidth-1] */
780 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
781 + (srcWidth
- 1) * bpt
;
782 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
783 + (dstWidth
- 1) * bpt
;
784 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
786 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
787 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
788 + (bytesPerSrcImage
- bpt
);
789 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
790 + (bytesPerDstImage
- bpt
);
791 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
799 make_1d_stack_mipmap(const struct gl_texture_format
*format
, GLint border
,
800 GLint srcWidth
, const GLubyte
*srcPtr
, GLuint srcRowStride
,
801 GLint dstWidth
, GLint dstHeight
,
802 GLubyte
*dstPtr
, GLuint dstRowStride
)
804 const GLint bpt
= format
->TexelBytes
;
805 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
806 const GLint dstWidthNB
= dstWidth
- 2 * border
;
807 const GLint dstHeightNB
= dstHeight
- 2 * border
;
808 const GLint srcRowBytes
= bpt
* srcRowStride
;
809 const GLint dstRowBytes
= bpt
* dstRowStride
;
814 /* Compute src and dst pointers, skipping any border */
815 src
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
816 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
818 for (row
= 0; row
< dstHeightNB
; row
++) {
819 do_row(format
, srcWidthNB
, src
, src
,
826 /* copy left-most pixel from source */
827 MEMCPY(dstPtr
, srcPtr
, bpt
);
828 /* copy right-most pixel from source */
829 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
830 srcPtr
+ (srcWidth
- 1) * bpt
,
838 * There is quite a bit of refactoring that could be done with this function
839 * and \c make_2d_mipmap.
842 make_2d_stack_mipmap(const struct gl_texture_format
*format
, GLint border
,
843 GLint srcWidth
, GLint srcHeight
,
844 const GLubyte
*srcPtr
, GLint srcRowStride
,
845 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
846 GLubyte
*dstPtr
, GLint dstRowStride
)
848 const GLint bpt
= format
->TexelBytes
;
849 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
850 const GLint dstWidthNB
= dstWidth
- 2 * border
;
851 const GLint dstHeightNB
= dstHeight
- 2 * border
;
852 const GLint dstDepthNB
= dstDepth
- 2 * border
;
853 const GLint srcRowBytes
= bpt
* srcRowStride
;
854 const GLint dstRowBytes
= bpt
* dstRowStride
;
855 const GLubyte
*srcA
, *srcB
;
860 /* Compute src and dst pointers, skipping any border */
861 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
863 srcB
= srcA
+ srcRowBytes
;
866 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
868 for (layer
= 0; layer
< dstDepthNB
; layer
++) {
869 for (row
= 0; row
< dstHeightNB
; row
++) {
870 do_row(format
, srcWidthNB
, srcA
, srcB
,
872 srcA
+= 2 * srcRowBytes
;
873 srcB
+= 2 * srcRowBytes
;
877 /* This is ugly but probably won't be used much */
879 /* fill in dest border */
880 /* lower-left border pixel */
881 MEMCPY(dstPtr
, srcPtr
, bpt
);
882 /* lower-right border pixel */
883 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
884 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
885 /* upper-left border pixel */
886 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
887 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
888 /* upper-right border pixel */
889 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
890 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
892 do_row(format
, srcWidthNB
,
895 dstWidthNB
, dstPtr
+ bpt
);
897 do_row(format
, srcWidthNB
,
898 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
899 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
901 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
902 /* left and right borders */
903 if (srcHeight
== dstHeight
) {
904 /* copy border pixel from src to dst */
905 for (row
= 1; row
< srcHeight
; row
++) {
906 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
907 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
908 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
909 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
913 /* average two src pixels each dest pixel */
914 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
916 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
917 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
918 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
920 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
921 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
922 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
931 * For GL_SGIX_generate_mipmap:
932 * Generate a complete set of mipmaps from texObj's base-level image.
933 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
936 _mesa_generate_mipmap(GLcontext
*ctx
, GLenum target
,
937 const struct gl_texture_unit
*texUnit
,
938 struct gl_texture_object
*texObj
)
940 const struct gl_texture_image
*srcImage
;
941 const struct gl_texture_format
*convertFormat
;
942 const GLubyte
*srcData
= NULL
;
943 GLubyte
*dstData
= NULL
;
944 GLint level
, maxLevels
;
947 /* XXX choose cube map face here??? */
948 srcImage
= texObj
->Image
[0][texObj
->BaseLevel
];
951 maxLevels
= _mesa_max_texture_levels(ctx
, texObj
->Target
);
952 ASSERT(maxLevels
> 0); /* bad target */
954 /* Find convertFormat - the format that do_row() will process */
955 if (srcImage
->IsCompressed
) {
956 /* setup for compressed textures */
958 GLint components
, size
;
961 assert(texObj
->Target
== GL_TEXTURE_2D
||
962 texObj
->Target
== GL_TEXTURE_CUBE_MAP_ARB
);
964 if (srcImage
->_BaseFormat
== GL_RGB
) {
965 convertFormat
= &_mesa_texformat_rgb
;
968 else if (srcImage
->_BaseFormat
== GL_RGBA
) {
969 convertFormat
= &_mesa_texformat_rgba
;
973 _mesa_problem(ctx
, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
977 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
978 size
= _mesa_bytes_per_pixel(srcImage
->_BaseFormat
, CHAN_TYPE
)
979 * srcImage
->Width
* srcImage
->Height
* srcImage
->Depth
+ 20;
980 /* 20 extra bytes, just be safe when calling last FetchTexel */
981 srcData
= (GLubyte
*) _mesa_malloc(size
);
983 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
986 dstData
= (GLubyte
*) _mesa_malloc(size
/ 2); /* 1/4 would probably be OK */
988 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
989 _mesa_free((void *) srcData
);
993 /* decompress base image here */
994 dst
= (GLchan
*) srcData
;
995 for (row
= 0; row
< srcImage
->Height
; row
++) {
997 for (col
= 0; col
< srcImage
->Width
; col
++) {
998 srcImage
->FetchTexelc(srcImage
, col
, row
, 0, dst
);
1005 convertFormat
= srcImage
->TexFormat
;
1008 for (level
= texObj
->BaseLevel
; level
< texObj
->MaxLevel
1009 && level
< maxLevels
- 1; level
++) {
1010 /* generate image[level+1] from image[level] */
1011 const struct gl_texture_image
*srcImage
;
1012 struct gl_texture_image
*dstImage
;
1013 GLint srcWidth
, srcHeight
, srcDepth
;
1014 GLint dstWidth
, dstHeight
, dstDepth
;
1015 GLint border
, bytesPerTexel
;
1017 /* get src image parameters */
1018 srcImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
1020 srcWidth
= srcImage
->Width
;
1021 srcHeight
= srcImage
->Height
;
1022 srcDepth
= srcImage
->Depth
;
1023 border
= srcImage
->Border
;
1025 /* compute next (level+1) image size */
1026 if (srcWidth
- 2 * border
> 1) {
1027 dstWidth
= (srcWidth
- 2 * border
) / 2 + 2 * border
;
1030 dstWidth
= srcWidth
; /* can't go smaller */
1032 if ((srcHeight
- 2 * border
> 1) &&
1033 (texObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
)) {
1034 dstHeight
= (srcHeight
- 2 * border
) / 2 + 2 * border
;
1037 dstHeight
= srcHeight
; /* can't go smaller */
1039 if ((srcDepth
- 2 * border
> 1) &&
1040 (texObj
->Target
!= GL_TEXTURE_2D_ARRAY_EXT
)) {
1041 dstDepth
= (srcDepth
- 2 * border
) / 2 + 2 * border
;
1044 dstDepth
= srcDepth
; /* can't go smaller */
1047 if (dstWidth
== srcWidth
&&
1048 dstHeight
== srcHeight
&&
1049 dstDepth
== srcDepth
) {
1051 if (srcImage
->IsCompressed
) {
1052 _mesa_free((void *) srcData
);
1053 _mesa_free(dstData
);
1058 /* get dest gl_texture_image */
1059 dstImage
= _mesa_get_tex_image(ctx
, texObj
, target
, level
+ 1);
1061 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1065 if (dstImage
->ImageOffsets
)
1066 _mesa_free(dstImage
->ImageOffsets
);
1068 /* Free old image data */
1070 ctx
->Driver
.FreeTexImageData(ctx
, dstImage
);
1072 /* initialize new image */
1073 _mesa_init_teximage_fields(ctx
, target
, dstImage
, dstWidth
, dstHeight
,
1074 dstDepth
, border
, srcImage
->InternalFormat
);
1075 dstImage
->DriverData
= NULL
;
1076 dstImage
->TexFormat
= srcImage
->TexFormat
;
1077 dstImage
->FetchTexelc
= srcImage
->FetchTexelc
;
1078 dstImage
->FetchTexelf
= srcImage
->FetchTexelf
;
1079 dstImage
->IsCompressed
= srcImage
->IsCompressed
;
1080 if (dstImage
->IsCompressed
) {
1081 dstImage
->CompressedSize
1082 = ctx
->Driver
.CompressedTextureSize(ctx
, dstImage
->Width
,
1085 dstImage
->TexFormat
->MesaFormat
);
1086 ASSERT(dstImage
->CompressedSize
> 0);
1089 ASSERT(dstImage
->TexFormat
);
1090 ASSERT(dstImage
->FetchTexelc
);
1091 ASSERT(dstImage
->FetchTexelf
);
1093 /* Alloc new teximage data buffer.
1094 * Setup src and dest data pointers.
1096 if (dstImage
->IsCompressed
) {
1097 dstImage
->Data
= _mesa_alloc_texmemory(dstImage
->CompressedSize
);
1098 if (!dstImage
->Data
) {
1099 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1102 /* srcData and dstData are already set */
1107 bytesPerTexel
= dstImage
->TexFormat
->TexelBytes
;
1108 ASSERT(dstWidth
* dstHeight
* dstDepth
* bytesPerTexel
> 0);
1109 dstImage
->Data
= _mesa_alloc_texmemory(dstWidth
* dstHeight
1110 * dstDepth
* bytesPerTexel
);
1111 if (!dstImage
->Data
) {
1112 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1115 srcData
= (const GLubyte
*) srcImage
->Data
;
1116 dstData
= (GLubyte
*) dstImage
->Data
;
1120 * We use simple 2x2 averaging to compute the next mipmap level.
1124 make_1d_mipmap(convertFormat
, border
,
1129 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
:
1130 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
:
1131 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
:
1132 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
:
1133 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
:
1134 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
:
1135 make_2d_mipmap(convertFormat
, border
,
1136 srcWidth
, srcHeight
, srcData
, srcImage
->RowStride
,
1137 dstWidth
, dstHeight
, dstData
, dstImage
->RowStride
);
1140 make_3d_mipmap(convertFormat
, border
,
1141 srcWidth
, srcHeight
, srcDepth
,
1142 srcData
, srcImage
->RowStride
,
1143 dstWidth
, dstHeight
, dstDepth
,
1144 dstData
, dstImage
->RowStride
);
1146 case GL_TEXTURE_1D_ARRAY_EXT
:
1147 make_1d_stack_mipmap(convertFormat
, border
,
1148 srcWidth
, srcData
, srcImage
->RowStride
,
1149 dstWidth
, dstHeight
,
1150 dstData
, dstImage
->RowStride
);
1152 case GL_TEXTURE_2D_ARRAY_EXT
:
1153 make_2d_stack_mipmap(convertFormat
, border
,
1154 srcWidth
, srcHeight
,
1155 srcData
, srcImage
->RowStride
,
1156 dstWidth
, dstHeight
,
1157 dstDepth
, dstData
, dstImage
->RowStride
);
1159 case GL_TEXTURE_RECTANGLE_NV
:
1160 /* no mipmaps, do nothing */
1163 _mesa_problem(ctx
, "bad dimensions in _mesa_generate_mipmaps");
1167 if (dstImage
->IsCompressed
) {
1169 /* compress image from dstData into dstImage->Data */
1170 const GLenum srcFormat
= convertFormat
->BaseFormat
;
1172 = _mesa_compressed_row_stride(dstImage
->TexFormat
->MesaFormat
, dstWidth
);
1173 ASSERT(srcFormat
== GL_RGB
|| srcFormat
== GL_RGBA
);
1174 dstImage
->TexFormat
->StoreImage(ctx
, 2, dstImage
->_BaseFormat
,
1175 dstImage
->TexFormat
,
1177 0, 0, 0, /* dstX/Y/Zoffset */
1178 dstRowStride
, 0, /* strides */
1179 dstWidth
, dstHeight
, 1, /* size */
1180 srcFormat
, CHAN_TYPE
,
1181 dstData
, /* src data, actually */
1182 &ctx
->DefaultPacking
);
1183 /* swap src and dest pointers */
1184 temp
= (GLubyte
*) srcData
;
1189 } /* loop over mipmap levels */
1194 * Helper function for drivers which need to rescale texture images to
1195 * certain aspect ratios.
1196 * Nearest filtering only (for broken hardware that can't support
1197 * all aspect ratios). This can be made a lot faster, but I don't
1198 * really care enough...
1201 _mesa_rescale_teximage2d(GLuint bytesPerPixel
,
1202 GLuint srcStrideInPixels
,
1203 GLuint dstRowStride
,
1204 GLint srcWidth
, GLint srcHeight
,
1205 GLint dstWidth
, GLint dstHeight
,
1206 const GLvoid
*srcImage
, GLvoid
*dstImage
)
1210 #define INNER_LOOP( TYPE, HOP, WOP ) \
1211 for ( row = 0 ; row < dstHeight ; row++ ) { \
1212 GLint srcRow = row HOP hScale; \
1213 for ( col = 0 ; col < dstWidth ; col++ ) { \
1214 GLint srcCol = col WOP wScale; \
1215 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1217 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1220 #define RESCALE_IMAGE( TYPE ) \
1222 const TYPE *src = (const TYPE *)srcImage; \
1223 TYPE *dst = (TYPE *)dstImage; \
1225 if ( srcHeight < dstHeight ) { \
1226 const GLint hScale = dstHeight / srcHeight; \
1227 if ( srcWidth < dstWidth ) { \
1228 const GLint wScale = dstWidth / srcWidth; \
1229 INNER_LOOP( TYPE, /, / ); \
1232 const GLint wScale = srcWidth / dstWidth; \
1233 INNER_LOOP( TYPE, /, * ); \
1237 const GLint hScale = srcHeight / dstHeight; \
1238 if ( srcWidth < dstWidth ) { \
1239 const GLint wScale = dstWidth / srcWidth; \
1240 INNER_LOOP( TYPE, *, / ); \
1243 const GLint wScale = srcWidth / dstWidth; \
1244 INNER_LOOP( TYPE, *, * ); \
1249 switch ( bytesPerPixel
) {
1251 RESCALE_IMAGE( GLuint
);
1255 RESCALE_IMAGE( GLushort
);
1259 RESCALE_IMAGE( GLubyte
);
1262 _mesa_problem(NULL
,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1268 * Upscale an image by replication, not (typical) stretching.
1269 * We use this when the image width or height is less than a
1270 * certain size (4, 8) and we need to upscale an image.
1273 _mesa_upscale_teximage2d(GLsizei inWidth
, GLsizei inHeight
,
1274 GLsizei outWidth
, GLsizei outHeight
,
1275 GLint comps
, const GLchan
*src
, GLint srcRowStride
,
1280 ASSERT(outWidth
>= inWidth
);
1281 ASSERT(outHeight
>= inHeight
);
1283 ASSERT(inWidth
== 1 || inWidth
== 2 || inHeight
== 1 || inHeight
== 2);
1284 ASSERT((outWidth
& 3) == 0);
1285 ASSERT((outHeight
& 3) == 0);
1288 for (i
= 0; i
< outHeight
; i
++) {
1289 const GLint ii
= i
% inHeight
;
1290 for (j
= 0; j
< outWidth
; j
++) {
1291 const GLint jj
= j
% inWidth
;
1292 for (k
= 0; k
< comps
; k
++) {
1293 dest
[(i
* outWidth
+ j
) * comps
+ k
]
1294 = src
[ii
* srcRowStride
+ jj
* comps
+ k
];