Initial implementation of MESA_texture_array
[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, 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 const struct gl_texture_unit *texUnit,
937 struct gl_texture_object *texObj)
938 {
939 const struct gl_texture_image *srcImage;
940 const struct gl_texture_format *convertFormat;
941 const GLubyte *srcData = NULL;
942 GLubyte *dstData = NULL;
943 GLint level, maxLevels;
944
945 ASSERT(texObj);
946 /* XXX choose cube map face here??? */
947 srcImage = texObj->Image[0][texObj->BaseLevel];
948 ASSERT(srcImage);
949
950 maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
951 ASSERT(maxLevels > 0); /* bad target */
952
953 /* Find convertFormat - the format that do_row() will process */
954 if (srcImage->IsCompressed) {
955 /* setup for compressed textures */
956 GLuint row;
957 GLint components, size;
958 GLchan *dst;
959
960 assert(texObj->Target == GL_TEXTURE_2D);
961
962 if (srcImage->_BaseFormat == GL_RGB) {
963 convertFormat = &_mesa_texformat_rgb;
964 components = 3;
965 }
966 else if (srcImage->_BaseFormat == GL_RGBA) {
967 convertFormat = &_mesa_texformat_rgba;
968 components = 4;
969 }
970 else {
971 _mesa_problem(ctx, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
972 return;
973 }
974
975 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
976 size = _mesa_bytes_per_pixel(srcImage->_BaseFormat, CHAN_TYPE)
977 * srcImage->Width * srcImage->Height * srcImage->Depth + 20;
978 /* 20 extra bytes, just be safe when calling last FetchTexel */
979 srcData = (GLubyte *) _mesa_malloc(size);
980 if (!srcData) {
981 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
982 return;
983 }
984 dstData = (GLubyte *) _mesa_malloc(size / 2); /* 1/4 would probably be OK */
985 if (!dstData) {
986 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generate mipmaps");
987 _mesa_free((void *) srcData);
988 return;
989 }
990
991 /* decompress base image here */
992 dst = (GLchan *) srcData;
993 for (row = 0; row < srcImage->Height; row++) {
994 GLuint col;
995 for (col = 0; col < srcImage->Width; col++) {
996 srcImage->FetchTexelc(srcImage, col, row, 0, dst);
997 dst += components;
998 }
999 }
1000 }
1001 else {
1002 /* uncompressed */
1003 convertFormat = srcImage->TexFormat;
1004 }
1005
1006 for (level = texObj->BaseLevel; level < texObj->MaxLevel
1007 && level < maxLevels - 1; level++) {
1008 /* generate image[level+1] from image[level] */
1009 const struct gl_texture_image *srcImage;
1010 struct gl_texture_image *dstImage;
1011 GLint srcWidth, srcHeight, srcDepth;
1012 GLint dstWidth, dstHeight, dstDepth;
1013 GLint border, bytesPerTexel;
1014
1015 /* get src image parameters */
1016 srcImage = _mesa_select_tex_image(ctx, texObj, target, level);
1017 ASSERT(srcImage);
1018 srcWidth = srcImage->Width;
1019 srcHeight = srcImage->Height;
1020 srcDepth = srcImage->Depth;
1021 border = srcImage->Border;
1022
1023 /* compute next (level+1) image size */
1024 if (srcWidth - 2 * border > 1) {
1025 dstWidth = (srcWidth - 2 * border) / 2 + 2 * border;
1026 }
1027 else {
1028 dstWidth = srcWidth; /* can't go smaller */
1029 }
1030 if ((srcHeight - 2 * border > 1) &&
1031 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT)) {
1032 dstHeight = (srcHeight - 2 * border) / 2 + 2 * border;
1033 }
1034 else {
1035 dstHeight = srcHeight; /* can't go smaller */
1036 }
1037 if ((srcDepth - 2 * border > 1) &&
1038 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT)) {
1039 dstDepth = (srcDepth - 2 * border) / 2 + 2 * border;
1040 }
1041 else {
1042 dstDepth = srcDepth; /* can't go smaller */
1043 }
1044
1045 if (dstWidth == srcWidth &&
1046 dstHeight == srcHeight &&
1047 dstDepth == srcDepth) {
1048 /* all done */
1049 if (srcImage->IsCompressed) {
1050 _mesa_free((void *) srcData);
1051 _mesa_free(dstData);
1052 }
1053 return;
1054 }
1055
1056 /* get dest gl_texture_image */
1057 dstImage = _mesa_get_tex_image(ctx, texObj, target, level + 1);
1058 if (!dstImage) {
1059 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1060 return;
1061 }
1062
1063 if (dstImage->ImageOffsets)
1064 _mesa_free(dstImage->ImageOffsets);
1065
1066 /* Free old image data */
1067 if (dstImage->Data)
1068 ctx->Driver.FreeTexImageData(ctx, dstImage);
1069
1070 /* initialize new image */
1071 _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight,
1072 dstDepth, border, srcImage->InternalFormat);
1073 dstImage->DriverData = NULL;
1074 dstImage->TexFormat = srcImage->TexFormat;
1075 dstImage->FetchTexelc = srcImage->FetchTexelc;
1076 dstImage->FetchTexelf = srcImage->FetchTexelf;
1077 dstImage->IsCompressed = srcImage->IsCompressed;
1078 if (dstImage->IsCompressed) {
1079 dstImage->CompressedSize
1080 = ctx->Driver.CompressedTextureSize(ctx, dstImage->Width,
1081 dstImage->Height,
1082 dstImage->Depth,
1083 dstImage->TexFormat->MesaFormat);
1084 ASSERT(dstImage->CompressedSize > 0);
1085 }
1086
1087 ASSERT(dstImage->TexFormat);
1088 ASSERT(dstImage->FetchTexelc);
1089 ASSERT(dstImage->FetchTexelf);
1090
1091 /* Alloc new teximage data buffer.
1092 * Setup src and dest data pointers.
1093 */
1094 if (dstImage->IsCompressed) {
1095 dstImage->Data = _mesa_alloc_texmemory(dstImage->CompressedSize);
1096 if (!dstImage->Data) {
1097 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1098 return;
1099 }
1100 /* srcData and dstData are already set */
1101 ASSERT(srcData);
1102 ASSERT(dstData);
1103 }
1104 else {
1105 bytesPerTexel = dstImage->TexFormat->TexelBytes;
1106 ASSERT(dstWidth * dstHeight * dstDepth * bytesPerTexel > 0);
1107 dstImage->Data = _mesa_alloc_texmemory(dstWidth * dstHeight
1108 * dstDepth * bytesPerTexel);
1109 if (!dstImage->Data) {
1110 _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps");
1111 return;
1112 }
1113 srcData = (const GLubyte *) srcImage->Data;
1114 dstData = (GLubyte *) dstImage->Data;
1115 }
1116
1117 /*
1118 * We use simple 2x2 averaging to compute the next mipmap level.
1119 */
1120 switch (target) {
1121 case GL_TEXTURE_1D:
1122 make_1d_mipmap(convertFormat, border,
1123 srcWidth, srcData,
1124 dstWidth, dstData);
1125 break;
1126 case GL_TEXTURE_2D:
1127 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
1128 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
1129 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
1130 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
1131 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
1132 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
1133 make_2d_mipmap(convertFormat, border,
1134 srcWidth, srcHeight, srcData,
1135 dstWidth, dstHeight, dstData);
1136 break;
1137 case GL_TEXTURE_3D:
1138 make_3d_mipmap(convertFormat, border,
1139 srcWidth, srcHeight, srcDepth, srcData,
1140 dstWidth, dstHeight, dstDepth, dstData);
1141 break;
1142 case GL_TEXTURE_1D_ARRAY_EXT:
1143 make_1d_stack_mipmap(convertFormat, border,
1144 srcWidth, srcData,
1145 dstWidth, dstHeight, dstData);
1146 break;
1147 case GL_TEXTURE_2D_ARRAY_EXT:
1148 make_2d_stack_mipmap(convertFormat, border,
1149 srcWidth, srcHeight, srcData,
1150 dstWidth, dstHeight, dstDepth, dstData);
1151 break;
1152 case GL_TEXTURE_RECTANGLE_NV:
1153 /* no mipmaps, do nothing */
1154 break;
1155 default:
1156 _mesa_problem(ctx, "bad dimensions in _mesa_generate_mipmaps");
1157 return;
1158 }
1159
1160 if (dstImage->IsCompressed) {
1161 GLubyte *temp;
1162 /* compress image from dstData into dstImage->Data */
1163 const GLenum srcFormat = convertFormat->BaseFormat;
1164 GLint dstRowStride
1165 = _mesa_compressed_row_stride(dstImage->TexFormat->MesaFormat, dstWidth);
1166 ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA);
1167 dstImage->TexFormat->StoreImage(ctx, 2, dstImage->_BaseFormat,
1168 dstImage->TexFormat,
1169 dstImage->Data,
1170 0, 0, 0, /* dstX/Y/Zoffset */
1171 dstRowStride, 0, /* strides */
1172 dstWidth, dstHeight, 1, /* size */
1173 srcFormat, CHAN_TYPE,
1174 dstData, /* src data, actually */
1175 &ctx->DefaultPacking);
1176 /* swap src and dest pointers */
1177 temp = (GLubyte *) srcData;
1178 srcData = dstData;
1179 dstData = temp;
1180 }
1181
1182 } /* loop over mipmap levels */
1183 }
1184
1185
1186 /**
1187 * Helper function for drivers which need to rescale texture images to
1188 * certain aspect ratios.
1189 * Nearest filtering only (for broken hardware that can't support
1190 * all aspect ratios). This can be made a lot faster, but I don't
1191 * really care enough...
1192 */
1193 void
1194 _mesa_rescale_teximage2d(GLuint bytesPerPixel,
1195 GLuint srcStrideInPixels,
1196 GLuint dstRowStride,
1197 GLint srcWidth, GLint srcHeight,
1198 GLint dstWidth, GLint dstHeight,
1199 const GLvoid *srcImage, GLvoid *dstImage)
1200 {
1201 GLint row, col;
1202
1203 #define INNER_LOOP( TYPE, HOP, WOP ) \
1204 for ( row = 0 ; row < dstHeight ; row++ ) { \
1205 GLint srcRow = row HOP hScale; \
1206 for ( col = 0 ; col < dstWidth ; col++ ) { \
1207 GLint srcCol = col WOP wScale; \
1208 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1209 } \
1210 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1211 } \
1212
1213 #define RESCALE_IMAGE( TYPE ) \
1214 do { \
1215 const TYPE *src = (const TYPE *)srcImage; \
1216 TYPE *dst = (TYPE *)dstImage; \
1217 \
1218 if ( srcHeight < dstHeight ) { \
1219 const GLint hScale = dstHeight / srcHeight; \
1220 if ( srcWidth < dstWidth ) { \
1221 const GLint wScale = dstWidth / srcWidth; \
1222 INNER_LOOP( TYPE, /, / ); \
1223 } \
1224 else { \
1225 const GLint wScale = srcWidth / dstWidth; \
1226 INNER_LOOP( TYPE, /, * ); \
1227 } \
1228 } \
1229 else { \
1230 const GLint hScale = srcHeight / dstHeight; \
1231 if ( srcWidth < dstWidth ) { \
1232 const GLint wScale = dstWidth / srcWidth; \
1233 INNER_LOOP( TYPE, *, / ); \
1234 } \
1235 else { \
1236 const GLint wScale = srcWidth / dstWidth; \
1237 INNER_LOOP( TYPE, *, * ); \
1238 } \
1239 } \
1240 } while (0)
1241
1242 switch ( bytesPerPixel ) {
1243 case 4:
1244 RESCALE_IMAGE( GLuint );
1245 break;
1246
1247 case 2:
1248 RESCALE_IMAGE( GLushort );
1249 break;
1250
1251 case 1:
1252 RESCALE_IMAGE( GLubyte );
1253 break;
1254 default:
1255 _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1256 }
1257 }
1258
1259
1260 /**
1261 * Upscale an image by replication, not (typical) stretching.
1262 * We use this when the image width or height is less than a
1263 * certain size (4, 8) and we need to upscale an image.
1264 */
1265 void
1266 _mesa_upscale_teximage2d(GLsizei inWidth, GLsizei inHeight,
1267 GLsizei outWidth, GLsizei outHeight,
1268 GLint comps, const GLchan *src, GLint srcRowStride,
1269 GLchan *dest )
1270 {
1271 GLint i, j, k;
1272
1273 ASSERT(outWidth >= inWidth);
1274 ASSERT(outHeight >= inHeight);
1275 #if 0
1276 ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2);
1277 ASSERT((outWidth & 3) == 0);
1278 ASSERT((outHeight & 3) == 0);
1279 #endif
1280
1281 for (i = 0; i < outHeight; i++) {
1282 const GLint ii = i % inHeight;
1283 for (j = 0; j < outWidth; j++) {
1284 const GLint jj = j % inWidth;
1285 for (k = 0; k < comps; k++) {
1286 dest[(i * outWidth + j) * comps + k]
1287 = src[ii * srcRowStride + jj * comps + k];
1288 }
1289 }
1290 }
1291 }
1292