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 * Strides are in bytes. If zero, it'll be computed as width * bpp.
453 make_2d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
454 GLint srcWidth
, GLint srcHeight
,
455 GLint srcRowStride
, const GLubyte
*srcPtr
,
456 GLint dstWidth
, GLint dstHeight
,
457 GLint dstRowStride
, GLubyte
*dstPtr
)
459 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
460 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
461 const GLint dstWidthNB
= dstWidth
- 2 * border
;
462 const GLint dstHeightNB
= dstHeight
- 2 * border
;
463 const GLubyte
*srcA
, *srcB
;
468 srcRowStride
= bpt
* srcWidth
;
471 dstRowStride
= bpt
* dstWidth
;
473 /* Compute src and dst pointers, skipping any border */
474 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
476 srcB
= srcA
+ srcRowStride
;
479 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
481 for (row
= 0; row
< dstHeightNB
; row
++) {
482 do_row(datatype
, comps
, srcWidthNB
, srcA
, srcB
,
484 srcA
+= 2 * srcRowStride
;
485 srcB
+= 2 * srcRowStride
;
489 /* This is ugly but probably won't be used much */
491 /* fill in dest border */
492 /* lower-left border pixel */
493 MEMCPY(dstPtr
, srcPtr
, bpt
);
494 /* lower-right border pixel */
495 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
496 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
497 /* upper-left border pixel */
498 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
499 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
500 /* upper-right border pixel */
501 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
502 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
504 do_row(datatype
, comps
, srcWidthNB
,
507 dstWidthNB
, dstPtr
+ bpt
);
509 do_row(datatype
, comps
, srcWidthNB
,
510 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
511 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
513 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
514 /* left and right borders */
515 if (srcHeight
== dstHeight
) {
516 /* copy border pixel from src to dst */
517 for (row
= 1; row
< srcHeight
; row
++) {
518 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
519 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
520 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
521 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
525 /* average two src pixels each dest pixel */
526 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
527 do_row(datatype
, comps
, 1,
528 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
529 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
530 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
531 do_row(datatype
, comps
, 1,
532 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
533 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
534 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
542 make_3d_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
543 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
545 const GLubyte
*srcPtr
,
546 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
550 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
551 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
552 const GLint srcDepthNB
= srcDepth
- 2 * border
;
553 const GLint dstWidthNB
= dstWidth
- 2 * border
;
554 const GLint dstHeightNB
= dstHeight
- 2 * border
;
555 const GLint dstDepthNB
= dstDepth
- 2 * border
;
556 GLvoid
*tmpRowA
, *tmpRowB
;
558 GLint bytesPerSrcImage
, bytesPerDstImage
;
559 GLint srcImageOffset
, srcRowOffset
;
561 (void) srcDepthNB
; /* silence warnings */
563 /* Need two temporary row buffers */
564 tmpRowA
= _mesa_malloc(srcWidth
* bpt
);
567 tmpRowB
= _mesa_malloc(srcWidth
* bpt
);
573 bytesPerSrcImage
= srcWidth
* srcHeight
* bpt
;
574 bytesPerDstImage
= dstWidth
* dstHeight
* bpt
;
577 srcRowStride
= srcWidth
* bpt
;
579 dstRowStride
= dstWidth
* bpt
;
581 /* Offset between adjacent src images to be averaged together */
582 srcImageOffset
= (srcDepth
== dstDepth
) ? 0 : bytesPerSrcImage
;
584 /* Offset between adjacent src rows to be averaged together */
585 srcRowOffset
= (srcHeight
== dstHeight
) ? 0 : srcWidth
* bpt
;
588 * Need to average together up to 8 src pixels for each dest pixel.
589 * Break that down into 3 operations:
590 * 1. take two rows from source image and average them together.
591 * 2. take two rows from next source image and average them together.
592 * 3. take the two averaged rows and average them for the final dst row.
596 _mesa_printf("mip3d %d x %d x %d -> %d x %d x %d\n",
597 srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
600 for (img
= 0; img
< dstDepthNB
; img
++) {
601 /* first source image pointer, skipping border */
602 const GLubyte
*imgSrcA
= srcPtr
603 + (bytesPerSrcImage
+ srcRowStride
+ border
) * bpt
* border
604 + img
* (bytesPerSrcImage
+ srcImageOffset
);
605 /* second source image pointer, skipping border */
606 const GLubyte
*imgSrcB
= imgSrcA
+ srcImageOffset
;
607 /* address of the dest image, skipping border */
608 GLubyte
*imgDst
= dstPtr
609 + (bytesPerDstImage
+ dstRowStride
+ border
) * bpt
* border
610 + img
* bytesPerDstImage
;
612 /* setup the four source row pointers and the dest row pointer */
613 const GLubyte
*srcImgARowA
= imgSrcA
;
614 const GLubyte
*srcImgARowB
= imgSrcA
+ srcRowOffset
;
615 const GLubyte
*srcImgBRowA
= imgSrcB
;
616 const GLubyte
*srcImgBRowB
= imgSrcB
+ srcRowOffset
;
617 GLubyte
*dstImgRow
= imgDst
;
619 for (row
= 0; row
< dstHeightNB
; row
++) {
620 /* Average together two rows from first src image */
621 do_row(datatype
, comps
, srcWidthNB
, srcImgARowA
, srcImgARowB
,
622 srcWidthNB
, tmpRowA
);
623 /* Average together two rows from second src image */
624 do_row(datatype
, comps
, srcWidthNB
, srcImgBRowA
, srcImgBRowB
,
625 srcWidthNB
, tmpRowB
);
626 /* Average together the temp rows to make the final row */
627 do_row(datatype
, comps
, srcWidthNB
, tmpRowA
, tmpRowB
,
628 dstWidthNB
, dstImgRow
);
629 /* advance to next rows */
630 srcImgARowA
+= srcRowStride
+ srcRowOffset
;
631 srcImgARowB
+= srcRowStride
+ srcRowOffset
;
632 srcImgBRowA
+= srcRowStride
+ srcRowOffset
;
633 srcImgBRowB
+= srcRowStride
+ srcRowOffset
;
634 dstImgRow
+= dstRowStride
;
641 /* Luckily we can leverage the make_2d_mipmap() function here! */
643 /* do front border image */
644 make_2d_mipmap(datatype
, comps
, 1, srcWidth
, srcHeight
, 0, srcPtr
,
645 dstWidth
, dstHeight
, 0, dstPtr
);
646 /* do back border image */
647 make_2d_mipmap(datatype
, comps
, 1, srcWidth
, srcHeight
,
649 srcPtr
+ bytesPerSrcImage
* (srcDepth
- 1),
652 dstPtr
+ bytesPerDstImage
* (dstDepth
- 1));
653 /* do four remaining border edges that span the image slices */
654 if (srcDepth
== dstDepth
) {
655 /* just copy border pixels from src to dst */
656 for (img
= 0; img
< dstDepthNB
; img
++) {
660 /* do border along [img][row=0][col=0] */
661 src
= srcPtr
+ (img
+ 1) * bytesPerSrcImage
;
662 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
663 MEMCPY(dst
, src
, bpt
);
665 /* do border along [img][row=dstHeight-1][col=0] */
666 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
667 + (srcHeight
- 1) * srcRowStride
;
668 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
669 + (dstHeight
- 1) * dstRowStride
;
670 MEMCPY(dst
, src
, bpt
);
672 /* do border along [img][row=0][col=dstWidth-1] */
673 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
674 + (srcWidth
- 1) * bpt
;
675 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
676 + (dstWidth
- 1) * bpt
;
677 MEMCPY(dst
, src
, bpt
);
679 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
680 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
681 + (bytesPerSrcImage
- bpt
);
682 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
683 + (bytesPerDstImage
- bpt
);
684 MEMCPY(dst
, src
, bpt
);
688 /* average border pixels from adjacent src image pairs */
689 ASSERT(srcDepthNB
== 2 * dstDepthNB
);
690 for (img
= 0; img
< dstDepthNB
; img
++) {
694 /* do border along [img][row=0][col=0] */
695 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
;
696 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
;
697 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
699 /* do border along [img][row=dstHeight-1][col=0] */
700 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
701 + (srcHeight
- 1) * srcRowStride
;
702 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
703 + (dstHeight
- 1) * dstRowStride
;
704 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
706 /* do border along [img][row=0][col=dstWidth-1] */
707 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
708 + (srcWidth
- 1) * bpt
;
709 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
710 + (dstWidth
- 1) * bpt
;
711 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
713 /* do border along [img][row=dstHeight-1][col=dstWidth-1] */
714 src
= srcPtr
+ (img
* 2 + 1) * bytesPerSrcImage
715 + (bytesPerSrcImage
- bpt
);
716 dst
= dstPtr
+ (img
+ 1) * bytesPerDstImage
717 + (bytesPerDstImage
- bpt
);
718 do_row(datatype
, comps
, 1, src
, src
+ srcImageOffset
, 1, dst
);
726 make_1d_stack_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
727 GLint srcWidth
, const GLubyte
*srcPtr
,
728 GLint dstWidth
, GLint dstHeight
, GLubyte
*dstPtr
)
730 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
731 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
732 const GLint dstWidthNB
= dstWidth
- 2 * border
;
733 const GLint dstHeightNB
= dstHeight
- 2 * border
;
734 const GLint srcRowStride
= bpt
* srcWidth
;
735 const GLint dstRowStride
= bpt
* dstWidth
;
740 /* Compute src and dst pointers, skipping any border */
741 src
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
742 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
744 for (row
= 0; row
< dstHeightNB
; row
++) {
745 do_row(datatype
, comps
, srcWidthNB
, src
, src
,
752 /* copy left-most pixel from source */
753 MEMCPY(dstPtr
, srcPtr
, bpt
);
754 /* copy right-most pixel from source */
755 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
756 srcPtr
+ (srcWidth
- 1) * bpt
,
764 * There is quite a bit of refactoring that could be done with this function
765 * and \c make_2d_mipmap.
768 make_2d_stack_mipmap(GLenum datatype
, GLuint comps
, GLint border
,
769 GLint srcWidth
, GLint srcHeight
,
771 const GLubyte
*srcPtr
,
772 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
776 const GLint bpt
= bytes_per_pixel(datatype
, comps
);
777 const GLint srcWidthNB
= srcWidth
- 2 * border
; /* sizes w/out border */
778 const GLint dstWidthNB
= dstWidth
- 2 * border
;
779 const GLint dstHeightNB
= dstHeight
- 2 * border
;
780 const GLint dstDepthNB
= dstDepth
- 2 * border
;
781 const GLubyte
*srcA
, *srcB
;
787 srcRowStride
= bpt
* srcWidth
;
790 dstRowStride
= bpt
* dstWidth
;
792 /* Compute src and dst pointers, skipping any border */
793 srcA
= srcPtr
+ border
* ((srcWidth
+ 1) * bpt
);
795 srcB
= srcA
+ srcRowStride
;
798 dst
= dstPtr
+ border
* ((dstWidth
+ 1) * bpt
);
800 for (layer
= 0; layer
< dstDepthNB
; layer
++) {
801 for (row
= 0; row
< dstHeightNB
; row
++) {
802 do_row(datatype
, comps
, srcWidthNB
, srcA
, srcB
,
804 srcA
+= 2 * srcRowStride
;
805 srcB
+= 2 * srcRowStride
;
809 /* This is ugly but probably won't be used much */
811 /* fill in dest border */
812 /* lower-left border pixel */
813 MEMCPY(dstPtr
, srcPtr
, bpt
);
814 /* lower-right border pixel */
815 MEMCPY(dstPtr
+ (dstWidth
- 1) * bpt
,
816 srcPtr
+ (srcWidth
- 1) * bpt
, bpt
);
817 /* upper-left border pixel */
818 MEMCPY(dstPtr
+ dstWidth
* (dstHeight
- 1) * bpt
,
819 srcPtr
+ srcWidth
* (srcHeight
- 1) * bpt
, bpt
);
820 /* upper-right border pixel */
821 MEMCPY(dstPtr
+ (dstWidth
* dstHeight
- 1) * bpt
,
822 srcPtr
+ (srcWidth
* srcHeight
- 1) * bpt
, bpt
);
824 do_row(datatype
, comps
, srcWidthNB
,
827 dstWidthNB
, dstPtr
+ bpt
);
829 do_row(datatype
, comps
, srcWidthNB
,
830 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
831 srcPtr
+ (srcWidth
* (srcHeight
- 1) + 1) * bpt
,
833 dstPtr
+ (dstWidth
* (dstHeight
- 1) + 1) * bpt
);
834 /* left and right borders */
835 if (srcHeight
== dstHeight
) {
836 /* copy border pixel from src to dst */
837 for (row
= 1; row
< srcHeight
; row
++) {
838 MEMCPY(dstPtr
+ dstWidth
* row
* bpt
,
839 srcPtr
+ srcWidth
* row
* bpt
, bpt
);
840 MEMCPY(dstPtr
+ (dstWidth
* row
+ dstWidth
- 1) * bpt
,
841 srcPtr
+ (srcWidth
* row
+ srcWidth
- 1) * bpt
, bpt
);
845 /* average two src pixels each dest pixel */
846 for (row
= 0; row
< dstHeightNB
; row
+= 2) {
847 do_row(datatype
, comps
, 1,
848 srcPtr
+ (srcWidth
* (row
* 2 + 1)) * bpt
,
849 srcPtr
+ (srcWidth
* (row
* 2 + 2)) * bpt
,
850 1, dstPtr
+ (dstWidth
* row
+ 1) * bpt
);
851 do_row(datatype
, comps
, 1,
852 srcPtr
+ (srcWidth
* (row
* 2 + 1) + srcWidth
- 1) * bpt
,
853 srcPtr
+ (srcWidth
* (row
* 2 + 2) + srcWidth
- 1) * bpt
,
854 1, dstPtr
+ (dstWidth
* row
+ 1 + dstWidth
- 1) * bpt
);
863 * Down-sample a texture image to produce the next lower mipmap level.
866 _mesa_generate_mipmap_level(GLenum target
,
867 GLenum datatype
, GLuint comps
,
869 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
871 const GLubyte
*srcData
,
872 GLint dstWidth
, GLint dstHeight
, GLint dstDepth
,
878 make_1d_mipmap(datatype
, comps
, border
,
883 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
:
884 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
:
885 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
:
886 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
:
887 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
:
888 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
:
889 make_2d_mipmap(datatype
, comps
, border
,
890 srcWidth
, srcHeight
, srcRowStride
, srcData
,
891 dstWidth
, dstHeight
, dstRowStride
, dstData
);
894 make_3d_mipmap(datatype
, comps
, border
,
895 srcWidth
, srcHeight
, srcDepth
, srcRowStride
, srcData
,
896 dstWidth
, dstHeight
, dstDepth
, dstRowStride
, dstData
);
898 case GL_TEXTURE_1D_ARRAY_EXT
:
899 make_1d_stack_mipmap(datatype
, comps
, border
,
901 dstWidth
, dstHeight
, dstData
);
903 case GL_TEXTURE_2D_ARRAY_EXT
:
904 make_2d_stack_mipmap(datatype
, comps
, border
,
905 srcWidth
, srcHeight
, srcRowStride
, srcData
,
906 dstWidth
, dstHeight
, dstDepth
, dstRowStride
, dstData
);
908 case GL_TEXTURE_RECTANGLE_NV
:
909 /* no mipmaps, do nothing */
912 _mesa_problem(NULL
, "bad target in _mesa_generate_mipmap_level");
918 * compute next (level+1) image size
919 * \return GL_FALSE if no smaller size can be generated (eg. src is 1x1x1 size)
922 next_mipmap_level_size(GLenum target
, GLint border
,
923 GLint srcWidth
, GLint srcHeight
, GLint srcDepth
,
924 GLint
*dstWidth
, GLint
*dstHeight
, GLint
*dstDepth
)
926 if (srcWidth
- 2 * border
> 1) {
927 *dstWidth
= (srcWidth
- 2 * border
) / 2 + 2 * border
;
930 *dstWidth
= srcWidth
; /* can't go smaller */
933 if ((srcHeight
- 2 * border
> 1) &&
934 (target
!= GL_TEXTURE_1D_ARRAY_EXT
)) {
935 *dstHeight
= (srcHeight
- 2 * border
) / 2 + 2 * border
;
938 *dstHeight
= srcHeight
; /* can't go smaller */
941 if ((srcDepth
- 2 * border
> 1) &&
942 (target
!= GL_TEXTURE_2D_ARRAY_EXT
)) {
943 *dstDepth
= (srcDepth
- 2 * border
) / 2 + 2 * border
;
946 *dstDepth
= srcDepth
; /* can't go smaller */
949 if (*dstWidth
== srcWidth
&&
950 *dstHeight
== srcHeight
&&
951 *dstDepth
== srcDepth
) {
963 * For GL_SGIX_generate_mipmap:
964 * Generate a complete set of mipmaps from texObj's base-level image.
965 * Stop at texObj's MaxLevel or when we get to the 1x1 texture.
968 _mesa_generate_mipmap(GLcontext
*ctx
, GLenum target
,
969 struct gl_texture_object
*texObj
)
971 const struct gl_texture_image
*srcImage
;
972 const struct gl_texture_format
*convertFormat
;
973 const GLubyte
*srcData
= NULL
;
974 GLubyte
*dstData
= NULL
;
975 GLint level
, maxLevels
;
980 /* XXX choose cube map face here??? */
981 srcImage
= texObj
->Image
[0][texObj
->BaseLevel
];
984 maxLevels
= _mesa_max_texture_levels(ctx
, texObj
->Target
);
985 ASSERT(maxLevels
> 0); /* bad target */
987 /* Find convertFormat - the format that do_row() will process */
988 if (srcImage
->IsCompressed
) {
989 /* setup for compressed textures */
991 GLint components
, size
;
994 assert(texObj
->Target
== GL_TEXTURE_2D
);
996 if (srcImage
->_BaseFormat
== GL_RGB
) {
997 convertFormat
= &_mesa_texformat_rgb
;
1000 else if (srcImage
->_BaseFormat
== GL_RGBA
) {
1001 convertFormat
= &_mesa_texformat_rgba
;
1005 _mesa_problem(ctx
, "bad srcImage->_BaseFormat in _mesa_generate_mipmaps");
1009 /* allocate storage for uncompressed GL_RGB or GL_RGBA images */
1010 size
= _mesa_bytes_per_pixel(srcImage
->_BaseFormat
, CHAN_TYPE
)
1011 * srcImage
->Width
* srcImage
->Height
* srcImage
->Depth
+ 20;
1012 /* 20 extra bytes, just be safe when calling last FetchTexel */
1013 srcData
= (GLubyte
*) _mesa_malloc(size
);
1015 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
1018 dstData
= (GLubyte
*) _mesa_malloc(size
/ 2); /* 1/4 would probably be OK */
1020 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generate mipmaps");
1021 _mesa_free((void *) srcData
);
1025 /* decompress base image here */
1026 dst
= (GLchan
*) srcData
;
1027 for (row
= 0; row
< srcImage
->Height
; row
++) {
1029 for (col
= 0; col
< srcImage
->Width
; col
++) {
1030 srcImage
->FetchTexelc(srcImage
, col
, row
, 0, dst
);
1037 convertFormat
= srcImage
->TexFormat
;
1040 _mesa_format_to_type_and_comps(convertFormat
, &datatype
, &comps
);
1042 for (level
= texObj
->BaseLevel
; level
< texObj
->MaxLevel
1043 && level
< maxLevels
- 1; level
++) {
1044 /* generate image[level+1] from image[level] */
1045 const struct gl_texture_image
*srcImage
;
1046 struct gl_texture_image
*dstImage
;
1047 GLint srcWidth
, srcHeight
, srcDepth
;
1048 GLint dstWidth
, dstHeight
, dstDepth
;
1049 GLint border
, bytesPerTexel
;
1050 GLboolean nextLevel
;
1052 /* get src image parameters */
1053 srcImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
1055 srcWidth
= srcImage
->Width
;
1056 srcHeight
= srcImage
->Height
;
1057 srcDepth
= srcImage
->Depth
;
1058 border
= srcImage
->Border
;
1060 nextLevel
= next_mipmap_level_size(target
, border
,
1061 srcWidth
, srcHeight
, srcDepth
,
1062 &dstWidth
, &dstHeight
, &dstDepth
);
1065 if (srcImage
->IsCompressed
) {
1066 _mesa_free((void *) srcData
);
1067 _mesa_free(dstData
);
1072 /* get dest gl_texture_image */
1073 dstImage
= _mesa_get_tex_image(ctx
, texObj
, target
, level
+ 1);
1075 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1079 if (dstImage
->ImageOffsets
)
1080 _mesa_free(dstImage
->ImageOffsets
);
1082 /* Free old image data */
1084 ctx
->Driver
.FreeTexImageData(ctx
, dstImage
);
1086 /* initialize new image */
1087 _mesa_init_teximage_fields(ctx
, target
, dstImage
, dstWidth
, dstHeight
,
1088 dstDepth
, border
, srcImage
->InternalFormat
);
1089 dstImage
->DriverData
= NULL
;
1090 dstImage
->TexFormat
= srcImage
->TexFormat
;
1091 dstImage
->FetchTexelc
= srcImage
->FetchTexelc
;
1092 dstImage
->FetchTexelf
= srcImage
->FetchTexelf
;
1093 dstImage
->IsCompressed
= srcImage
->IsCompressed
;
1094 if (dstImage
->IsCompressed
) {
1095 dstImage
->CompressedSize
1096 = ctx
->Driver
.CompressedTextureSize(ctx
, dstImage
->Width
,
1099 dstImage
->TexFormat
->MesaFormat
);
1100 ASSERT(dstImage
->CompressedSize
> 0);
1103 ASSERT(dstImage
->TexFormat
);
1104 ASSERT(dstImage
->FetchTexelc
);
1105 ASSERT(dstImage
->FetchTexelf
);
1107 /* Alloc new teximage data buffer.
1108 * Setup src and dest data pointers.
1110 if (dstImage
->IsCompressed
) {
1111 dstImage
->Data
= _mesa_alloc_texmemory(dstImage
->CompressedSize
);
1112 if (!dstImage
->Data
) {
1113 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1116 /* srcData and dstData are already set */
1121 bytesPerTexel
= dstImage
->TexFormat
->TexelBytes
;
1122 ASSERT(dstWidth
* dstHeight
* dstDepth
* bytesPerTexel
> 0);
1123 dstImage
->Data
= _mesa_alloc_texmemory(dstWidth
* dstHeight
1124 * dstDepth
* bytesPerTexel
);
1125 if (!dstImage
->Data
) {
1126 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "generating mipmaps");
1129 srcData
= (const GLubyte
*) srcImage
->Data
;
1130 dstData
= (GLubyte
*) dstImage
->Data
;
1133 /* Note, 0 indicates default row strides */
1134 _mesa_generate_mipmap_level(target
, datatype
, comps
, border
,
1135 srcWidth
, srcHeight
, srcDepth
, 0, srcData
,
1136 dstWidth
, dstHeight
, dstDepth
, 0, dstData
);
1138 if (dstImage
->IsCompressed
) {
1140 /* compress image from dstData into dstImage->Data */
1141 const GLenum srcFormat
= convertFormat
->BaseFormat
;
1143 = _mesa_compressed_row_stride(dstImage
->TexFormat
->MesaFormat
, dstWidth
);
1144 ASSERT(srcFormat
== GL_RGB
|| srcFormat
== GL_RGBA
);
1145 dstImage
->TexFormat
->StoreImage(ctx
, 2, dstImage
->_BaseFormat
,
1146 dstImage
->TexFormat
,
1148 0, 0, 0, /* dstX/Y/Zoffset */
1149 dstRowStride
, 0, /* strides */
1150 dstWidth
, dstHeight
, 1, /* size */
1151 srcFormat
, CHAN_TYPE
,
1152 dstData
, /* src data, actually */
1153 &ctx
->DefaultPacking
);
1154 /* swap src and dest pointers */
1155 temp
= (GLubyte
*) srcData
;
1160 } /* loop over mipmap levels */
1165 * Helper function for drivers which need to rescale texture images to
1166 * certain aspect ratios.
1167 * Nearest filtering only (for broken hardware that can't support
1168 * all aspect ratios). This can be made a lot faster, but I don't
1169 * really care enough...
1172 _mesa_rescale_teximage2d(GLuint bytesPerPixel
,
1173 GLuint srcStrideInPixels
,
1174 GLuint dstRowStride
,
1175 GLint srcWidth
, GLint srcHeight
,
1176 GLint dstWidth
, GLint dstHeight
,
1177 const GLvoid
*srcImage
, GLvoid
*dstImage
)
1181 #define INNER_LOOP( TYPE, HOP, WOP ) \
1182 for ( row = 0 ; row < dstHeight ; row++ ) { \
1183 GLint srcRow = row HOP hScale; \
1184 for ( col = 0 ; col < dstWidth ; col++ ) { \
1185 GLint srcCol = col WOP wScale; \
1186 dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \
1188 dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \
1191 #define RESCALE_IMAGE( TYPE ) \
1193 const TYPE *src = (const TYPE *)srcImage; \
1194 TYPE *dst = (TYPE *)dstImage; \
1196 if ( srcHeight < dstHeight ) { \
1197 const GLint hScale = dstHeight / srcHeight; \
1198 if ( srcWidth < dstWidth ) { \
1199 const GLint wScale = dstWidth / srcWidth; \
1200 INNER_LOOP( TYPE, /, / ); \
1203 const GLint wScale = srcWidth / dstWidth; \
1204 INNER_LOOP( TYPE, /, * ); \
1208 const GLint hScale = srcHeight / dstHeight; \
1209 if ( srcWidth < dstWidth ) { \
1210 const GLint wScale = dstWidth / srcWidth; \
1211 INNER_LOOP( TYPE, *, / ); \
1214 const GLint wScale = srcWidth / dstWidth; \
1215 INNER_LOOP( TYPE, *, * ); \
1220 switch ( bytesPerPixel
) {
1222 RESCALE_IMAGE( GLuint
);
1226 RESCALE_IMAGE( GLushort
);
1230 RESCALE_IMAGE( GLubyte
);
1233 _mesa_problem(NULL
,"unexpected bytes/pixel in _mesa_rescale_teximage2d");
1239 * Upscale an image by replication, not (typical) stretching.
1240 * We use this when the image width or height is less than a
1241 * certain size (4, 8) and we need to upscale an image.
1244 _mesa_upscale_teximage2d(GLsizei inWidth
, GLsizei inHeight
,
1245 GLsizei outWidth
, GLsizei outHeight
,
1246 GLint comps
, const GLchan
*src
, GLint srcRowStride
,
1251 ASSERT(outWidth
>= inWidth
);
1252 ASSERT(outHeight
>= inHeight
);
1254 ASSERT(inWidth
== 1 || inWidth
== 2 || inHeight
== 1 || inHeight
== 2);
1255 ASSERT((outWidth
& 3) == 0);
1256 ASSERT((outHeight
& 3) == 0);
1259 for (i
= 0; i
< outHeight
; i
++) {
1260 const GLint ii
= i
% inHeight
;
1261 for (j
= 0; j
< outWidth
; j
++) {
1262 const GLint jj
= j
% inWidth
;
1263 for (k
= 0; k
< comps
; k
++) {
1264 dest
[(i
* outWidth
+ j
) * comps
+ k
]
1265 = src
[ii
* srcRowStride
+ jj
* comps
+ k
];