Merge branch 'upstream-gallium-0.1' into darktama-gallium-0.1
[mesa.git] / src / mesa / main / mipmap.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 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 /**
535 * XXX need to use the tex image's row stride!
536 */
537 static void
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)
541 {
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;
549 GLubyte *dst;
550 GLint row;
551
552 /* Compute src and dst pointers, skipping any border */
553 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
554 if (srcHeight > 1)
555 srcB = srcA + srcRowStride;
556 else
557 srcB = srcA;
558 dst = dstPtr + border * ((dstWidth + 1) * bpt);
559
560 for (row = 0; row < dstHeightNB; row++) {
561 do_row(format, srcWidthNB, srcA, srcB,
562 dstWidthNB, dst);
563 srcA += 2 * srcRowStride;
564 srcB += 2 * srcRowStride;
565 dst += dstRowStride;
566 }
567
568 /* This is ugly but probably won't be used much */
569 if (border > 0) {
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);
582 /* lower border */
583 do_row(format, srcWidthNB,
584 srcPtr + bpt,
585 srcPtr + bpt,
586 dstWidthNB, dstPtr + bpt);
587 /* upper border */
588 do_row(format, srcWidthNB,
589 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
590 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
591 dstWidthNB,
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);
601 }
602 }
603 else {
604 /* average two src pixels each dest pixel */
605 for (row = 0; row < dstHeightNB; row += 2) {
606 do_row(format, 1,
607 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
608 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
609 1, dstPtr + (dstWidth * row + 1) * bpt);
610 do_row(format, 1,
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);
614 }
615 }
616 }
617 }
618
619
620 static void
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,
625 GLubyte *dstPtr)
626 {
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;
634 GLint img, row;
635 GLint bytesPerSrcImage, bytesPerDstImage;
636 GLint bytesPerSrcRow, bytesPerDstRow;
637 GLint srcImageOffset, srcRowOffset;
638
639 (void) srcDepthNB; /* silence warnings */
640
641 /* Need two temporary row buffers */
642 tmpRowA = _mesa_malloc(srcWidth * bpt);
643 if (!tmpRowA)
644 return;
645 tmpRowB = _mesa_malloc(srcWidth * bpt);
646 if (!tmpRowB) {
647 _mesa_free(tmpRowA);
648 return;
649 }
650
651 bytesPerSrcImage = srcWidth * srcHeight * bpt;
652 bytesPerDstImage = dstWidth * dstHeight * bpt;
653
654 bytesPerSrcRow = srcWidth * bpt;
655 bytesPerDstRow = dstWidth * bpt;
656
657 /* Offset between adjacent src images to be averaged together */
658 srcImageOffset = (srcDepth == dstDepth) ? 0 : bytesPerSrcImage;
659
660 /* Offset between adjacent src rows to be averaged together */
661 srcRowOffset = (srcHeight == dstHeight) ? 0 : srcWidth * bpt;
662
663 /*
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.
669 */
670
671 /*
672 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
673 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
674 */
675
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;
687
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;
694
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;
711 }
712 }
713
714 _mesa_free(tmpRowA);
715 _mesa_free(tmpRowB);
716
717 /* Luckily we can leverage the make_2d_mipmap() function here! */
718 if (border > 0) {
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),
725 dstWidth, dstHeight,
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++) {
731 const GLubyte *src;
732 GLubyte *dst;
733
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);
738
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);
745
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);
752
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);
759 }
760 }
761 else {
762 /* average border pixels from adjacent src image pairs */
763 ASSERT(srcDepthNB == 2 * dstDepthNB);
764 for (img = 0; img < dstDepthNB; img++) {
765 const GLubyte *src;
766 GLubyte *dst;
767
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);
772
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);
779
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);
786
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);
793 }
794 }
795 }
796 }
797
798
799 static void
800 make_1d_stack_mipmap(const struct gl_texture_format *format, GLint border,
801 GLint srcWidth, const GLubyte *srcPtr,
802 GLint dstWidth, GLint dstHeight, GLubyte *dstPtr)
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 srcRowStride = bpt * srcWidth;
809 const GLint dstRowStride = bpt * dstWidth;
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 += srcRowStride;
822 dst += dstRowStride;
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, const GLubyte *srcPtr,
844 GLint dstWidth, GLint dstHeight, GLint dstDepth,
845 GLubyte *dstPtr)
846 {
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;
855 GLubyte *dst;
856 GLint layer;
857 GLint row;
858
859 /* Compute src and dst pointers, skipping any border */
860 srcA = srcPtr + border * ((srcWidth + 1) * bpt);
861 if (srcHeight > 1)
862 srcB = srcA + srcRowStride;
863 else
864 srcB = srcA;
865 dst = dstPtr + border * ((dstWidth + 1) * bpt);
866
867 for (layer = 0; layer < dstDepthNB; layer++) {
868 for (row = 0; row < dstHeightNB; row++) {
869 do_row(format, srcWidthNB, srcA, srcB,
870 dstWidthNB, dst);
871 srcA += 2 * srcRowStride;
872 srcB += 2 * srcRowStride;
873 dst += dstRowStride;
874 }
875
876 /* This is ugly but probably won't be used much */
877 if (border > 0) {
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);
890 /* lower border */
891 do_row(format, srcWidthNB,
892 srcPtr + bpt,
893 srcPtr + bpt,
894 dstWidthNB, dstPtr + bpt);
895 /* upper border */
896 do_row(format, srcWidthNB,
897 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
898 srcPtr + (srcWidth * (srcHeight - 1) + 1) * bpt,
899 dstWidthNB,
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);
909 }
910 }
911 else {
912 /* average two src pixels each dest pixel */
913 for (row = 0; row < dstHeightNB; row += 2) {
914 do_row(format, 1,
915 srcPtr + (srcWidth * (row * 2 + 1)) * bpt,
916 srcPtr + (srcWidth * (row * 2 + 2)) * bpt,
917 1, dstPtr + (dstWidth * row + 1) * bpt);
918 do_row(format, 1,
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);
922 }
923 }
924 }
925 }
926 }
927
928
929 /**
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.
933 */
934 void
935 _mesa_generate_mipmap(GLcontext *ctx, GLenum target,
936 struct gl_texture_object *texObj)
937 {
938 const struct gl_texture_image *srcImage;
939 const struct gl_texture_format *convertFormat;
940 const GLubyte *srcData = NULL;
941 GLubyte *dstData = NULL;
942 GLint level, maxLevels;
943
944 ASSERT(texObj);
945 /* XXX choose cube map face here??? */
946 srcImage = texObj->Image[0][texObj->BaseLevel];
947 ASSERT(srcImage);
948
949 maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
950 ASSERT(maxLevels > 0); /* bad target */
951
952 /* Find convertFormat - the format that do_row() will process */
953 if (srcImage->IsCompressed) {
954 /* setup for compressed textures */
955 GLuint row;
956 GLint components, size;
957 GLchan *dst;
958
959 assert(texObj->Target == GL_TEXTURE_2D);
960
961 if (srcImage->_BaseFormat == GL_RGB) {
962 convertFormat = &_mesa_texformat_rgb;
963 components = 3;
964 }
965 else if (srcImage->_BaseFormat == GL_RGBA) {
966 convertFormat = &_mesa_texformat_rgba;
967 components = 4;
968 }
969 else {
970 _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
971 return;
972 }
973
974 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
975 size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE)
976 * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
977 /* 20 extra bytes, just be safe when calling last FetchTexel */
978 srcData = (GLubyte *) _mesa_malloc(size);
979 if (!srcData) {
980 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
981 return;
982 }
983 dstData = (GLubyte *) _mesa_malloc(size / 2); /* 1/4 would probably be OK */
984 if (!dstData) {
985 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
986 _mesa_free((void *) srcData);
987 return;
988 }
989
990 /* decompress base image here */
991 dst = (GLchan *) srcData;
992 for (row = 0; row < srcImage->Height; row++) {
993 GLuint col;
994 for (col = 0; col < srcImage->Width; col++) {
995 srcImage->FetchTexelc(srcImage, col, row, 0, dst);
996 dst += components;
997 }
998 }
999 }
1000 else {
1001 /* uncompressed */
1002 convertFormat = srcImage->TexFormat;
1003 }
1004
1005 for (level = texObj->BaseLevel; level < texObj->MaxLevel
1006 && level < maxLevels - 1; level++) {
1007 /* generate image[level+1] from image[level] */
1008 const struct gl_texture_image *srcImage;
1009 struct gl_texture_image *dstImage;
1010 GLint srcWidth, srcHeight, srcDepth;
1011 GLint dstWidth, dstHeight, dstDepth;
1012 GLint border, bytesPerTexel;
1013
1014 /* get src image parameters */
1015 srcImage = _mesa_select_tex_image(ctx, texObj, target, level);
1016 ASSERT(srcImage);
1017 srcWidth = srcImage->Width;
1018 srcHeight = srcImage->Height;
1019 srcDepth = srcImage->Depth;
1020 border = srcImage->Border;
1021
1022 /* compute next (level+1) image size */
1023 if (srcWidth - 2 * border > 1) {
1024 dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1025 }
1026 else {
1027 dstWidth = srcWidth; /* can't go smaller */
1028 }
1029 if ((srcHeight - 2 * border > 1) &&
1030 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT)) {
1031 dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1032 }
1033 else {
1034 dstHeight = srcHeight; /* can't go smaller */
1035 }
1036 if ((srcDepth - 2 * border > 1) &&
1037 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT)) {
1038 dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1039 }
1040 else {
1041 dstDepth = srcDepth; /* can't go smaller */
1042 }
1043
1044 if (dstWidth == srcWidth &&
1045 dstHeight == srcHeight &&
1046 dstDepth == srcDepth) {
1047 /* all done */
1048 if (srcImage->IsCompressed) {
1049 _mesa_free((void *) srcData);
1050 _mesa_free(dstData);
1051 }
1052 return;
1053 }
1054
1055 /* get dest gl_texture_image */
1056 dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
1057 if (!dstImage) {
1058 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1059 return;
1060 }
1061
1062 if (dstImage->ImageOffsets)
1063 _mesa_free(dstImage->ImageOffsets);
1064
1065 /* Free old image data */
1066 if (dstImage->Data)
1067 ctx->Driver.FreeTexImageData(ctx, dstImage);
1068
1069 /* initialize new image */
1070 _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
1071 dstDepth, border, srcImage->InternalFormat);
1072 dstImage->DriverData = NULL;
1073 dstImage->TexFormat = srcImage->TexFormat;
1074 dstImage->FetchTexelc = srcImage->FetchTexelc;
1075 dstImage->FetchTexelf = srcImage->FetchTexelf;
1076 dstImage->IsCompressed = srcImage->IsCompressed;
1077 if (dstImage->IsCompressed) {
1078 dstImage->CompressedSize
1079 = ctx->Driver.CompressedTextureSize(ctx, dstImage->Width,
1080 dstImage->Height,
1081 dstImage->Depth,
1082 dstImage->TexFormat->MesaFormat);
1083 ASSERT(dstImage->CompressedSize > 0);
1084 }
1085
1086 ASSERT(dstImage->TexFormat);
1087 ASSERT(dstImage->FetchTexelc);
1088 ASSERT(dstImage->FetchTexelf);
1089
1090 /* Alloc new teximage data buffer.
1091 * Setup src and dest data pointers.
1092 */
1093 if (dstImage->IsCompressed) {
1094 dstImage->Data = _mesa_alloc_texmemory(dstImage->CompressedSize);
1095 if (!dstImage->Data) {
1096 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1097 return;
1098 }
1099 /* srcData and dstData are already set */
1100 ASSERT(srcData);
1101 ASSERT(dstData);
1102 }
1103 else {
1104 bytesPerTexel = dstImage->TexFormat->TexelBytes;
1105 ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
1106 dstImage->Data = _mesa_alloc_texmemory(dstWidth * dstHeight
1107 * dstDepth * bytesPerTexel);
1108 if (!dstImage->Data) {
1109 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1110 return;
1111 }
1112 srcData = (const GLubyte *) srcImage->Data;
1113 dstData = (GLubyte *) dstImage->Data;
1114 }
1115
1116 /*
1117 * We use simple 2x2 averaging to compute the next mipmap level.
1118 */
1119 switch (target) {
1120 case GL_TEXTURE_1D:
1121 make_1d_mipmap(convertFormat, border,
1122 srcWidth, srcData,
1123 dstWidth, dstData);
1124 break;
1125 case GL_TEXTURE_2D:
1126 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
1127 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
1128 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
1129 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
1130 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
1131 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
1132 make_2d_mipmap(convertFormat, border,
1133 srcWidth, srcHeight, srcData,
1134 dstWidth, dstHeight, dstData);
1135 break;
1136 case GL_TEXTURE_3D:
1137 make_3d_mipmap(convertFormat, border,
1138 srcWidth, srcHeight, srcDepth, srcData,
1139 dstWidth, dstHeight, dstDepth, dstData);
1140 break;
1141 case GL_TEXTURE_1D_ARRAY_EXT:
1142 make_1d_stack_mipmap(convertFormat, border,
1143 srcWidth, srcData,
1144 dstWidth, dstHeight, dstData);
1145 break;
1146 case GL_TEXTURE_2D_ARRAY_EXT:
1147 make_2d_stack_mipmap(convertFormat, border,
1148 srcWidth, srcHeight, srcData,
1149 dstWidth, dstHeight, dstDepth, dstData);
1150 break;
1151 case GL_TEXTURE_RECTANGLE_NV:
1152 /* no mipmaps, do nothing */
1153 break;
1154 default:
1155 _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
1156 return;
1157 }
1158
1159 if (dstImage->IsCompressed) {
1160 GLubyte *temp;
1161 /* compress image from dstData into dstImage->Data */
1162 const GLenum srcFormat = convertFormat->BaseFormat;
1163 GLint dstRowStride
1164 = _mesa_compressed_row_stride(dstImage->TexFormat->MesaFormat, dstWidth);
1165 ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
1166 dstImage->TexFormat->StoreImage(ctx, 2, dstImage->_BaseFormat,
1167 dstImage->TexFormat,
1168 dstImage->Data,
1169 0, 0, 0, /* dstX/Y/Zoffset */
1170 dstRowStride, 0, /* strides */
1171 dstWidth, dstHeight, 1, /* size */
1172 srcFormat, CHAN_TYPE,
1173 dstData, /* src data, actually */
1174 &ctx->DefaultPacking);
1175 /* swap src and dest pointers */
1176 temp = (GLubyte *) srcData;
1177 srcData = dstData;
1178 dstData = temp;
1179 }
1180
1181 } /* loop over mipmap levels */
1182 }
1183
1184
1185 /**
1186 * Helper function for drivers which need to rescale texture images to
1187 * certain aspect ratios.
1188 * Nearest filtering only (for broken hardware that can't support
1189 * all aspect ratios). This can be made a lot faster, but I don't
1190 * really care enough...
1191 */
1192 void
1193 _mesa_rescale_teximage2d(GLuint bytesPerPixel,
1194 GLuint srcStrideInPixels,
1195 GLuint dstRowStride,
1196 GLint srcWidth, GLint srcHeight,
1197 GLint dstWidth, GLint dstHeight,
1198 const GLvoid *srcImage, GLvoid *dstImage)
1199 {
1200 GLint row, col;
1201
1202 #define INNER_LOOP( TYPE, HOP, WOP ) \
1203 for ( row = 0 ; row < dstHeight ; row++ ) { \
1204 GLint srcRow = row HOP hScale; \
1205 for ( col = 0 ; col < dstWidth ; col++ ) { \
1206 GLint srcCol = col WOP wScale; \
1207 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1208 } \
1209 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1210 } \
1211
1212 #define RESCALE_IMAGE( TYPE ) \
1213 do { \
1214 const TYPE *src = (const TYPE *)srcImage; \
1215 TYPE *dst = (TYPE *)dstImage; \
1216 \
1217 if ( srcHeight < dstHeight ) { \
1218 const GLint hScale = dstHeight / srcHeight; \
1219 if ( srcWidth < dstWidth ) { \
1220 const GLint wScale = dstWidth / srcWidth; \
1221 INNER_LOOP( TYPE, /, / ); \
1222 } \
1223 else { \
1224 const GLint wScale = srcWidth / dstWidth; \
1225 INNER_LOOP( TYPE, /, * ); \
1226 } \
1227 } \
1228 else { \
1229 const GLint hScale = srcHeight / dstHeight; \
1230 if ( srcWidth < dstWidth ) { \
1231 const GLint wScale = dstWidth / srcWidth; \
1232 INNER_LOOP( TYPE, *, / ); \
1233 } \
1234 else { \
1235 const GLint wScale = srcWidth / dstWidth; \
1236 INNER_LOOP( TYPE, *, * ); \
1237 } \
1238 } \
1239 } while (0)
1240
1241 switch ( bytesPerPixel ) {
1242 case 4:
1243 RESCALE_IMAGE( GLuint );
1244 break;
1245
1246 case 2:
1247 RESCALE_IMAGE( GLushort );
1248 break;
1249
1250 case 1:
1251 RESCALE_IMAGE( GLubyte );
1252 break;
1253 default:
1254 _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1255 }
1256 }
1257
1258
1259 /**
1260 * Upscale an image by replication, not (typical) stretching.
1261 * We use this when the image width or height is less than a
1262 * certain size (4, 8) and we need to upscale an image.
1263 */
1264 void
1265 _mesa_upscale_teximage2d(GLsizei inWidth, GLsizei inHeight,
1266 GLsizei outWidth, GLsizei outHeight,
1267 GLint comps, const GLchan *src, GLint srcRowStride,
1268 GLchan *dest )
1269 {
1270 GLint i, j, k;
1271
1272 ASSERT(outWidth >= inWidth);
1273 ASSERT(outHeight >= inHeight);
1274 #if 0
1275 ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
1276 ASSERT((outWidth & 3) == 0);
1277 ASSERT((outHeight & 3) == 0);
1278 #endif
1279
1280 for (i = 0; i < outHeight; i++) {
1281 const GLint ii = i % inHeight;
1282 for (j = 0; j < outWidth; j++) {
1283 const GLint jj = j % inWidth;
1284 for (k = 0; k < comps; k++) {
1285 dest[(i * outWidth + j) * comps + k]
1286 = src[ii * srcRowStride + jj * comps + k];
1287 }
1288 }
1289 }
1290 }
1291