Merge branch 'master' into autoconf2
[mesa.git] / src / mesa / main / mipmap.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25
26 /**
27 * \file mipmap.c mipmap generation and teximage resizing functions.
28 */
29
30 #include "imports.h"
31 #include "mipmap.h"
32 #include "texcompress.h"
33 #include "texformat.h"
34 #include "teximage.h"
35 #include "image.h"
36
37
38
39 /**
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.
44 */
45 static void
46 do_row(const struct gl_texture_format *format, GLint srcWidth,
47 const GLvoid *srcRowA, const GLvoid *srcRowB,
48 GLint dstWidth, GLvoid *dstRow)
49 {
50 const GLuint k0 = (srcWidth == dstWidth) ? 0 : 1;
51 const GLuint colStride = (srcWidth == dstWidth) ? 1 : 2;
52
53 /* This assertion is no longer valid with non-power-of-2 textures
54 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
55 */
56
57 switch (format->MesaFormat) {
58 case MESA_FORMAT_RGBA:
59 {
60 GLuint i, j, k;
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;
74 }
75 }
76 return;
77 case MESA_FORMAT_RGB:
78 {
79 GLuint i, j, k;
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;
91 }
92 }
93 return;
94 case MESA_FORMAT_ALPHA:
95 case MESA_FORMAT_LUMINANCE:
96 case MESA_FORMAT_INTENSITY:
97 {
98 GLuint i, j, k;
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;
105 }
106 }
107 return;
108 case MESA_FORMAT_LUMINANCE_ALPHA:
109 {
110 GLuint i, j, k;
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;
120 }
121 }
122 return;
123 case MESA_FORMAT_Z32:
124 {
125 GLuint i, j, k;
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;
132 }
133 }
134 return;
135 case MESA_FORMAT_Z16:
136 {
137 GLuint i, j, k;
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;
144 }
145 }
146 return;
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:
154 #endif
155 {
156 GLuint i, j, k;
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;
170 }
171 }
172 return;
173 case MESA_FORMAT_RGB888:
174 case MESA_FORMAT_BGR888:
175 #if FEATURE_EXT_texture_sRGB
176 case MESA_FORMAT_SRGB8:
177 #endif
178 {
179 GLuint i, j, k;
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;
191 }
192 }
193 return;
194 case MESA_FORMAT_RGB565:
195 case MESA_FORMAT_RGB565_REV:
196 {
197 GLuint i, j, k;
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;
219 }
220 }
221 return;
222 case MESA_FORMAT_ARGB4444:
223 case MESA_FORMAT_ARGB4444_REV:
224 {
225 GLuint i, j, k;
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;
252 }
253 }
254 return;
255 case MESA_FORMAT_ARGB1555:
256 case MESA_FORMAT_ARGB1555_REV: /* XXX broken? */
257 {
258 GLuint i, j, k;
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;
285 }
286 }
287 return;
288 case MESA_FORMAT_AL88:
289 case MESA_FORMAT_AL88_REV:
290 #if FEATURE_EXT_texture_sRGB
291 case MESA_FORMAT_SLA8:
292 #endif
293 {
294 GLuint i, j, k;
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;
304 }
305 }
306 return;
307 case MESA_FORMAT_RGB332:
308 {
309 GLuint i, j, k;
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;
331 }
332 }
333 return;
334 case MESA_FORMAT_A8:
335 case MESA_FORMAT_L8:
336 case MESA_FORMAT_I8:
337 case MESA_FORMAT_CI8:
338 #if FEATURE_EXT_texture_sRGB
339 case MESA_FORMAT_SL8:
340 #endif
341 {
342 GLuint i, j, k;
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;
349 }
350 }
351 return;
352 case MESA_FORMAT_RGBA_FLOAT32:
353 {
354 GLuint i, j, k;
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;
368 }
369 }
370 return;
371 case MESA_FORMAT_RGBA_FLOAT16:
372 {
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);
386 }
387 }
388 }
389 return;
390 case MESA_FORMAT_RGB_FLOAT32:
391 {
392 GLuint i, j, k;
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;
404 }
405 }
406 return;
407 case MESA_FORMAT_RGB_FLOAT16:
408 {
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);
422 }
423 }
424 }
425 return;
426 case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32:
427 {
428 GLuint i, j, k;
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;
438 }
439 }
440 return;
441 case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16:
442 {
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);
456 }
457 }
458 }
459 return;
460 case MESA_FORMAT_ALPHA_FLOAT32:
461 case MESA_FORMAT_LUMINANCE_FLOAT32:
462 case MESA_FORMAT_INTENSITY_FLOAT32:
463 {
464 GLuint i, j, k;
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;
471 }
472 }
473 return;
474 case MESA_FORMAT_ALPHA_FLOAT16:
475 case MESA_FORMAT_LUMINANCE_FLOAT16:
476 case MESA_FORMAT_INTENSITY_FLOAT16:
477 {
478 GLuint i, j, k;
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);
490 }
491 }
492 return;
493
494 default:
495 _mesa_problem(NULL, "bad format in do_row()");
496 }
497 }
498
499
500 /*
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.
504 */
505
506 static void
507 make_1d_mipmap(const struct gl_texture_format *format, GLint border,
508 GLint srcWidth, const GLubyte *srcPtr,
509 GLint dstWidth, GLubyte *dstPtr)
510 {
511 const GLint bpt = format->TexelBytes;
512 const GLubyte *src;
513 GLubyte *dst;
514
515 /* skip the border pixel, if any */
516 src = srcPtr + border * bpt;
517 dst = dstPtr + border * bpt;
518
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);
522
523 if (border) {
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,
529 bpt);
530 }
531 }
532
533
534 static void
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)
540 {
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;
548 GLubyte *dst;
549 GLint row;
550
551 /* Compute src and dst pointers, skipping any border */
552 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
553 if (srcHeight > 1)
554 srcB = srcA + srcRowBytes;
555 else
556 srcB = srcA;
557 dst = dstPtr + border * ((dstWidth + 1) * bpt);
558
559 for (row = 0; row < dstHeightNB; row++) {
560 do_row(format, srcWidthNB, srcA, srcB,
561 dstWidthNB, dst);
562 srcA += 2 * srcRowBytes;
563 srcB += 2 * srcRowBytes;
564 dst += dstRowBytes;
565 }
566
567 /* This is ugly but probably won't be used much */
568 if (border > 0) {
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);
581 /* lower border */
582 do_row(format, srcWidthNB,
583 srcPtr + bpt,
584 srcPtr + bpt,
585 dstWidthNB, dstPtr + bpt);
586 /* upper border */
587 do_row(format, srcWidthNB,
588 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
589 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
590 dstWidthNB,
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);
600 }
601 }
602 else {
603 /* average two src pixels each dest pixel */
604 for (row = 0; row < dstHeightNB; row += 2) {
605 do_row(format, 1,
606 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
607 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
608 1, dstPtr + (dstWidth * row + 1) * bpt);
609 do_row(format, 1,
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);
613 }
614 }
615 }
616 }
617
618
619 static void
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)
625 {
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;
633 GLint img, row;
634 GLint bytesPerSrcImage, bytesPerDstImage;
635 GLint bytesPerSrcRow, bytesPerDstRow;
636 GLint srcImageOffset, srcRowOffset;
637
638 (void) srcDepthNB; /* silence warnings */
639
640 /* Need two temporary row buffers */
641 tmpRowA = _mesa_malloc(srcWidth * bpt);
642 if (!tmpRowA)
643 return;
644 tmpRowB = _mesa_malloc(srcWidth * bpt);
645 if (!tmpRowB) {
646 _mesa_free(tmpRowA);
647 return;
648 }
649
650 bytesPerSrcImage = srcWidth * srcHeight * bpt;
651 bytesPerDstImage = dstWidth * dstHeight * bpt;
652
653 bytesPerSrcRow = srcWidth * bpt;
654 bytesPerDstRow = dstWidth * bpt;
655
656 /* Offset between adjacent src images to be averaged together */
657 srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
658
659 /* Offset between adjacent src rows to be averaged together */
660 srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
661
662 /*
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.
668 */
669
670 /*
671 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
672 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
673 */
674
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;
686
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;
693
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;
710 }
711 }
712
713 _mesa_free(tmpRowA);
714 _mesa_free(tmpRowB);
715
716 /* Luckily we can leverage the make_2d_mipmap() function here! */
717 if (border > 0) {
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,
724 dstWidth, dstHeight,
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++) {
730 const GLubyte *src;
731 GLubyte *dst;
732
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);
737
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);
744
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);
751
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);
758 }
759 }
760 else {
761 /* average border pixels from adjacent src image pairs */
762 ASSERT(srcDepthNB == 2 * dstDepthNB);
763 for (img = 0; img < dstDepthNB; img++) {
764 const GLubyte *src;
765 GLubyte *dst;
766
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);
771
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);
778
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);
785
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);
792 }
793 }
794 }
795 }
796
797
798 static void
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 )
803 {
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;
810 const GLubyte *src;
811 GLubyte *dst;
812 GLint row;
813
814 /* Compute src and dst pointers, skipping any border */
815 src = srcPtr + border * ((srcWidth + 1) * bpt);
816 dst = dstPtr + border * ((dstWidth + 1) * bpt);
817
818 for (row = 0; row < dstHeightNB; row++) {
819 do_row(format, srcWidthNB, src, src,
820 dstWidthNB, dst);
821 src += srcRowBytes;
822 dst += dstRowBytes;
823 }
824
825 if (border) {
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,
831 bpt);
832 }
833 }
834
835
836 /**
837 * \bugs
838 * There is quite a bit of refactoring that could be done with this function
839 * and \c make_2d_mipmap.
840 */
841 static void
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)
847 {
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;
856 GLubyte *dst;
857 GLint layer;
858 GLint row;
859
860 /* Compute src and dst pointers, skipping any border */
861 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
862 if (srcHeight > 1)
863 srcB = srcA + srcRowBytes;
864 else
865 srcB = srcA;
866 dst = dstPtr + border * ((dstWidth + 1) * bpt);
867
868 for (layer = 0; layer < dstDepthNB; layer++) {
869 for (row = 0; row < dstHeightNB; row++) {
870 do_row(format, srcWidthNB, srcA, srcB,
871 dstWidthNB, dst);
872 srcA += 2 * srcRowBytes;
873 srcB += 2 * srcRowBytes;
874 dst += dstRowBytes;
875 }
876
877 /* This is ugly but probably won't be used much */
878 if (border > 0) {
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);
891 /* lower border */
892 do_row(format, srcWidthNB,
893 srcPtr + bpt,
894 srcPtr + bpt,
895 dstWidthNB, dstPtr + bpt);
896 /* upper border */
897 do_row(format, srcWidthNB,
898 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
899 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
900 dstWidthNB,
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);
910 }
911 }
912 else {
913 /* average two src pixels each dest pixel */
914 for (row = 0; row < dstHeightNB; row += 2) {
915 do_row(format, 1,
916 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
917 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
918 1, dstPtr + (dstWidth * row + 1) * bpt);
919 do_row(format, 1,
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);
923 }
924 }
925 }
926 }
927 }
928
929
930 /**
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.
934 */
935 void
936 _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
937 const struct gl_texture_unit *texUnit,
938 struct gl_texture_object *texObj)
939 {
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;
945
946 ASSERT(texObj);
947 /* XXX choose cube map face here??? */
948 srcImage = texObj->Image[0][texObj->BaseLevel];
949 ASSERT(srcImage);
950
951 maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
952 ASSERT(maxLevels > 0); /* bad target */
953
954 /* Find convertFormat - the format that do_row() will process */
955 if (srcImage->IsCompressed) {
956 /* setup for compressed textures */
957 GLuint row;
958 GLint components, size;
959 GLchan *dst;
960
961 assert(texObj->Target == GL_TEXTURE_2D ||
962 texObj->Target == GL_TEXTURE_CUBE_MAP_ARB);
963
964 if (srcImage->_BaseFormat == GL_RGB) {
965 convertFormat = &_mesa_texformat_rgb;
966 components = 3;
967 }
968 else if (srcImage->_BaseFormat == GL_RGBA) {
969 convertFormat = &_mesa_texformat_rgba;
970 components = 4;
971 }
972 else {
973 _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
974 return;
975 }
976
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);
982 if (!srcData) {
983 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
984 return;
985 }
986 dstData = (GLubyte *) _mesa_malloc(size / 2); /* 1/4 would probably be OK */
987 if (!dstData) {
988 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
989 _mesa_free((void *) srcData);
990 return;
991 }
992
993 /* decompress base image here */
994 dst = (GLchan *) srcData;
995 for (row = 0; row < srcImage->Height; row++) {
996 GLuint col;
997 for (col = 0; col < srcImage->Width; col++) {
998 srcImage->FetchTexelc(srcImage, col, row, 0, dst);
999 dst += components;
1000 }
1001 }
1002 }
1003 else {
1004 /* uncompressed */
1005 convertFormat = srcImage->TexFormat;
1006 }
1007
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;
1016
1017 /* get src image parameters */
1018 srcImage = _mesa_select_tex_image(ctx, texObj, target, level);
1019 ASSERT(srcImage);
1020 srcWidth = srcImage->Width;
1021 srcHeight = srcImage->Height;
1022 srcDepth = srcImage->Depth;
1023 border = srcImage->Border;
1024
1025 /* compute next (level+1) image size */
1026 if (srcWidth - 2 * border > 1) {
1027 dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1028 }
1029 else {
1030 dstWidth = srcWidth; /* can't go smaller */
1031 }
1032 if ((srcHeight - 2 * border > 1) &&
1033 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT)) {
1034 dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1035 }
1036 else {
1037 dstHeight = srcHeight; /* can't go smaller */
1038 }
1039 if ((srcDepth - 2 * border > 1) &&
1040 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT)) {
1041 dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1042 }
1043 else {
1044 dstDepth = srcDepth; /* can't go smaller */
1045 }
1046
1047 if (dstWidth == srcWidth &&
1048 dstHeight == srcHeight &&
1049 dstDepth == srcDepth) {
1050 /* all done */
1051 if (srcImage->IsCompressed) {
1052 _mesa_free((void *) srcData);
1053 _mesa_free(dstData);
1054 }
1055 return;
1056 }
1057
1058 /* get dest gl_texture_image */
1059 dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
1060 if (!dstImage) {
1061 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1062 return;
1063 }
1064
1065 if (dstImage->ImageOffsets)
1066 _mesa_free(dstImage->ImageOffsets);
1067
1068 /* Free old image data */
1069 if (dstImage->Data)
1070 ctx->Driver.FreeTexImageData(ctx, dstImage);
1071
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,
1083 dstImage->Height,
1084 dstImage->Depth,
1085 dstImage->TexFormat->MesaFormat);
1086 ASSERT(dstImage->CompressedSize > 0);
1087 }
1088
1089 ASSERT(dstImage->TexFormat);
1090 ASSERT(dstImage->FetchTexelc);
1091 ASSERT(dstImage->FetchTexelf);
1092
1093 /* Alloc new teximage data buffer.
1094 * Setup src and dest data pointers.
1095 */
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");
1100 return;
1101 }
1102 /* srcData and dstData are already set */
1103 ASSERT(srcData);
1104 ASSERT(dstData);
1105 }
1106 else {
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");
1113 return;
1114 }
1115 srcData = (const GLubyte *) srcImage->Data;
1116 dstData = (GLubyte *) dstImage->Data;
1117 }
1118
1119 /*
1120 * We use simple 2x2 averaging to compute the next mipmap level.
1121 */
1122 switch (target) {
1123 case GL_TEXTURE_1D:
1124 make_1d_mipmap(convertFormat, border,
1125 srcWidth, srcData,
1126 dstWidth, dstData);
1127 break;
1128 case GL_TEXTURE_2D:
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);
1138 break;
1139 case GL_TEXTURE_3D:
1140 make_3d_mipmap(convertFormat, border,
1141 srcWidth, srcHeight, srcDepth,
1142 srcData, srcImage->RowStride,
1143 dstWidth, dstHeight, dstDepth,
1144 dstData, dstImage->RowStride);
1145 break;
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);
1151 break;
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);
1158 break;
1159 case GL_TEXTURE_RECTANGLE_NV:
1160 /* no mipmaps, do nothing */
1161 break;
1162 default:
1163 _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
1164 return;
1165 }
1166
1167 if (dstImage->IsCompressed) {
1168 GLubyte *temp;
1169 /* compress image from dstData into dstImage->Data */
1170 const GLenum srcFormat = convertFormat->BaseFormat;
1171 GLint dstRowStride
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,
1176 dstImage->Data,
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;
1185 srcData = dstData;
1186 dstData = temp;
1187 }
1188
1189 } /* loop over mipmap levels */
1190 }
1191
1192
1193 /**
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...
1199 */
1200 void
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)
1207 {
1208 GLint row, col;
1209
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]; \
1216 } \
1217 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1218 } \
1219
1220 #define RESCALE_IMAGE( TYPE ) \
1221 do { \
1222 const TYPE *src = (const TYPE *)srcImage; \
1223 TYPE *dst = (TYPE *)dstImage; \
1224 \
1225 if ( srcHeight < dstHeight ) { \
1226 const GLint hScale = dstHeight / srcHeight; \
1227 if ( srcWidth < dstWidth ) { \
1228 const GLint wScale = dstWidth / srcWidth; \
1229 INNER_LOOP( TYPE, /, / ); \
1230 } \
1231 else { \
1232 const GLint wScale = srcWidth / dstWidth; \
1233 INNER_LOOP( TYPE, /, * ); \
1234 } \
1235 } \
1236 else { \
1237 const GLint hScale = srcHeight / dstHeight; \
1238 if ( srcWidth < dstWidth ) { \
1239 const GLint wScale = dstWidth / srcWidth; \
1240 INNER_LOOP( TYPE, *, / ); \
1241 } \
1242 else { \
1243 const GLint wScale = srcWidth / dstWidth; \
1244 INNER_LOOP( TYPE, *, * ); \
1245 } \
1246 } \
1247 } while (0)
1248
1249 switch ( bytesPerPixel ) {
1250 case 4:
1251 RESCALE_IMAGE( GLuint );
1252 break;
1253
1254 case 2:
1255 RESCALE_IMAGE( GLushort );
1256 break;
1257
1258 case 1:
1259 RESCALE_IMAGE( GLubyte );
1260 break;
1261 default:
1262 _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1263 }
1264 }
1265
1266
1267 /**
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.
1271 */
1272 void
1273 _mesa_upscale_teximage2d(GLsizei inWidth, GLsizei inHeight,
1274 GLsizei outWidth, GLsizei outHeight,
1275 GLint comps, const GLchan *src, GLint srcRowStride,
1276 GLchan *dest )
1277 {
1278 GLint i, j, k;
1279
1280 ASSERT(outWidth >= inWidth);
1281 ASSERT(outHeight >= inHeight);
1282 #if 0
1283 ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
1284 ASSERT((outWidth & 3) == 0);
1285 ASSERT((outHeight & 3) == 0);
1286 #endif
1287
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];
1295 }
1296 }
1297 }
1298 }
1299