2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 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 * XXX need to use the tex image's row stride!
538 make_2d_mipmap(const struct gl_texture_format
*format
, GLint border
,
539 GLint srcWidth
, GLint srcHeight
, const GLubyte
*srcPtr
,
540 GLint dstWidth
, GLint dstHeight
, GLubyte
*dstPtr
)
542 const GLint bpt
= format
->TexelBytes
;
543 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
544 const GLint dstWidthNB
= dstWidth
- 2 * border
;
545 const GLint dstHeightNB
= dstHeight
- 2 * border
;
546 const GLint srcRowStride
= bpt
* srcWidth
;
547 const GLint dstRowStride
= bpt
* dstWidth
;
548 const GLubyte
*srcA
, *srcB
;
552 /* Compute src and dst pointers, skipping any border */
553 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
555 srcB
= srcA
+ srcRowStride
;
558 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
560 for (row
= 0; row
< dstHeightNB
; row
++) {
561 do_row(format
, srcWidthNB
, srcA
, srcB
,
563 srcA
+= 2 * srcRowStride
;
564 srcB
+= 2 * srcRowStride
;
568 /* This is ugly but probably won't be used much */
570 /* fill in dest border */
571 /* lower-left border pixel */
572 MEMCPY(dstPtr
, srcPtr
, bpt
);
573 /* lower-right border pixel */
574 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
575 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
576 /* upper-left border pixel */
577 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
578 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
579 /* upper-right border pixel */
580 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
581 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
583 do_row(format
, srcWidthNB
,
586 dstWidthNB
, dstPtr
+ bpt
);
588 do_row(format
, srcWidthNB
,
589 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
590 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
592 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
593 /* left and right borders */
594 if (srcHeight
== dstHeight
) {
595 /* copy border pixel from src to dst */
596 for (row
= 1; row
< srcHeight
; row
++) {
597 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
598 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
599 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
600 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
604 /* average two src pixels each dest pixel */
605 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
607 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
608 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
609 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
611 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
612 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
613 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
621 make_3d_mipmap(const struct gl_texture_format
*format
, GLint border
,
622 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
623 const GLubyte
*srcPtr
,
624 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
627 const GLint bpt
= format
->TexelBytes
;
628 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
629 const GLint srcDepthNB
= srcDepth
- 2 * border
;
630 const GLint dstWidthNB
= dstWidth
- 2 * border
;
631 const GLint dstHeightNB
= dstHeight
- 2 * border
;
632 const GLint dstDepthNB
= dstDepth
- 2 * border
;
633 GLvoid
*tmpRowA
, *tmpRowB
;
635 GLint bytesPerSrcImage
, bytesPerDstImage
;
636 GLint bytesPerSrcRow
, bytesPerDstRow
;
637 GLint srcImageOffset
, srcRowOffset
;
639 (void) srcDepthNB
; /* silence warnings */
641 /* Need two temporary row buffers */
642 tmpRowA
= _mesa_malloc(srcWidth
* bpt
);
645 tmpRowB
= _mesa_malloc(srcWidth
* bpt
);
651 bytesPerSrcImage
= srcWidth
* srcHeight
* bpt
;
652 bytesPerDstImage
= dstWidth
* dstHeight
* bpt
;
654 bytesPerSrcRow
= srcWidth
* bpt
;
655 bytesPerDstRow
= dstWidth
* bpt
;
657 /* Offset between adjacent src images to be averaged together */
658 srcImageOffset
= (srcDepth
== dstDepth
) ? 0 : bytesPerSrcImage
;
660 /* Offset between adjacent src rows to be averaged together */
661 srcRowOffset
= (srcHeight
== dstHeight
) ? 0 : srcWidth
* bpt
;
664 * Need to average together up to 8 src pixels for each dest pixel.
665 * Break that down into 3 operations:
666 * 1. take two rows from source image and average them together.
667 * 2. take two rows from next source image and average them together.
668 * 3. take the two averaged rows and average them for the final dst row.
672 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
673 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
676 for (img
= 0; img
< dstDepthNB
; img
++) {
677 /* first source image pointer, skipping border */
678 const GLubyte
*imgSrcA
= srcPtr
679 + (bytesPerSrcImage
+ bytesPerSrcRow
+ border
) * bpt
* border
680 + img
* (bytesPerSrcImage
+ srcImageOffset
);
681 /* second source image pointer, skipping border */
682 const GLubyte
*imgSrcB
= imgSrcA
+ srcImageOffset
;
683 /* address of the dest image, skipping border */
684 GLubyte
*imgDst
= dstPtr
685 + (bytesPerDstImage
+ bytesPerDstRow
+ border
) * bpt
* border
686 + img
* bytesPerDstImage
;
688 /* setup the four source row pointers and the dest row pointer */
689 const GLubyte
*srcImgARowA
= imgSrcA
;
690 const GLubyte
*srcImgARowB
= imgSrcA
+ srcRowOffset
;
691 const GLubyte
*srcImgBRowA
= imgSrcB
;
692 const GLubyte
*srcImgBRowB
= imgSrcB
+ srcRowOffset
;
693 GLubyte
*dstImgRow
= imgDst
;
695 for (row
= 0; row
< dstHeightNB
; row
++) {
696 /* Average together two rows from first src image */
697 do_row(format
, srcWidthNB
, srcImgARowA
, srcImgARowB
,
698 srcWidthNB
, tmpRowA
);
699 /* Average together two rows from second src image */
700 do_row(format
, srcWidthNB
, srcImgBRowA
, srcImgBRowB
,
701 srcWidthNB
, tmpRowB
);
702 /* Average together the temp rows to make the final row */
703 do_row(format
, srcWidthNB
, tmpRowA
, tmpRowB
,
704 dstWidthNB
, dstImgRow
);
705 /* advance to next rows */
706 srcImgARowA
+= bytesPerSrcRow
+ srcRowOffset
;
707 srcImgARowB
+= bytesPerSrcRow
+ srcRowOffset
;
708 srcImgBRowA
+= bytesPerSrcRow
+ srcRowOffset
;
709 srcImgBRowB
+= bytesPerSrcRow
+ srcRowOffset
;
710 dstImgRow
+= bytesPerDstRow
;
717 /* Luckily we can leverage the make_2d_mipmap() function here! */
719 /* do front border image */
720 make_2d_mipmap(format
, 1, srcWidth
, srcHeight
, srcPtr
,
721 dstWidth
, dstHeight
, dstPtr
);
722 /* do back border image */
723 make_2d_mipmap(format
, 1, srcWidth
, srcHeight
,
724 srcPtr
+ bytesPerSrcImage
* (srcDepth
- 1),
726 dstPtr
+ bytesPerDstImage
* (dstDepth
- 1));
727 /* do four remaining border edges that span the image slices */
728 if (srcDepth
== dstDepth
) {
729 /* just copy border pixels from src to dst */
730 for (img
= 0; img
< dstDepthNB
; img
++) {
734 /* do border along [img][row=0][col=0] */
735 src
= srcPtr
+ (img
+ 1) * bytesPerSrcImage
;
736 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
737 MEMCPY(dst
, src
, bpt
);
739 /* do border along [img][row=dstHeight-1][col=0] */
740 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
741 + (srcHeight
- 1) * bytesPerSrcRow
;
742 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
743 + (dstHeight
- 1) * bytesPerDstRow
;
744 MEMCPY(dst
, src
, bpt
);
746 /* do border along [img][row=0][col=dstWidth-1] */
747 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
748 + (srcWidth
- 1) * bpt
;
749 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
750 + (dstWidth
- 1) * bpt
;
751 MEMCPY(dst
, src
, bpt
);
753 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
754 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
755 + (bytesPerSrcImage
- bpt
);
756 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
757 + (bytesPerDstImage
- bpt
);
758 MEMCPY(dst
, src
, bpt
);
762 /* average border pixels from adjacent src image pairs */
763 ASSERT(srcDepthNB
== 2 * dstDepthNB
);
764 for (img
= 0; img
< dstDepthNB
; img
++) {
768 /* do border along [img][row=0][col=0] */
769 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
;
770 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
771 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
773 /* do border along [img][row=dstHeight-1][col=0] */
774 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
775 + (srcHeight
- 1) * bytesPerSrcRow
;
776 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
777 + (dstHeight
- 1) * bytesPerDstRow
;
778 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
780 /* do border along [img][row=0][col=dstWidth-1] */
781 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
782 + (srcWidth
- 1) * bpt
;
783 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
784 + (dstWidth
- 1) * bpt
;
785 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
787 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
788 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
789 + (bytesPerSrcImage
- bpt
);
790 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
791 + (bytesPerDstImage
- bpt
);
792 do_row(format
, 1, src
, src
+ srcImageOffset
, 1, dst
);
800 make_1d_stack_mipmap(const struct gl_texture_format
*format
, GLint border
,
801 GLint srcWidth
, GLubyte
*srcPtr
,
802 GLint dstWidth
, GLint dstHeight
, GLubyte
*dstPtr
)
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 srcRowStride
= bpt
* srcWidth
;
809 const GLint dstRowStride
= bpt
* dstWidth
;
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
, const GLubyte
*srcPtr
,
844 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
847 const GLint bpt
= format
->TexelBytes
;
848 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
849 const GLint dstWidthNB
= dstWidth
- 2 * border
;
850 const GLint dstHeightNB
= dstHeight
- 2 * border
;
851 const GLint dstDepthNB
= dstDepth
- 2 * border
;
852 const GLint srcRowStride
= bpt
* srcWidth
;
853 const GLint dstRowStride
= bpt
* dstWidth
;
854 const GLubyte
*srcA
, *srcB
;
859 /* Compute src and dst pointers, skipping any border */
860 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
862 srcB
= srcA
+ srcRowStride
;
865 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
867 for (layer
= 0; layer
< dstDepthNB
; layer
++) {
868 for (row
= 0; row
< dstHeightNB
; row
++) {
869 do_row(format
, srcWidthNB
, srcA
, srcB
,
871 srcA
+= 2 * srcRowStride
;
872 srcB
+= 2 * srcRowStride
;
876 /* This is ugly but probably won't be used much */
878 /* fill in dest border */
879 /* lower-left border pixel */
880 MEMCPY(dstPtr
, srcPtr
, bpt
);
881 /* lower-right border pixel */
882 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
883 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
884 /* upper-left border pixel */
885 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
886 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
887 /* upper-right border pixel */
888 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
889 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
891 do_row(format
, srcWidthNB
,
894 dstWidthNB
, dstPtr
+ bpt
);
896 do_row(format
, srcWidthNB
,
897 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
898 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
900 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
901 /* left and right borders */
902 if (srcHeight
== dstHeight
) {
903 /* copy border pixel from src to dst */
904 for (row
= 1; row
< srcHeight
; row
++) {
905 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
906 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
907 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
908 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
912 /* average two src pixels each dest pixel */
913 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
915 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
916 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
917 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
919 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
920 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
921 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
930 * For GL_SGIX_generate_mipmap:
931 * Generate a complete set of mipmaps from texObj's base-level image.
932 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
935 _mesa_generate_mipmap(GLcontext
*ctx
, GLenum target
,
936 const struct gl_texture_unit
*texUnit
,
937 struct gl_texture_object
*texObj
)
939 const struct gl_texture_image
*srcImage
;
940 const struct gl_texture_format
*convertFormat
;
941 const GLubyte
*srcData
= NULL
;
942 GLubyte
*dstData
= NULL
;
943 GLint level
, maxLevels
;
946 /* XXX choose cube map face here??? */
947 srcImage
= texObj
->Image
[0][texObj
->BaseLevel
];
950 maxLevels
= _mesa_max_texture_levels(ctx
, texObj
->Target
);
951 ASSERT(maxLevels
> 0); /* bad target */
953 /* Find convertFormat - the format that do_row() will process */
954 if (srcImage
->IsCompressed
) {
955 /* setup for compressed textures */
957 GLint components
, size
;
960 assert(texObj
->Target
== GL_TEXTURE_2D
);
962 if (srcImage
->_BaseFormat
== GL_RGB
) {
963 convertFormat
= &_mesa_texformat_rgb
;
966 else if (srcImage
->_BaseFormat
== GL_RGBA
) {
967 convertFormat
= &_mesa_texformat_rgba
;
971 _mesa_problem(ctx
, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
975 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
976 size
= _mesa_bytes_per_pixel(srcImage
->_BaseFormat
, CHAN_TYPE
)
977 * srcImage
->Width
* srcImage
->Height
* srcImage
->Depth
+ 20;
978 /* 20 extra bytes, just be safe when calling last FetchTexel */
979 srcData
= (GLubyte
*) _mesa_malloc(size
);
981 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
984 dstData
= (GLubyte
*) _mesa_malloc(size
/ 2); /* 1/4 would probably be OK */
986 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
987 _mesa_free((void *) srcData
);
991 /* decompress base image here */
992 dst
= (GLchan
*) srcData
;
993 for (row
= 0; row
< srcImage
->Height
; row
++) {
995 for (col
= 0; col
< srcImage
->Width
; col
++) {
996 srcImage
->FetchTexelc(srcImage
, col
, row
, 0, dst
);
1003 convertFormat
= srcImage
->TexFormat
;
1006 for (level
= texObj
->BaseLevel
; level
< texObj
->MaxLevel
1007 && level
< maxLevels
- 1; level
++) {
1008 /* generate image[level+1] from image[level] */
1009 const struct gl_texture_image
*srcImage
;
1010 struct gl_texture_image
*dstImage
;
1011 GLint srcWidth
, srcHeight
, srcDepth
;
1012 GLint dstWidth
, dstHeight
, dstDepth
;
1013 GLint border
, bytesPerTexel
;
1015 /* get src image parameters */
1016 srcImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
1018 srcWidth
= srcImage
->Width
;
1019 srcHeight
= srcImage
->Height
;
1020 srcDepth
= srcImage
->Depth
;
1021 border
= srcImage
->Border
;
1023 /* compute next (level+1) image size */
1024 if (srcWidth
- 2 * border
> 1) {
1025 dstWidth
= (srcWidth
- 2 * border
) / 2 + 2 * border
;
1028 dstWidth
= srcWidth
; /* can't go smaller */
1030 if ((srcHeight
- 2 * border
> 1) &&
1031 (texObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
)) {
1032 dstHeight
= (srcHeight
- 2 * border
) / 2 + 2 * border
;
1035 dstHeight
= srcHeight
; /* can't go smaller */
1037 if ((srcDepth
- 2 * border
> 1) &&
1038 (texObj
->Target
!= GL_TEXTURE_2D_ARRAY_EXT
)) {
1039 dstDepth
= (srcDepth
- 2 * border
) / 2 + 2 * border
;
1042 dstDepth
= srcDepth
; /* can't go smaller */
1045 if (dstWidth
== srcWidth
&&
1046 dstHeight
== srcHeight
&&
1047 dstDepth
== srcDepth
) {
1049 if (srcImage
->IsCompressed
) {
1050 _mesa_free((void *) srcData
);
1051 _mesa_free(dstData
);
1056 /* get dest gl_texture_image */
1057 dstImage
= _mesa_get_tex_image(ctx
, texObj
, target
, level
+ 1);
1059 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1063 if (dstImage
->ImageOffsets
)
1064 _mesa_free(dstImage
->ImageOffsets
);
1066 /* Free old image data */
1068 ctx
->Driver
.FreeTexImageData(ctx
, dstImage
);
1070 /* initialize new image */
1071 _mesa_init_teximage_fields(ctx
, target
, dstImage
, dstWidth
, dstHeight
,
1072 dstDepth
, border
, srcImage
->InternalFormat
);
1073 dstImage
->DriverData
= NULL
;
1074 dstImage
->TexFormat
= srcImage
->TexFormat
;
1075 dstImage
->FetchTexelc
= srcImage
->FetchTexelc
;
1076 dstImage
->FetchTexelf
= srcImage
->FetchTexelf
;
1077 dstImage
->IsCompressed
= srcImage
->IsCompressed
;
1078 if (dstImage
->IsCompressed
) {
1079 dstImage
->CompressedSize
1080 = ctx
->Driver
.CompressedTextureSize(ctx
, dstImage
->Width
,
1083 dstImage
->TexFormat
->MesaFormat
);
1084 ASSERT(dstImage
->CompressedSize
> 0);
1087 ASSERT(dstImage
->TexFormat
);
1088 ASSERT(dstImage
->FetchTexelc
);
1089 ASSERT(dstImage
->FetchTexelf
);
1091 /* Alloc new teximage data buffer.
1092 * Setup src and dest data pointers.
1094 if (dstImage
->IsCompressed
) {
1095 dstImage
->Data
= _mesa_alloc_texmemory(dstImage
->CompressedSize
);
1096 if (!dstImage
->Data
) {
1097 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1100 /* srcData and dstData are already set */
1105 bytesPerTexel
= dstImage
->TexFormat
->TexelBytes
;
1106 ASSERT(dstWidth
* dstHeight
* dstDepth
* bytesPerTexel
> 0);
1107 dstImage
->Data
= _mesa_alloc_texmemory(dstWidth
* dstHeight
1108 * dstDepth
* bytesPerTexel
);
1109 if (!dstImage
->Data
) {
1110 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1113 srcData
= (const GLubyte
*) srcImage
->Data
;
1114 dstData
= (GLubyte
*) dstImage
->Data
;
1118 * We use simple 2x2 averaging to compute the next mipmap level.
1122 make_1d_mipmap(convertFormat
, border
,
1127 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
:
1128 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
:
1129 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
:
1130 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
:
1131 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
:
1132 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
:
1133 make_2d_mipmap(convertFormat
, border
,
1134 srcWidth
, srcHeight
, srcData
,
1135 dstWidth
, dstHeight
, dstData
);
1138 make_3d_mipmap(convertFormat
, border
,
1139 srcWidth
, srcHeight
, srcDepth
, srcData
,
1140 dstWidth
, dstHeight
, dstDepth
, dstData
);
1142 case GL_TEXTURE_1D_ARRAY_EXT
:
1143 make_1d_stack_mipmap(convertFormat
, border
,
1145 dstWidth
, dstHeight
, dstData
);
1147 case GL_TEXTURE_2D_ARRAY_EXT
:
1148 make_2d_stack_mipmap(convertFormat
, border
,
1149 srcWidth
, srcHeight
, srcData
,
1150 dstWidth
, dstHeight
, dstDepth
, dstData
);
1152 case GL_TEXTURE_RECTANGLE_NV
:
1153 /* no mipmaps, do nothing */
1156 _mesa_problem(ctx
, "bad dimensions in _mesa_generate_mipmaps");
1160 if (dstImage
->IsCompressed
) {
1162 /* compress image from dstData into dstImage->Data */
1163 const GLenum srcFormat
= convertFormat
->BaseFormat
;
1165 = _mesa_compressed_row_stride(dstImage
->TexFormat
->MesaFormat
, dstWidth
);
1166 ASSERT(srcFormat
== GL_RGB
|| srcFormat
== GL_RGBA
);
1167 dstImage
->TexFormat
->StoreImage(ctx
, 2, dstImage
->_BaseFormat
,
1168 dstImage
->TexFormat
,
1170 0, 0, 0, /* dstX/Y/Zoffset */
1171 dstRowStride
, 0, /* strides */
1172 dstWidth
, dstHeight
, 1, /* size */
1173 srcFormat
, CHAN_TYPE
,
1174 dstData
, /* src data, actually */
1175 &ctx
->DefaultPacking
);
1176 /* swap src and dest pointers */
1177 temp
= (GLubyte
*) srcData
;
1182 } /* loop over mipmap levels */
1187 * Helper function for drivers which need to rescale texture images to
1188 * certain aspect ratios.
1189 * Nearest filtering only (for broken hardware that can't support
1190 * all aspect ratios). This can be made a lot faster, but I don't
1191 * really care enough...
1194 _mesa_rescale_teximage2d(GLuint bytesPerPixel
,
1195 GLuint srcStrideInPixels
,
1196 GLuint dstRowStride
,
1197 GLint srcWidth
, GLint srcHeight
,
1198 GLint dstWidth
, GLint dstHeight
,
1199 const GLvoid
*srcImage
, GLvoid
*dstImage
)
1203 #define INNER_LOOP( TYPE, HOP, WOP ) \
1204 for ( row = 0 ; row < dstHeight ; row++ ) { \
1205 GLint srcRow = row HOP hScale; \
1206 for ( col = 0 ; col < dstWidth ; col++ ) { \
1207 GLint srcCol = col WOP wScale; \
1208 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1210 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1213 #define RESCALE_IMAGE( TYPE ) \
1215 const TYPE *src = (const TYPE *)srcImage; \
1216 TYPE *dst = (TYPE *)dstImage; \
1218 if ( srcHeight < dstHeight ) { \
1219 const GLint hScale = dstHeight / srcHeight; \
1220 if ( srcWidth < dstWidth ) { \
1221 const GLint wScale = dstWidth / srcWidth; \
1222 INNER_LOOP( TYPE, /, / ); \
1225 const GLint wScale = srcWidth / dstWidth; \
1226 INNER_LOOP( TYPE, /, * ); \
1230 const GLint hScale = srcHeight / dstHeight; \
1231 if ( srcWidth < dstWidth ) { \
1232 const GLint wScale = dstWidth / srcWidth; \
1233 INNER_LOOP( TYPE, *, / ); \
1236 const GLint wScale = srcWidth / dstWidth; \
1237 INNER_LOOP( TYPE, *, * ); \
1242 switch ( bytesPerPixel
) {
1244 RESCALE_IMAGE( GLuint
);
1248 RESCALE_IMAGE( GLushort
);
1252 RESCALE_IMAGE( GLubyte
);
1255 _mesa_problem(NULL
,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1261 * Upscale an image by replication, not (typical) stretching.
1262 * We use this when the image width or height is less than a
1263 * certain size (4, 8) and we need to upscale an image.
1266 _mesa_upscale_teximage2d(GLsizei inWidth
, GLsizei inHeight
,
1267 GLsizei outWidth
, GLsizei outHeight
,
1268 GLint comps
, const GLchan
*src
, GLint srcRowStride
,
1273 ASSERT(outWidth
>= inWidth
);
1274 ASSERT(outHeight
>= inHeight
);
1276 ASSERT(inWidth
== 1 || inWidth
== 2 || inHeight
== 1 || inHeight
== 2);
1277 ASSERT((outWidth
& 3) == 0);
1278 ASSERT((outHeight
& 3) == 0);
1281 for (i
= 0; i
< outHeight
; i
++) {
1282 const GLint ii
= i
% inHeight
;
1283 for (j
= 0; j
< outWidth
; j
++) {
1284 const GLint jj
= j
% inWidth
;
1285 for (k
= 0; k
< comps
; k
++) {
1286 dest
[(i
* outWidth
+ j
) * comps
+ k
]
1287 = src
[ii
* srcRowStride
+ jj
* comps
+ k
];