2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * \file mipmap.c mipmap generation and teximage resizing functions.
32 #include "texcompress.h"
33 #include "texformat.h"
40 bytes_per_pixel(GLenum datatype
, GLuint comps
)
42 GLint b
= _mesa_sizeof_packed_type(datatype
);
49 * Average together two rows of a source image to produce a single new
50 * row in the dest image. It's legal for the two source rows to point
51 * to the same data. The source width must be equal to either the
52 * dest width or two times the dest width.
53 * \param datatype GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
54 * \param comps number of components per pixel (1..4)
57 do_row(GLenum datatype
, GLuint comps
, GLint srcWidth
,
58 const GLvoid
*srcRowA
, const GLvoid
*srcRowB
,
59 GLint dstWidth
, GLvoid
*dstRow
)
61 const GLuint k0
= (srcWidth
== dstWidth
) ? 0 : 1;
62 const GLuint colStride
= (srcWidth
== dstWidth
) ? 1 : 2;
67 /* This assertion is no longer valid with non-power-of-2 textures
68 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
71 if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 4) {
73 const GLubyte(*rowA
)[4] = (const GLubyte(*)[4]) srcRowA
;
74 const GLubyte(*rowB
)[4] = (const GLubyte(*)[4]) srcRowB
;
75 GLubyte(*dst
)[4] = (GLubyte(*)[4]) dstRow
;
76 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
77 i
++, j
+= colStride
, k
+= colStride
) {
78 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
79 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
80 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
81 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
84 else if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 3) {
86 const GLubyte(*rowA
)[3] = (const GLubyte(*)[3]) srcRowA
;
87 const GLubyte(*rowB
)[3] = (const GLubyte(*)[3]) srcRowB
;
88 GLubyte(*dst
)[3] = (GLubyte(*)[3]) dstRow
;
89 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
90 i
++, j
+= colStride
, k
+= colStride
) {
91 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
92 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
93 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
96 else if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 2) {
98 const GLubyte(*rowA
)[2] = (const GLubyte(*)[2]) srcRowA
;
99 const GLubyte(*rowB
)[2] = (const GLubyte(*)[2]) srcRowB
;
100 GLubyte(*dst
)[2] = (GLubyte(*)[2]) dstRow
;
101 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
102 i
++, j
+= colStride
, k
+= colStride
) {
103 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) >> 2;
104 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) >> 2;
107 else if (datatype
== GL_UNSIGNED_BYTE
&& comps
== 1) {
109 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
110 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
111 GLubyte
*dst
= (GLubyte
*) dstRow
;
112 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
113 i
++, j
+= colStride
, k
+= colStride
) {
114 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) >> 2;
118 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 4) {
120 const GLushort(*rowA
)[4] = (const GLushort(*)[4]) srcRowA
;
121 const GLushort(*rowB
)[4] = (const GLushort(*)[4]) srcRowB
;
122 GLushort(*dst
)[4] = (GLushort(*)[4]) dstRow
;
123 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
124 i
++, j
+= colStride
, k
+= colStride
) {
125 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
126 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
127 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
128 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
131 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 3) {
133 const GLushort(*rowA
)[3] = (const GLushort(*)[3]) srcRowA
;
134 const GLushort(*rowB
)[3] = (const GLushort(*)[3]) srcRowB
;
135 GLushort(*dst
)[3] = (GLushort(*)[3]) dstRow
;
136 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
137 i
++, j
+= colStride
, k
+= colStride
) {
138 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
139 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
140 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
143 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 2) {
145 const GLushort(*rowA
)[2] = (const GLushort(*)[2]) srcRowA
;
146 const GLushort(*rowB
)[2] = (const GLushort(*)[2]) srcRowB
;
147 GLushort(*dst
)[2] = (GLushort(*)[2]) dstRow
;
148 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
149 i
++, j
+= colStride
, k
+= colStride
) {
150 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
151 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
154 else if (datatype
== GL_UNSIGNED_SHORT
&& comps
== 1) {
156 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
157 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
158 GLushort
*dst
= (GLushort
*) dstRow
;
159 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
160 i
++, j
+= colStride
, k
+= colStride
) {
161 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) / 4;
165 else if (datatype
== GL_FLOAT
&& comps
== 4) {
167 const GLfloat(*rowA
)[4] = (const GLfloat(*)[4]) srcRowA
;
168 const GLfloat(*rowB
)[4] = (const GLfloat(*)[4]) srcRowB
;
169 GLfloat(*dst
)[4] = (GLfloat(*)[4]) dstRow
;
170 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
171 i
++, j
+= colStride
, k
+= colStride
) {
172 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
173 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
174 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
175 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
176 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
177 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
178 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
179 rowB
[j
][3] + rowB
[k
][3]) * 0.25F
;
182 else if (datatype
== GL_FLOAT
&& comps
== 3) {
184 const GLfloat(*rowA
)[3] = (const GLfloat(*)[3]) srcRowA
;
185 const GLfloat(*rowB
)[3] = (const GLfloat(*)[3]) srcRowB
;
186 GLfloat(*dst
)[3] = (GLfloat(*)[3]) dstRow
;
187 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
188 i
++, j
+= colStride
, k
+= colStride
) {
189 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
190 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
191 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
192 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
193 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
194 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
197 else if (datatype
== GL_FLOAT
&& comps
== 2) {
199 const GLfloat(*rowA
)[2] = (const GLfloat(*)[2]) srcRowA
;
200 const GLfloat(*rowB
)[2] = (const GLfloat(*)[2]) srcRowB
;
201 GLfloat(*dst
)[2] = (GLfloat(*)[2]) dstRow
;
202 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
203 i
++, j
+= colStride
, k
+= colStride
) {
204 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
205 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
206 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
207 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
210 else if (datatype
== GL_FLOAT
&& comps
== 1) {
212 const GLfloat
*rowA
= (const GLfloat
*) srcRowA
;
213 const GLfloat
*rowB
= (const GLfloat
*) srcRowB
;
214 GLfloat
*dst
= (GLfloat
*) dstRow
;
215 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
216 i
++, j
+= colStride
, k
+= colStride
) {
217 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) * 0.25F
;
221 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 4) {
222 GLuint i
, j
, k
, comp
;
223 const GLhalfARB(*rowA
)[4] = (const GLhalfARB(*)[4]) srcRowA
;
224 const GLhalfARB(*rowB
)[4] = (const GLhalfARB(*)[4]) srcRowB
;
225 GLhalfARB(*dst
)[4] = (GLhalfARB(*)[4]) dstRow
;
226 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
227 i
++, j
+= colStride
, k
+= colStride
) {
228 for (comp
= 0; comp
< 4; comp
++) {
229 GLfloat aj
, ak
, bj
, bk
;
230 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
231 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
232 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
233 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
234 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
238 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 3) {
239 GLuint i
, j
, k
, comp
;
240 const GLhalfARB(*rowA
)[3] = (const GLhalfARB(*)[3]) srcRowA
;
241 const GLhalfARB(*rowB
)[3] = (const GLhalfARB(*)[3]) srcRowB
;
242 GLhalfARB(*dst
)[3] = (GLhalfARB(*)[3]) dstRow
;
243 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
244 i
++, j
+= colStride
, k
+= colStride
) {
245 for (comp
= 0; comp
< 3; comp
++) {
246 GLfloat aj
, ak
, bj
, bk
;
247 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
248 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
249 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
250 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
251 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
255 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 2) {
256 GLuint i
, j
, k
, comp
;
257 const GLhalfARB(*rowA
)[2] = (const GLhalfARB(*)[2]) srcRowA
;
258 const GLhalfARB(*rowB
)[2] = (const GLhalfARB(*)[2]) srcRowB
;
259 GLhalfARB(*dst
)[2] = (GLhalfARB(*)[2]) dstRow
;
260 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
261 i
++, j
+= colStride
, k
+= colStride
) {
262 for (comp
= 0; comp
< 2; comp
++) {
263 GLfloat aj
, ak
, bj
, bk
;
264 aj
= _mesa_half_to_float(rowA
[j
][comp
]);
265 ak
= _mesa_half_to_float(rowA
[k
][comp
]);
266 bj
= _mesa_half_to_float(rowB
[j
][comp
]);
267 bk
= _mesa_half_to_float(rowB
[k
][comp
]);
268 dst
[i
][comp
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
272 else if (datatype
== GL_HALF_FLOAT_ARB
&& comps
== 1) {
274 const GLhalfARB
*rowA
= (const GLhalfARB
*) srcRowA
;
275 const GLhalfARB
*rowB
= (const GLhalfARB
*) srcRowB
;
276 GLhalfARB
*dst
= (GLhalfARB
*) dstRow
;
277 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
278 i
++, j
+= colStride
, k
+= colStride
) {
279 GLfloat aj
, ak
, bj
, bk
;
280 aj
= _mesa_half_to_float(rowA
[j
]);
281 ak
= _mesa_half_to_float(rowA
[k
]);
282 bj
= _mesa_half_to_float(rowB
[j
]);
283 bk
= _mesa_half_to_float(rowB
[k
]);
284 dst
[i
] = _mesa_float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
288 else if (datatype
== GL_UNSIGNED_INT
&& comps
== 1) {
290 const GLuint
*rowA
= (const GLuint
*) srcRowA
;
291 const GLuint
*rowB
= (const GLuint
*) srcRowB
;
292 GLfloat
*dst
= (GLfloat
*) dstRow
;
293 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
294 i
++, j
+= colStride
, k
+= colStride
) {
295 dst
[i
] = rowA
[j
] / 4 + rowA
[k
] / 4 + rowB
[j
] / 4 + rowB
[k
] / 4;
299 else if (datatype
== GL_UNSIGNED_SHORT_5_6_5
&& comps
== 3) {
301 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
302 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
303 GLushort
*dst
= (GLushort
*) dstRow
;
304 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
305 i
++, j
+= colStride
, k
+= colStride
) {
306 const GLint rowAr0
= rowA
[j
] & 0x1f;
307 const GLint rowAr1
= rowA
[k
] & 0x1f;
308 const GLint rowBr0
= rowB
[j
] & 0x1f;
309 const GLint rowBr1
= rowB
[k
] & 0x1f;
310 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x3f;
311 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x3f;
312 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x3f;
313 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x3f;
314 const GLint rowAb0
= (rowA
[j
] >> 11) & 0x1f;
315 const GLint rowAb1
= (rowA
[k
] >> 11) & 0x1f;
316 const GLint rowBb0
= (rowB
[j
] >> 11) & 0x1f;
317 const GLint rowBb1
= (rowB
[k
] >> 11) & 0x1f;
318 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
319 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
320 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
321 dst
[i
] = (blue
<< 11) | (green
<< 5) | red
;
324 else if (datatype
== GL_UNSIGNED_SHORT_4_4_4_4
&& comps
== 4) {
326 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
327 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
328 GLushort
*dst
= (GLushort
*) dstRow
;
329 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
330 i
++, j
+= colStride
, k
+= colStride
) {
331 const GLint rowAr0
= rowA
[j
] & 0xf;
332 const GLint rowAr1
= rowA
[k
] & 0xf;
333 const GLint rowBr0
= rowB
[j
] & 0xf;
334 const GLint rowBr1
= rowB
[k
] & 0xf;
335 const GLint rowAg0
= (rowA
[j
] >> 4) & 0xf;
336 const GLint rowAg1
= (rowA
[k
] >> 4) & 0xf;
337 const GLint rowBg0
= (rowB
[j
] >> 4) & 0xf;
338 const GLint rowBg1
= (rowB
[k
] >> 4) & 0xf;
339 const GLint rowAb0
= (rowA
[j
] >> 8) & 0xf;
340 const GLint rowAb1
= (rowA
[k
] >> 8) & 0xf;
341 const GLint rowBb0
= (rowB
[j
] >> 8) & 0xf;
342 const GLint rowBb1
= (rowB
[k
] >> 8) & 0xf;
343 const GLint rowAa0
= (rowA
[j
] >> 12) & 0xf;
344 const GLint rowAa1
= (rowA
[k
] >> 12) & 0xf;
345 const GLint rowBa0
= (rowB
[j
] >> 12) & 0xf;
346 const GLint rowBa1
= (rowB
[k
] >> 12) & 0xf;
347 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
348 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
349 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
350 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
351 dst
[i
] = (alpha
<< 12) | (blue
<< 8) | (green
<< 4) | red
;
354 else if (datatype
== GL_UNSIGNED_SHORT_1_5_5_5_REV
&& comps
== 4) {
356 const GLushort
*rowA
= (const GLushort
*) srcRowA
;
357 const GLushort
*rowB
= (const GLushort
*) srcRowB
;
358 GLushort
*dst
= (GLushort
*) dstRow
;
359 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
360 i
++, j
+= colStride
, k
+= colStride
) {
361 const GLint rowAr0
= rowA
[j
] & 0x1f;
362 const GLint rowAr1
= rowA
[k
] & 0x1f;
363 const GLint rowBr0
= rowB
[j
] & 0x1f;
364 const GLint rowBr1
= rowB
[k
] & 0xf;
365 const GLint rowAg0
= (rowA
[j
] >> 5) & 0x1f;
366 const GLint rowAg1
= (rowA
[k
] >> 5) & 0x1f;
367 const GLint rowBg0
= (rowB
[j
] >> 5) & 0x1f;
368 const GLint rowBg1
= (rowB
[k
] >> 5) & 0x1f;
369 const GLint rowAb0
= (rowA
[j
] >> 10) & 0x1f;
370 const GLint rowAb1
= (rowA
[k
] >> 10) & 0x1f;
371 const GLint rowBb0
= (rowB
[j
] >> 10) & 0x1f;
372 const GLint rowBb1
= (rowB
[k
] >> 10) & 0x1f;
373 const GLint rowAa0
= (rowA
[j
] >> 15) & 0x1;
374 const GLint rowAa1
= (rowA
[k
] >> 15) & 0x1;
375 const GLint rowBa0
= (rowB
[j
] >> 15) & 0x1;
376 const GLint rowBa1
= (rowB
[k
] >> 15) & 0x1;
377 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
378 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
379 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
380 const GLint alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
381 dst
[i
] = (alpha
<< 15) | (blue
<< 10) | (green
<< 5) | red
;
384 else if (datatype
== GL_UNSIGNED_BYTE_3_3_2
&& comps
== 3) {
386 const GLubyte
*rowA
= (const GLubyte
*) srcRowA
;
387 const GLubyte
*rowB
= (const GLubyte
*) srcRowB
;
388 GLubyte
*dst
= (GLubyte
*) dstRow
;
389 for (i
= j
= 0, k
= k0
; i
< (GLuint
) dstWidth
;
390 i
++, j
+= colStride
, k
+= colStride
) {
391 const GLint rowAr0
= rowA
[j
] & 0x3;
392 const GLint rowAr1
= rowA
[k
] & 0x3;
393 const GLint rowBr0
= rowB
[j
] & 0x3;
394 const GLint rowBr1
= rowB
[k
] & 0x3;
395 const GLint rowAg0
= (rowA
[j
] >> 2) & 0x7;
396 const GLint rowAg1
= (rowA
[k
] >> 2) & 0x7;
397 const GLint rowBg0
= (rowB
[j
] >> 2) & 0x7;
398 const GLint rowBg1
= (rowB
[k
] >> 2) & 0x7;
399 const GLint rowAb0
= (rowA
[j
] >> 5) & 0x7;
400 const GLint rowAb1
= (rowA
[k
] >> 5) & 0x7;
401 const GLint rowBb0
= (rowB
[j
] >> 5) & 0x7;
402 const GLint rowBb1
= (rowB
[k
] >> 5) & 0x7;
403 const GLint red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
404 const GLint green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
405 const GLint blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
406 dst
[i
] = (blue
<< 5) | (green
<< 2) | red
;
410 _mesa_problem(NULL
, "bad format in do_row()");
416 * These functions generate a 1/2-size mipmap image from a source image.
417 * Texture borders are handled by copying or averaging the source image's
418 * border texels, depending on the scale-down factor.
422 make_1d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
423 GLint srcWidth
, const GLubyte
*srcPtr
,
424 GLint dstWidth
, GLubyte
*dstPtr
)
426 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
430 /* skip the border pixel, if any */
431 src
= srcPtr
+ border
* bpt
;
432 dst
= dstPtr
+ border
* bpt
;
434 /* we just duplicate the input row, kind of hack, saves code */
435 do_row(datatype
, comps
, srcWidth
- 2 * border
, src
, src
,
436 dstWidth
- 2 * border
, dst
);
439 /* copy left-most pixel from source */
440 MEMCPY(dstPtr
, srcPtr
, bpt
);
441 /* copy right-most pixel from source */
442 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
443 srcPtr
+ (srcWidth
- 1) * bpt
,
450 * XXX need to use the tex image's row stride!
453 make_2d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
454 GLint srcWidth
, GLint srcHeight
, const GLubyte
*srcPtr
,
455 GLint dstWidth
, GLint dstHeight
, GLubyte
*dstPtr
)
457 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
458 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
459 const GLint dstWidthNB
= dstWidth
- 2 * border
;
460 const GLint dstHeightNB
= dstHeight
- 2 * border
;
461 const GLint srcRowStride
= bpt
* srcWidth
;
462 const GLint dstRowStride
= bpt
* dstWidth
;
463 const GLubyte
*srcA
, *srcB
;
467 /* Compute src and dst pointers, skipping any border */
468 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
470 srcB
= srcA
+ srcRowStride
;
473 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
475 for (row
= 0; row
< dstHeightNB
; row
++) {
476 do_row(datatype
, comps
, srcWidthNB
, srcA
, srcB
,
478 srcA
+= 2 * srcRowStride
;
479 srcB
+= 2 * srcRowStride
;
483 /* This is ugly but probably won't be used much */
485 /* fill in dest border */
486 /* lower-left border pixel */
487 MEMCPY(dstPtr
, srcPtr
, bpt
);
488 /* lower-right border pixel */
489 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
490 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
491 /* upper-left border pixel */
492 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
493 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
494 /* upper-right border pixel */
495 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
496 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
498 do_row(datatype
, comps
, srcWidthNB
,
501 dstWidthNB
, dstPtr
+ bpt
);
503 do_row(datatype
, comps
, srcWidthNB
,
504 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
505 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
507 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
508 /* left and right borders */
509 if (srcHeight
== dstHeight
) {
510 /* copy border pixel from src to dst */
511 for (row
= 1; row
< srcHeight
; row
++) {
512 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
513 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
514 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
515 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
519 /* average two src pixels each dest pixel */
520 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
521 do_row(datatype
, comps
, 1,
522 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
523 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
524 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
525 do_row(datatype
, comps
, 1,
526 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
527 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
528 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
536 make_3d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
537 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
538 const GLubyte
*srcPtr
,
539 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
542 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
543 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
544 const GLint srcDepthNB
= srcDepth
- 2 * border
;
545 const GLint dstWidthNB
= dstWidth
- 2 * border
;
546 const GLint dstHeightNB
= dstHeight
- 2 * border
;
547 const GLint dstDepthNB
= dstDepth
- 2 * border
;
548 GLvoid
*tmpRowA
, *tmpRowB
;
550 GLint bytesPerSrcImage
, bytesPerDstImage
;
551 GLint bytesPerSrcRow
, bytesPerDstRow
;
552 GLint srcImageOffset
, srcRowOffset
;
554 (void) srcDepthNB
; /* silence warnings */
556 /* Need two temporary row buffers */
557 tmpRowA
= _mesa_malloc(srcWidth
* bpt
);
560 tmpRowB
= _mesa_malloc(srcWidth
* bpt
);
566 bytesPerSrcImage
= srcWidth
* srcHeight
* bpt
;
567 bytesPerDstImage
= dstWidth
* dstHeight
* bpt
;
569 bytesPerSrcRow
= srcWidth
* bpt
;
570 bytesPerDstRow
= dstWidth
* bpt
;
572 /* Offset between adjacent src images to be averaged together */
573 srcImageOffset
= (srcDepth
== dstDepth
) ? 0 : bytesPerSrcImage
;
575 /* Offset between adjacent src rows to be averaged together */
576 srcRowOffset
= (srcHeight
== dstHeight
) ? 0 : srcWidth
* bpt
;
579 * Need to average together up to 8 src pixels for each dest pixel.
580 * Break that down into 3 operations:
581 * 1. take two rows from source image and average them together.
582 * 2. take two rows from next source image and average them together.
583 * 3. take the two averaged rows and average them for the final dst row.
587 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
588 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
591 for (img
= 0; img
< dstDepthNB
; img
++) {
592 /* first source image pointer, skipping border */
593 const GLubyte
*imgSrcA
= srcPtr
594 + (bytesPerSrcImage
+ bytesPerSrcRow
+ border
) * bpt
* border
595 + img
* (bytesPerSrcImage
+ srcImageOffset
);
596 /* second source image pointer, skipping border */
597 const GLubyte
*imgSrcB
= imgSrcA
+ srcImageOffset
;
598 /* address of the dest image, skipping border */
599 GLubyte
*imgDst
= dstPtr
600 + (bytesPerDstImage
+ bytesPerDstRow
+ border
) * bpt
* border
601 + img
* bytesPerDstImage
;
603 /* setup the four source row pointers and the dest row pointer */
604 const GLubyte
*srcImgARowA
= imgSrcA
;
605 const GLubyte
*srcImgARowB
= imgSrcA
+ srcRowOffset
;
606 const GLubyte
*srcImgBRowA
= imgSrcB
;
607 const GLubyte
*srcImgBRowB
= imgSrcB
+ srcRowOffset
;
608 GLubyte
*dstImgRow
= imgDst
;
610 for (row
= 0; row
< dstHeightNB
; row
++) {
611 /* Average together two rows from first src image */
612 do_row(datatype
, comps
, srcWidthNB
, srcImgARowA
, srcImgARowB
,
613 srcWidthNB
, tmpRowA
);
614 /* Average together two rows from second src image */
615 do_row(datatype
, comps
, srcWidthNB
, srcImgBRowA
, srcImgBRowB
,
616 srcWidthNB
, tmpRowB
);
617 /* Average together the temp rows to make the final row */
618 do_row(datatype
, comps
, srcWidthNB
, tmpRowA
, tmpRowB
,
619 dstWidthNB
, dstImgRow
);
620 /* advance to next rows */
621 srcImgARowA
+= bytesPerSrcRow
+ srcRowOffset
;
622 srcImgARowB
+= bytesPerSrcRow
+ srcRowOffset
;
623 srcImgBRowA
+= bytesPerSrcRow
+ srcRowOffset
;
624 srcImgBRowB
+= bytesPerSrcRow
+ srcRowOffset
;
625 dstImgRow
+= bytesPerDstRow
;
632 /* Luckily we can leverage the make_2d_mipmap() function here! */
634 /* do front border image */
635 make_2d_mipmap(datatype
, comps
, 1, srcWidth
, srcHeight
, srcPtr
,
636 dstWidth
, dstHeight
, dstPtr
);
637 /* do back border image */
638 make_2d_mipmap(datatype
, comps
, 1, srcWidth
, srcHeight
,
639 srcPtr
+ bytesPerSrcImage
* (srcDepth
- 1),
641 dstPtr
+ bytesPerDstImage
* (dstDepth
- 1));
642 /* do four remaining border edges that span the image slices */
643 if (srcDepth
== dstDepth
) {
644 /* just copy border pixels from src to dst */
645 for (img
= 0; img
< dstDepthNB
; img
++) {
649 /* do border along [img][row=0][col=0] */
650 src
= srcPtr
+ (img
+ 1) * bytesPerSrcImage
;
651 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
652 MEMCPY(dst
, src
, bpt
);
654 /* do border along [img][row=dstHeight-1][col=0] */
655 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
656 + (srcHeight
- 1) * bytesPerSrcRow
;
657 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
658 + (dstHeight
- 1) * bytesPerDstRow
;
659 MEMCPY(dst
, src
, bpt
);
661 /* do border along [img][row=0][col=dstWidth-1] */
662 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
663 + (srcWidth
- 1) * bpt
;
664 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
665 + (dstWidth
- 1) * bpt
;
666 MEMCPY(dst
, src
, bpt
);
668 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
669 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
670 + (bytesPerSrcImage
- bpt
);
671 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
672 + (bytesPerDstImage
- bpt
);
673 MEMCPY(dst
, src
, bpt
);
677 /* average border pixels from adjacent src image pairs */
678 ASSERT(srcDepthNB
== 2 * dstDepthNB
);
679 for (img
= 0; img
< dstDepthNB
; img
++) {
683 /* do border along [img][row=0][col=0] */
684 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
;
685 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
686 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
688 /* do border along [img][row=dstHeight-1][col=0] */
689 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
690 + (srcHeight
- 1) * bytesPerSrcRow
;
691 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
692 + (dstHeight
- 1) * bytesPerDstRow
;
693 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
695 /* do border along [img][row=0][col=dstWidth-1] */
696 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
697 + (srcWidth
- 1) * bpt
;
698 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
699 + (dstWidth
- 1) * bpt
;
700 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
702 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
703 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
704 + (bytesPerSrcImage
- bpt
);
705 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
706 + (bytesPerDstImage
- bpt
);
707 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
715 make_1d_stack_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
716 GLint srcWidth
, const GLubyte
*srcPtr
,
717 GLint dstWidth
, GLint dstHeight
, GLubyte
*dstPtr
)
719 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
720 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
721 const GLint dstWidthNB
= dstWidth
- 2 * border
;
722 const GLint dstHeightNB
= dstHeight
- 2 * border
;
723 const GLint srcRowStride
= bpt
* srcWidth
;
724 const GLint dstRowStride
= bpt
* dstWidth
;
729 /* Compute src and dst pointers, skipping any border */
730 src
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
731 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
733 for (row
= 0; row
< dstHeightNB
; row
++) {
734 do_row(datatype
, comps
, srcWidthNB
, src
, src
,
741 /* copy left-most pixel from source */
742 MEMCPY(dstPtr
, srcPtr
, bpt
);
743 /* copy right-most pixel from source */
744 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
745 srcPtr
+ (srcWidth
- 1) * bpt
,
753 * There is quite a bit of refactoring that could be done with this function
754 * and \c make_2d_mipmap.
757 make_2d_stack_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
758 GLint srcWidth
, GLint srcHeight
, const GLubyte
*srcPtr
,
759 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
762 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
763 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
764 const GLint dstWidthNB
= dstWidth
- 2 * border
;
765 const GLint dstHeightNB
= dstHeight
- 2 * border
;
766 const GLint dstDepthNB
= dstDepth
- 2 * border
;
767 const GLint srcRowStride
= bpt
* srcWidth
;
768 const GLint dstRowStride
= bpt
* dstWidth
;
769 const GLubyte
*srcA
, *srcB
;
774 /* Compute src and dst pointers, skipping any border */
775 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
777 srcB
= srcA
+ srcRowStride
;
780 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
782 for (layer
= 0; layer
< dstDepthNB
; layer
++) {
783 for (row
= 0; row
< dstHeightNB
; row
++) {
784 do_row(datatype
, comps
, srcWidthNB
, srcA
, srcB
,
786 srcA
+= 2 * srcRowStride
;
787 srcB
+= 2 * srcRowStride
;
791 /* This is ugly but probably won't be used much */
793 /* fill in dest border */
794 /* lower-left border pixel */
795 MEMCPY(dstPtr
, srcPtr
, bpt
);
796 /* lower-right border pixel */
797 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
798 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
799 /* upper-left border pixel */
800 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
801 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
802 /* upper-right border pixel */
803 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
804 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
806 do_row(datatype
, comps
, srcWidthNB
,
809 dstWidthNB
, dstPtr
+ bpt
);
811 do_row(datatype
, comps
, srcWidthNB
,
812 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
813 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
815 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
816 /* left and right borders */
817 if (srcHeight
== dstHeight
) {
818 /* copy border pixel from src to dst */
819 for (row
= 1; row
< srcHeight
; row
++) {
820 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
821 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
822 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
823 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
827 /* average two src pixels each dest pixel */
828 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
829 do_row(datatype
, comps
, 1,
830 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
831 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
832 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
833 do_row(datatype
, comps
, 1,
834 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
835 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
836 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
845 * For GL_SGIX_generate_mipmap:
846 * Generate a complete set of mipmaps from texObj's base-level image.
847 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
850 _mesa_generate_mipmap(GLcontext
*ctx
, GLenum target
,
851 struct gl_texture_object
*texObj
)
853 const struct gl_texture_image
*srcImage
;
854 const struct gl_texture_format
*convertFormat
;
855 const GLubyte
*srcData
= NULL
;
856 GLubyte
*dstData
= NULL
;
857 GLint level
, maxLevels
;
862 /* XXX choose cube map face here??? */
863 srcImage
= texObj
->Image
[0][texObj
->BaseLevel
];
866 maxLevels
= _mesa_max_texture_levels(ctx
, texObj
->Target
);
867 ASSERT(maxLevels
> 0); /* bad target */
869 /* Find convertFormat - the format that do_row() will process */
870 if (srcImage
->IsCompressed
) {
871 /* setup for compressed textures */
873 GLint components
, size
;
876 assert(texObj
->Target
== GL_TEXTURE_2D
);
878 if (srcImage
->_BaseFormat
== GL_RGB
) {
879 convertFormat
= &_mesa_texformat_rgb
;
882 else if (srcImage
->_BaseFormat
== GL_RGBA
) {
883 convertFormat
= &_mesa_texformat_rgba
;
887 _mesa_problem(ctx
, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
891 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
892 size
= _mesa_bytes_per_pixel(srcImage
->_BaseFormat
, CHAN_TYPE
)
893 * srcImage
->Width
* srcImage
->Height
* srcImage
->Depth
+ 20;
894 /* 20 extra bytes, just be safe when calling last FetchTexel */
895 srcData
= (GLubyte
*) _mesa_malloc(size
);
897 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
900 dstData
= (GLubyte
*) _mesa_malloc(size
/ 2); /* 1/4 would probably be OK */
902 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
903 _mesa_free((void *) srcData
);
907 /* decompress base image here */
908 dst
= (GLchan
*) srcData
;
909 for (row
= 0; row
< srcImage
->Height
; row
++) {
911 for (col
= 0; col
< srcImage
->Width
; col
++) {
912 srcImage
->FetchTexelc(srcImage
, col
, row
, 0, dst
);
919 convertFormat
= srcImage
->TexFormat
;
922 _mesa_format_to_type_and_comps(convertFormat
, &datatype
, &comps
);
924 for (level
= texObj
->BaseLevel
; level
< texObj
->MaxLevel
925 && level
< maxLevels
- 1; level
++) {
926 /* generate image[level+1] from image[level] */
927 const struct gl_texture_image
*srcImage
;
928 struct gl_texture_image
*dstImage
;
929 GLint srcWidth
, srcHeight
, srcDepth
;
930 GLint dstWidth
, dstHeight
, dstDepth
;
931 GLint border
, bytesPerTexel
;
933 /* get src image parameters */
934 srcImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
936 srcWidth
= srcImage
->Width
;
937 srcHeight
= srcImage
->Height
;
938 srcDepth
= srcImage
->Depth
;
939 border
= srcImage
->Border
;
941 /* compute next (level+1) image size */
942 if (srcWidth
- 2 * border
> 1) {
943 dstWidth
= (srcWidth
- 2 * border
) / 2 + 2 * border
;
946 dstWidth
= srcWidth
; /* can't go smaller */
948 if ((srcHeight
- 2 * border
> 1) &&
949 (texObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
)) {
950 dstHeight
= (srcHeight
- 2 * border
) / 2 + 2 * border
;
953 dstHeight
= srcHeight
; /* can't go smaller */
955 if ((srcDepth
- 2 * border
> 1) &&
956 (texObj
->Target
!= GL_TEXTURE_2D_ARRAY_EXT
)) {
957 dstDepth
= (srcDepth
- 2 * border
) / 2 + 2 * border
;
960 dstDepth
= srcDepth
; /* can't go smaller */
963 if (dstWidth
== srcWidth
&&
964 dstHeight
== srcHeight
&&
965 dstDepth
== srcDepth
) {
967 if (srcImage
->IsCompressed
) {
968 _mesa_free((void *) srcData
);
974 /* get dest gl_texture_image */
975 dstImage
= _mesa_get_tex_image(ctx
, texObj
, target
, level
+ 1);
977 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
981 if (dstImage
->ImageOffsets
)
982 _mesa_free(dstImage
->ImageOffsets
);
984 /* Free old image data */
986 ctx
->Driver
.FreeTexImageData(ctx
, dstImage
);
988 /* initialize new image */
989 _mesa_init_teximage_fields(ctx
, target
, dstImage
, dstWidth
, dstHeight
,
990 dstDepth
, border
, srcImage
->InternalFormat
);
991 dstImage
->DriverData
= NULL
;
992 dstImage
->TexFormat
= srcImage
->TexFormat
;
993 dstImage
->FetchTexelc
= srcImage
->FetchTexelc
;
994 dstImage
->FetchTexelf
= srcImage
->FetchTexelf
;
995 dstImage
->IsCompressed
= srcImage
->IsCompressed
;
996 if (dstImage
->IsCompressed
) {
997 dstImage
->CompressedSize
998 = ctx
->Driver
.CompressedTextureSize(ctx
, dstImage
->Width
,
1001 dstImage
->TexFormat
->MesaFormat
);
1002 ASSERT(dstImage
->CompressedSize
> 0);
1005 ASSERT(dstImage
->TexFormat
);
1006 ASSERT(dstImage
->FetchTexelc
);
1007 ASSERT(dstImage
->FetchTexelf
);
1009 /* Alloc new teximage data buffer.
1010 * Setup src and dest data pointers.
1012 if (dstImage
->IsCompressed
) {
1013 dstImage
->Data
= _mesa_alloc_texmemory(dstImage
->CompressedSize
);
1014 if (!dstImage
->Data
) {
1015 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1018 /* srcData and dstData are already set */
1023 bytesPerTexel
= dstImage
->TexFormat
->TexelBytes
;
1024 ASSERT(dstWidth
* dstHeight
* dstDepth
* bytesPerTexel
> 0);
1025 dstImage
->Data
= _mesa_alloc_texmemory(dstWidth
* dstHeight
1026 * dstDepth
* bytesPerTexel
);
1027 if (!dstImage
->Data
) {
1028 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1031 srcData
= (const GLubyte
*) srcImage
->Data
;
1032 dstData
= (GLubyte
*) dstImage
->Data
;
1036 * We use simple 2x2 averaging to compute the next mipmap level.
1040 make_1d_mipmap(datatype
, comps
, border
,
1045 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
:
1046 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
:
1047 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
:
1048 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
:
1049 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
:
1050 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
:
1051 make_2d_mipmap(datatype
, comps
, border
,
1052 srcWidth
, srcHeight
, srcData
,
1053 dstWidth
, dstHeight
, dstData
);
1056 make_3d_mipmap(datatype
, comps
, border
,
1057 srcWidth
, srcHeight
, srcDepth
, srcData
,
1058 dstWidth
, dstHeight
, dstDepth
, dstData
);
1060 case GL_TEXTURE_1D_ARRAY_EXT
:
1061 make_1d_stack_mipmap(datatype
, comps
, border
,
1063 dstWidth
, dstHeight
, dstData
);
1065 case GL_TEXTURE_2D_ARRAY_EXT
:
1066 make_2d_stack_mipmap(datatype
, comps
, border
,
1067 srcWidth
, srcHeight
, srcData
,
1068 dstWidth
, dstHeight
, dstDepth
, dstData
);
1070 case GL_TEXTURE_RECTANGLE_NV
:
1071 /* no mipmaps, do nothing */
1074 _mesa_problem(ctx
, "bad dimensions in _mesa_generate_mipmaps");
1078 if (dstImage
->IsCompressed
) {
1080 /* compress image from dstData into dstImage->Data */
1081 const GLenum srcFormat
= convertFormat
->BaseFormat
;
1083 = _mesa_compressed_row_stride(dstImage
->TexFormat
->MesaFormat
, dstWidth
);
1084 ASSERT(srcFormat
== GL_RGB
|| srcFormat
== GL_RGBA
);
1085 dstImage
->TexFormat
->StoreImage(ctx
, 2, dstImage
->_BaseFormat
,
1086 dstImage
->TexFormat
,
1088 0, 0, 0, /* dstX/Y/Zoffset */
1089 dstRowStride
, 0, /* strides */
1090 dstWidth
, dstHeight
, 1, /* size */
1091 srcFormat
, CHAN_TYPE
,
1092 dstData
, /* src data, actually */
1093 &ctx
->DefaultPacking
);
1094 /* swap src and dest pointers */
1095 temp
= (GLubyte
*) srcData
;
1100 } /* loop over mipmap levels */
1105 * Helper function for drivers which need to rescale texture images to
1106 * certain aspect ratios.
1107 * Nearest filtering only (for broken hardware that can't support
1108 * all aspect ratios). This can be made a lot faster, but I don't
1109 * really care enough...
1112 _mesa_rescale_teximage2d(GLuint bytesPerPixel
,
1113 GLuint srcStrideInPixels
,
1114 GLuint dstRowStride
,
1115 GLint srcWidth
, GLint srcHeight
,
1116 GLint dstWidth
, GLint dstHeight
,
1117 const GLvoid
*srcImage
, GLvoid
*dstImage
)
1121 #define INNER_LOOP( TYPE, HOP, WOP ) \
1122 for ( row = 0 ; row < dstHeight ; row++ ) { \
1123 GLint srcRow = row HOP hScale; \
1124 for ( col = 0 ; col < dstWidth ; col++ ) { \
1125 GLint srcCol = col WOP wScale; \
1126 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1128 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1131 #define RESCALE_IMAGE( TYPE ) \
1133 const TYPE *src = (const TYPE *)srcImage; \
1134 TYPE *dst = (TYPE *)dstImage; \
1136 if ( srcHeight < dstHeight ) { \
1137 const GLint hScale = dstHeight / srcHeight; \
1138 if ( srcWidth < dstWidth ) { \
1139 const GLint wScale = dstWidth / srcWidth; \
1140 INNER_LOOP( TYPE, /, / ); \
1143 const GLint wScale = srcWidth / dstWidth; \
1144 INNER_LOOP( TYPE, /, * ); \
1148 const GLint hScale = srcHeight / dstHeight; \
1149 if ( srcWidth < dstWidth ) { \
1150 const GLint wScale = dstWidth / srcWidth; \
1151 INNER_LOOP( TYPE, *, / ); \
1154 const GLint wScale = srcWidth / dstWidth; \
1155 INNER_LOOP( TYPE, *, * ); \
1160 switch ( bytesPerPixel
) {
1162 RESCALE_IMAGE( GLuint
);
1166 RESCALE_IMAGE( GLushort
);
1170 RESCALE_IMAGE( GLubyte
);
1173 _mesa_problem(NULL
,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1179 * Upscale an image by replication, not (typical) stretching.
1180 * We use this when the image width or height is less than a
1181 * certain size (4, 8) and we need to upscale an image.
1184 _mesa_upscale_teximage2d(GLsizei inWidth
, GLsizei inHeight
,
1185 GLsizei outWidth
, GLsizei outHeight
,
1186 GLint comps
, const GLchan
*src
, GLint srcRowStride
,
1191 ASSERT(outWidth
>= inWidth
);
1192 ASSERT(outHeight
>= inHeight
);
1194 ASSERT(inWidth
== 1 || inWidth
== 2 || inHeight
== 1 || inHeight
== 2);
1195 ASSERT((outWidth
& 3) == 0);
1196 ASSERT((outHeight
& 3) == 0);
1199 for (i
= 0; i
< outHeight
; i
++) {
1200 const GLint ii
= i
% inHeight
;
1201 for (j
= 0; j
< outWidth
; j
++) {
1202 const GLint jj
= j
% inWidth
;
1203 for (k
= 0; k
< comps
; k
++) {
1204 dest
[(i
* outWidth
+ j
) * comps
+ k
]
1205 = src
[ii
* srcRowStride
+ jj
* comps
+ k
];