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 * For GL_SGIX_generate_mipmap:
801 * Generate a complete set of mipmaps from texObj's base-level image.
802 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
805 _mesa_generate_mipmap(GLcontext
*ctx
, GLenum target
,
806 const struct gl_texture_unit
*texUnit
,
807 struct gl_texture_object
*texObj
)
809 const struct gl_texture_image
*srcImage
;
810 const struct gl_texture_format
*convertFormat
;
811 const GLubyte
*srcData
= NULL
;
812 GLubyte
*dstData
= NULL
;
813 GLint level
, maxLevels
;
816 /* XXX choose cube map face here??? */
817 srcImage
= texObj
->Image
[0][texObj
->BaseLevel
];
820 maxLevels
= _mesa_max_texture_levels(ctx
, texObj
->Target
);
821 ASSERT(maxLevels
> 0); /* bad target */
823 /* Find convertFormat - the format that do_row() will process */
824 if (srcImage
->IsCompressed
) {
825 /* setup for compressed textures */
827 GLint components
, size
;
830 assert(texObj
->Target
== GL_TEXTURE_2D
);
832 if (srcImage
->_BaseFormat
== GL_RGB
) {
833 convertFormat
= &_mesa_texformat_rgb
;
836 else if (srcImage
->_BaseFormat
== GL_RGBA
) {
837 convertFormat
= &_mesa_texformat_rgba
;
841 _mesa_problem(ctx
, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
845 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
846 size
= _mesa_bytes_per_pixel(srcImage
->_BaseFormat
, CHAN_TYPE
)
847 * srcImage
->Width
* srcImage
->Height
* srcImage
->Depth
+ 20;
848 /* 20 extra bytes, just be safe when calling last FetchTexel */
849 srcData
= (GLubyte
*) _mesa_malloc(size
);
851 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
854 dstData
= (GLubyte
*) _mesa_malloc(size
/ 2); /* 1/4 would probably be OK */
856 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
857 _mesa_free((void *) srcData
);
861 /* decompress base image here */
862 dst
= (GLchan
*) srcData
;
863 for (row
= 0; row
< srcImage
->Height
; row
++) {
865 for (col
= 0; col
< srcImage
->Width
; col
++) {
866 srcImage
->FetchTexelc(srcImage
, col
, row
, 0, dst
);
873 convertFormat
= srcImage
->TexFormat
;
876 for (level
= texObj
->BaseLevel
; level
< texObj
->MaxLevel
877 && level
< maxLevels
- 1; level
++) {
878 /* generate image[level+1] from image[level] */
879 const struct gl_texture_image
*srcImage
;
880 struct gl_texture_image
*dstImage
;
881 GLint srcWidth
, srcHeight
, srcDepth
;
882 GLint dstWidth
, dstHeight
, dstDepth
;
883 GLint border
, bytesPerTexel
;
885 /* get src image parameters */
886 srcImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
888 srcWidth
= srcImage
->Width
;
889 srcHeight
= srcImage
->Height
;
890 srcDepth
= srcImage
->Depth
;
891 border
= srcImage
->Border
;
893 /* compute next (level+1) image size */
894 if (srcWidth
- 2 * border
> 1) {
895 dstWidth
= (srcWidth
- 2 * border
) / 2 + 2 * border
;
898 dstWidth
= srcWidth
; /* can't go smaller */
900 if (srcHeight
- 2 * border
> 1) {
901 dstHeight
= (srcHeight
- 2 * border
) / 2 + 2 * border
;
904 dstHeight
= srcHeight
; /* can't go smaller */
906 if (srcDepth
- 2 * border
> 1) {
907 dstDepth
= (srcDepth
- 2 * border
) / 2 + 2 * border
;
910 dstDepth
= srcDepth
; /* can't go smaller */
913 if (dstWidth
== srcWidth
&&
914 dstHeight
== srcHeight
&&
915 dstDepth
== srcDepth
) {
917 if (srcImage
->IsCompressed
) {
918 _mesa_free((void *) srcData
);
924 /* get dest gl_texture_image */
925 dstImage
= _mesa_get_tex_image(ctx
, texObj
, target
, level
+ 1);
927 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
931 /* Free old image data */
933 ctx
->Driver
.FreeTexImageData(ctx
, dstImage
);
935 /* initialize new image */
936 _mesa_init_teximage_fields(ctx
, target
, dstImage
, dstWidth
, dstHeight
,
937 dstDepth
, border
, srcImage
->InternalFormat
);
938 dstImage
->DriverData
= NULL
;
939 dstImage
->TexFormat
= srcImage
->TexFormat
;
940 dstImage
->FetchTexelc
= srcImage
->FetchTexelc
;
941 dstImage
->FetchTexelf
= srcImage
->FetchTexelf
;
942 dstImage
->IsCompressed
= srcImage
->IsCompressed
;
943 if (dstImage
->IsCompressed
) {
944 dstImage
->CompressedSize
945 = ctx
->Driver
.CompressedTextureSize(ctx
, dstImage
->Width
,
948 dstImage
->TexFormat
->MesaFormat
);
949 ASSERT(dstImage
->CompressedSize
> 0);
952 ASSERT(dstImage
->TexFormat
);
953 ASSERT(dstImage
->FetchTexelc
);
954 ASSERT(dstImage
->FetchTexelf
);
956 /* Alloc new teximage data buffer.
957 * Setup src and dest data pointers.
959 if (dstImage
->IsCompressed
) {
960 dstImage
->Data
= _mesa_alloc_texmemory(dstImage
->CompressedSize
);
961 if (!dstImage
->Data
) {
962 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
965 /* srcData and dstData are already set */
970 bytesPerTexel
= dstImage
->TexFormat
->TexelBytes
;
971 ASSERT(dstWidth
* dstHeight
* dstDepth
* bytesPerTexel
> 0);
972 dstImage
->Data
= _mesa_alloc_texmemory(dstWidth
* dstHeight
973 * dstDepth
* bytesPerTexel
);
974 if (!dstImage
->Data
) {
975 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
978 srcData
= (const GLubyte
*) srcImage
->Data
;
979 dstData
= (GLubyte
*) dstImage
->Data
;
983 * We use simple 2x2 averaging to compute the next mipmap level.
987 make_1d_mipmap(convertFormat
, border
,
992 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
:
993 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
:
994 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
:
995 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
:
996 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
:
997 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
:
998 make_2d_mipmap(convertFormat
, border
,
999 srcWidth
, srcHeight
, srcData
,
1000 dstWidth
, dstHeight
, dstData
);
1003 make_3d_mipmap(convertFormat
, border
,
1004 srcWidth
, srcHeight
, srcDepth
, srcData
,
1005 dstWidth
, dstHeight
, dstDepth
, dstData
);
1007 case GL_TEXTURE_RECTANGLE_NV
:
1008 /* no mipmaps, do nothing */
1011 _mesa_problem(ctx
, "bad dimensions in _mesa_generate_mipmaps");
1015 if (dstImage
->IsCompressed
) {
1017 /* compress image from dstData into dstImage->Data */
1018 const GLenum srcFormat
= convertFormat
->BaseFormat
;
1020 = _mesa_compressed_row_stride(dstImage
->TexFormat
->MesaFormat
, dstWidth
);
1021 ASSERT(srcFormat
== GL_RGB
|| srcFormat
== GL_RGBA
);
1022 dstImage
->TexFormat
->StoreImage(ctx
, 2, dstImage
->_BaseFormat
,
1023 dstImage
->TexFormat
,
1025 0, 0, 0, /* dstX/Y/Zoffset */
1026 dstRowStride
, 0, /* strides */
1027 dstWidth
, dstHeight
, 1, /* size */
1028 srcFormat
, CHAN_TYPE
,
1029 dstData
, /* src data, actually */
1030 &ctx
->DefaultPacking
);
1031 /* swap src and dest pointers */
1032 temp
= (GLubyte
*) srcData
;
1037 } /* loop over mipmap levels */
1042 * Helper function for drivers which need to rescale texture images to
1043 * certain aspect ratios.
1044 * Nearest filtering only (for broken hardware that can't support
1045 * all aspect ratios). This can be made a lot faster, but I don't
1046 * really care enough...
1049 _mesa_rescale_teximage2d(GLuint bytesPerPixel
,
1050 GLuint srcStrideInPixels
,
1051 GLuint dstRowStride
,
1052 GLint srcWidth
, GLint srcHeight
,
1053 GLint dstWidth
, GLint dstHeight
,
1054 const GLvoid
*srcImage
, GLvoid
*dstImage
)
1058 #define INNER_LOOP( TYPE, HOP, WOP ) \
1059 for ( row = 0 ; row < dstHeight ; row++ ) { \
1060 GLint srcRow = row HOP hScale; \
1061 for ( col = 0 ; col < dstWidth ; col++ ) { \
1062 GLint srcCol = col WOP wScale; \
1063 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1065 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1068 #define RESCALE_IMAGE( TYPE ) \
1070 const TYPE *src = (const TYPE *)srcImage; \
1071 TYPE *dst = (TYPE *)dstImage; \
1073 if ( srcHeight < dstHeight ) { \
1074 const GLint hScale = dstHeight / srcHeight; \
1075 if ( srcWidth < dstWidth ) { \
1076 const GLint wScale = dstWidth / srcWidth; \
1077 INNER_LOOP( TYPE, /, / ); \
1080 const GLint wScale = srcWidth / dstWidth; \
1081 INNER_LOOP( TYPE, /, * ); \
1085 const GLint hScale = srcHeight / dstHeight; \
1086 if ( srcWidth < dstWidth ) { \
1087 const GLint wScale = dstWidth / srcWidth; \
1088 INNER_LOOP( TYPE, *, / ); \
1091 const GLint wScale = srcWidth / dstWidth; \
1092 INNER_LOOP( TYPE, *, * ); \
1097 switch ( bytesPerPixel
) {
1099 RESCALE_IMAGE( GLuint
);
1103 RESCALE_IMAGE( GLushort
);
1107 RESCALE_IMAGE( GLubyte
);
1110 _mesa_problem(NULL
,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1116 * Upscale an image by replication, not (typical) stretching.
1117 * We use this when the image width or height is less than a
1118 * certain size (4, 8) and we need to upscale an image.
1121 _mesa_upscale_teximage2d(GLsizei inWidth
, GLsizei inHeight
,
1122 GLsizei outWidth
, GLsizei outHeight
,
1123 GLint comps
, const GLchan
*src
, GLint srcRowStride
,
1128 ASSERT(outWidth
>= inWidth
);
1129 ASSERT(outHeight
>= inHeight
);
1131 ASSERT(inWidth
== 1 || inWidth
== 2 || inHeight
== 1 || inHeight
== 2);
1132 ASSERT((outWidth
& 3) == 0);
1133 ASSERT((outHeight
& 3) == 0);
1136 for (i
= 0; i
< outHeight
; i
++) {
1137 const GLint ii
= i
% inHeight
;
1138 for (j
= 0; j
< outWidth
; j
++) {
1139 const GLint jj
= j
% inWidth
;
1140 for (k
= 0; k
< comps
; k
++) {
1141 dest
[(i
* outWidth
+ j
) * comps
+ k
]
1142 = src
[ii
* srcRowStride
+ jj
* comps
+ k
];