1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Mipmap generation utility
36 #include "pipe/p_context.h"
37 #include "pipe/p_debug.h"
38 #include "pipe/p_defines.h"
39 #include "pipe/p_inlines.h"
40 #include "pipe/p_util.h"
41 #include "pipe/p_winsys.h"
42 #include "pipe/p_shader_tokens.h"
44 #include "util/u_draw_quad.h"
45 #include "util/u_gen_mipmap.h"
46 #include "util/u_simple_shaders.h"
48 #include "tgsi/util/tgsi_build.h"
49 #include "tgsi/util/tgsi_dump.h"
50 #include "tgsi/util/tgsi_parse.h"
52 #include "cso_cache/cso_context.h"
55 struct gen_mipmap_state
57 struct pipe_context
*pipe
;
58 struct cso_context
*cso
;
60 struct pipe_blend_state blend
;
61 struct pipe_depth_stencil_alpha_state depthstencil
;
62 struct pipe_rasterizer_state rasterizer
;
63 struct pipe_sampler_state sampler
;
64 struct pipe_viewport_state viewport
;
66 struct pipe_shader_state vert_shader
;
67 struct pipe_shader_state frag_shader
;
71 struct pipe_buffer
*vbuf
; /**< quad vertices */
72 float vertices
[4][2][4]; /**< vertex/texcoords for quad */
91 typedef ushort half_float
;
96 float_to_half(float f
);
99 half_to_float(half_float h
);
104 * Average together two rows of a source image to produce a single new
105 * row in the dest image. It's legal for the two source rows to point
106 * to the same data. The source width must be equal to either the
107 * dest width or two times the dest width.
108 * \param datatype GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
109 * \param comps number of components per pixel (1..4)
112 do_row(enum dtype datatype
, uint comps
, int srcWidth
,
113 const void *srcRowA
, const void *srcRowB
,
114 int dstWidth
, void *dstRow
)
116 const uint k0
= (srcWidth
== dstWidth
) ? 0 : 1;
117 const uint colStride
= (srcWidth
== dstWidth
) ? 1 : 2;
122 /* This assertion is no longer valid with non-power-of-2 textures
123 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
126 if (datatype
== UBYTE
&& comps
== 4) {
128 const ubyte(*rowA
)[4] = (const ubyte(*)[4]) srcRowA
;
129 const ubyte(*rowB
)[4] = (const ubyte(*)[4]) srcRowB
;
130 ubyte(*dst
)[4] = (ubyte(*)[4]) dstRow
;
131 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
132 i
++, j
+= colStride
, k
+= colStride
) {
133 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
134 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
135 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
136 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
139 else if (datatype
== UBYTE
&& comps
== 3) {
141 const ubyte(*rowA
)[3] = (const ubyte(*)[3]) srcRowA
;
142 const ubyte(*rowB
)[3] = (const ubyte(*)[3]) srcRowB
;
143 ubyte(*dst
)[3] = (ubyte(*)[3]) dstRow
;
144 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
145 i
++, j
+= colStride
, k
+= colStride
) {
146 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
147 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
148 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
151 else if (datatype
== UBYTE
&& comps
== 2) {
153 const ubyte(*rowA
)[2] = (const ubyte(*)[2]) srcRowA
;
154 const ubyte(*rowB
)[2] = (const ubyte(*)[2]) srcRowB
;
155 ubyte(*dst
)[2] = (ubyte(*)[2]) dstRow
;
156 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
157 i
++, j
+= colStride
, k
+= colStride
) {
158 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) >> 2;
159 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) >> 2;
162 else if (datatype
== UBYTE
&& comps
== 1) {
164 const ubyte
*rowA
= (const ubyte
*) srcRowA
;
165 const ubyte
*rowB
= (const ubyte
*) srcRowB
;
166 ubyte
*dst
= (ubyte
*) dstRow
;
167 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
168 i
++, j
+= colStride
, k
+= colStride
) {
169 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) >> 2;
173 else if (datatype
== USHORT
&& comps
== 4) {
175 const ushort(*rowA
)[4] = (const ushort(*)[4]) srcRowA
;
176 const ushort(*rowB
)[4] = (const ushort(*)[4]) srcRowB
;
177 ushort(*dst
)[4] = (ushort(*)[4]) dstRow
;
178 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
179 i
++, j
+= colStride
, k
+= colStride
) {
180 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
181 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
182 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
183 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
186 else if (datatype
== USHORT
&& comps
== 3) {
188 const ushort(*rowA
)[3] = (const ushort(*)[3]) srcRowA
;
189 const ushort(*rowB
)[3] = (const ushort(*)[3]) srcRowB
;
190 ushort(*dst
)[3] = (ushort(*)[3]) dstRow
;
191 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
192 i
++, j
+= colStride
, k
+= colStride
) {
193 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
194 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
195 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
198 else if (datatype
== USHORT
&& comps
== 2) {
200 const ushort(*rowA
)[2] = (const ushort(*)[2]) srcRowA
;
201 const ushort(*rowB
)[2] = (const ushort(*)[2]) srcRowB
;
202 ushort(*dst
)[2] = (ushort(*)[2]) dstRow
;
203 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
204 i
++, j
+= colStride
, k
+= colStride
) {
205 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
206 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
209 else if (datatype
== USHORT
&& comps
== 1) {
211 const ushort
*rowA
= (const ushort
*) srcRowA
;
212 const ushort
*rowB
= (const ushort
*) srcRowB
;
213 ushort
*dst
= (ushort
*) dstRow
;
214 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
215 i
++, j
+= colStride
, k
+= colStride
) {
216 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) / 4;
220 else if (datatype
== FLOAT
&& comps
== 4) {
222 const float(*rowA
)[4] = (const float(*)[4]) srcRowA
;
223 const float(*rowB
)[4] = (const float(*)[4]) srcRowB
;
224 float(*dst
)[4] = (float(*)[4]) dstRow
;
225 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
226 i
++, j
+= colStride
, k
+= colStride
) {
227 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
228 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
229 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
230 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
231 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
232 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
233 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
234 rowB
[j
][3] + rowB
[k
][3]) * 0.25F
;
237 else if (datatype
== FLOAT
&& comps
== 3) {
239 const float(*rowA
)[3] = (const float(*)[3]) srcRowA
;
240 const float(*rowB
)[3] = (const float(*)[3]) srcRowB
;
241 float(*dst
)[3] = (float(*)[3]) dstRow
;
242 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
243 i
++, j
+= colStride
, k
+= colStride
) {
244 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
245 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
246 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
247 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
248 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
249 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
252 else if (datatype
== FLOAT
&& comps
== 2) {
254 const float(*rowA
)[2] = (const float(*)[2]) srcRowA
;
255 const float(*rowB
)[2] = (const float(*)[2]) srcRowB
;
256 float(*dst
)[2] = (float(*)[2]) dstRow
;
257 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
258 i
++, j
+= colStride
, k
+= colStride
) {
259 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
260 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
261 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
262 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
265 else if (datatype
== FLOAT
&& comps
== 1) {
267 const float *rowA
= (const float *) srcRowA
;
268 const float *rowB
= (const float *) srcRowB
;
269 float *dst
= (float *) dstRow
;
270 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
271 i
++, j
+= colStride
, k
+= colStride
) {
272 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) * 0.25F
;
277 else if (datatype
== HALF_FLOAT
&& comps
== 4) {
279 const half_float(*rowA
)[4] = (const half_float(*)[4]) srcRowA
;
280 const half_float(*rowB
)[4] = (const half_float(*)[4]) srcRowB
;
281 half_float(*dst
)[4] = (half_float(*)[4]) dstRow
;
282 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
283 i
++, j
+= colStride
, k
+= colStride
) {
284 for (comp
= 0; comp
< 4; comp
++) {
285 float aj
, ak
, bj
, bk
;
286 aj
= half_to_float(rowA
[j
][comp
]);
287 ak
= half_to_float(rowA
[k
][comp
]);
288 bj
= half_to_float(rowB
[j
][comp
]);
289 bk
= half_to_float(rowB
[k
][comp
]);
290 dst
[i
][comp
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
294 else if (datatype
== HALF_FLOAT
&& comps
== 3) {
296 const half_float(*rowA
)[3] = (const half_float(*)[3]) srcRowA
;
297 const half_float(*rowB
)[3] = (const half_float(*)[3]) srcRowB
;
298 half_float(*dst
)[3] = (half_float(*)[3]) dstRow
;
299 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
300 i
++, j
+= colStride
, k
+= colStride
) {
301 for (comp
= 0; comp
< 3; comp
++) {
302 float aj
, ak
, bj
, bk
;
303 aj
= half_to_float(rowA
[j
][comp
]);
304 ak
= half_to_float(rowA
[k
][comp
]);
305 bj
= half_to_float(rowB
[j
][comp
]);
306 bk
= half_to_float(rowB
[k
][comp
]);
307 dst
[i
][comp
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
311 else if (datatype
== HALF_FLOAT
&& comps
== 2) {
313 const half_float(*rowA
)[2] = (const half_float(*)[2]) srcRowA
;
314 const half_float(*rowB
)[2] = (const half_float(*)[2]) srcRowB
;
315 half_float(*dst
)[2] = (half_float(*)[2]) dstRow
;
316 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
317 i
++, j
+= colStride
, k
+= colStride
) {
318 for (comp
= 0; comp
< 2; comp
++) {
319 float aj
, ak
, bj
, bk
;
320 aj
= half_to_float(rowA
[j
][comp
]);
321 ak
= half_to_float(rowA
[k
][comp
]);
322 bj
= half_to_float(rowB
[j
][comp
]);
323 bk
= half_to_float(rowB
[k
][comp
]);
324 dst
[i
][comp
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
328 else if (datatype
== HALF_FLOAT
&& comps
== 1) {
330 const half_float
*rowA
= (const half_float
*) srcRowA
;
331 const half_float
*rowB
= (const half_float
*) srcRowB
;
332 half_float
*dst
= (half_float
*) dstRow
;
333 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
334 i
++, j
+= colStride
, k
+= colStride
) {
335 float aj
, ak
, bj
, bk
;
336 aj
= half_to_float(rowA
[j
]);
337 ak
= half_to_float(rowA
[k
]);
338 bj
= half_to_float(rowB
[j
]);
339 bk
= half_to_float(rowB
[k
]);
340 dst
[i
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
345 else if (datatype
== UINT
&& comps
== 1) {
347 const uint
*rowA
= (const uint
*) srcRowA
;
348 const uint
*rowB
= (const uint
*) srcRowB
;
349 uint
*dst
= (uint
*) dstRow
;
350 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
351 i
++, j
+= colStride
, k
+= colStride
) {
352 dst
[i
] = rowA
[j
] / 4 + rowA
[k
] / 4 + rowB
[j
] / 4 + rowB
[k
] / 4;
356 else if (datatype
== USHORT_5_6_5
&& comps
== 3) {
358 const ushort
*rowA
= (const ushort
*) srcRowA
;
359 const ushort
*rowB
= (const ushort
*) srcRowB
;
360 ushort
*dst
= (ushort
*) dstRow
;
361 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
362 i
++, j
+= colStride
, k
+= colStride
) {
363 const int rowAr0
= rowA
[j
] & 0x1f;
364 const int rowAr1
= rowA
[k
] & 0x1f;
365 const int rowBr0
= rowB
[j
] & 0x1f;
366 const int rowBr1
= rowB
[k
] & 0x1f;
367 const int rowAg0
= (rowA
[j
] >> 5) & 0x3f;
368 const int rowAg1
= (rowA
[k
] >> 5) & 0x3f;
369 const int rowBg0
= (rowB
[j
] >> 5) & 0x3f;
370 const int rowBg1
= (rowB
[k
] >> 5) & 0x3f;
371 const int rowAb0
= (rowA
[j
] >> 11) & 0x1f;
372 const int rowAb1
= (rowA
[k
] >> 11) & 0x1f;
373 const int rowBb0
= (rowB
[j
] >> 11) & 0x1f;
374 const int rowBb1
= (rowB
[k
] >> 11) & 0x1f;
375 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
376 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
377 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
378 dst
[i
] = (blue
<< 11) | (green
<< 5) | red
;
381 else if (datatype
== USHORT_4_4_4_4
&& comps
== 4) {
383 const ushort
*rowA
= (const ushort
*) srcRowA
;
384 const ushort
*rowB
= (const ushort
*) srcRowB
;
385 ushort
*dst
= (ushort
*) dstRow
;
386 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
387 i
++, j
+= colStride
, k
+= colStride
) {
388 const int rowAr0
= rowA
[j
] & 0xf;
389 const int rowAr1
= rowA
[k
] & 0xf;
390 const int rowBr0
= rowB
[j
] & 0xf;
391 const int rowBr1
= rowB
[k
] & 0xf;
392 const int rowAg0
= (rowA
[j
] >> 4) & 0xf;
393 const int rowAg1
= (rowA
[k
] >> 4) & 0xf;
394 const int rowBg0
= (rowB
[j
] >> 4) & 0xf;
395 const int rowBg1
= (rowB
[k
] >> 4) & 0xf;
396 const int rowAb0
= (rowA
[j
] >> 8) & 0xf;
397 const int rowAb1
= (rowA
[k
] >> 8) & 0xf;
398 const int rowBb0
= (rowB
[j
] >> 8) & 0xf;
399 const int rowBb1
= (rowB
[k
] >> 8) & 0xf;
400 const int rowAa0
= (rowA
[j
] >> 12) & 0xf;
401 const int rowAa1
= (rowA
[k
] >> 12) & 0xf;
402 const int rowBa0
= (rowB
[j
] >> 12) & 0xf;
403 const int rowBa1
= (rowB
[k
] >> 12) & 0xf;
404 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
405 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
406 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
407 const int alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
408 dst
[i
] = (alpha
<< 12) | (blue
<< 8) | (green
<< 4) | red
;
411 else if (datatype
== USHORT_1_5_5_5_REV
&& comps
== 4) {
413 const ushort
*rowA
= (const ushort
*) srcRowA
;
414 const ushort
*rowB
= (const ushort
*) srcRowB
;
415 ushort
*dst
= (ushort
*) dstRow
;
416 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
417 i
++, j
+= colStride
, k
+= colStride
) {
418 const int rowAr0
= rowA
[j
] & 0x1f;
419 const int rowAr1
= rowA
[k
] & 0x1f;
420 const int rowBr0
= rowB
[j
] & 0x1f;
421 const int rowBr1
= rowB
[k
] & 0xf;
422 const int rowAg0
= (rowA
[j
] >> 5) & 0x1f;
423 const int rowAg1
= (rowA
[k
] >> 5) & 0x1f;
424 const int rowBg0
= (rowB
[j
] >> 5) & 0x1f;
425 const int rowBg1
= (rowB
[k
] >> 5) & 0x1f;
426 const int rowAb0
= (rowA
[j
] >> 10) & 0x1f;
427 const int rowAb1
= (rowA
[k
] >> 10) & 0x1f;
428 const int rowBb0
= (rowB
[j
] >> 10) & 0x1f;
429 const int rowBb1
= (rowB
[k
] >> 10) & 0x1f;
430 const int rowAa0
= (rowA
[j
] >> 15) & 0x1;
431 const int rowAa1
= (rowA
[k
] >> 15) & 0x1;
432 const int rowBa0
= (rowB
[j
] >> 15) & 0x1;
433 const int rowBa1
= (rowB
[k
] >> 15) & 0x1;
434 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
435 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
436 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
437 const int alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
438 dst
[i
] = (alpha
<< 15) | (blue
<< 10) | (green
<< 5) | red
;
441 else if (datatype
== UBYTE_3_3_2
&& comps
== 3) {
443 const ubyte
*rowA
= (const ubyte
*) srcRowA
;
444 const ubyte
*rowB
= (const ubyte
*) srcRowB
;
445 ubyte
*dst
= (ubyte
*) dstRow
;
446 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
447 i
++, j
+= colStride
, k
+= colStride
) {
448 const int rowAr0
= rowA
[j
] & 0x3;
449 const int rowAr1
= rowA
[k
] & 0x3;
450 const int rowBr0
= rowB
[j
] & 0x3;
451 const int rowBr1
= rowB
[k
] & 0x3;
452 const int rowAg0
= (rowA
[j
] >> 2) & 0x7;
453 const int rowAg1
= (rowA
[k
] >> 2) & 0x7;
454 const int rowBg0
= (rowB
[j
] >> 2) & 0x7;
455 const int rowBg1
= (rowB
[k
] >> 2) & 0x7;
456 const int rowAb0
= (rowA
[j
] >> 5) & 0x7;
457 const int rowAb1
= (rowA
[k
] >> 5) & 0x7;
458 const int rowBb0
= (rowB
[j
] >> 5) & 0x7;
459 const int rowBb1
= (rowB
[k
] >> 5) & 0x7;
460 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
461 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
462 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
463 dst
[i
] = (blue
<< 5) | (green
<< 2) | red
;
467 debug_printf("bad format in do_row()");
473 format_to_type_comps(enum pipe_format pformat
,
474 enum dtype
*datatype
, uint
*comps
)
477 case PIPE_FORMAT_A8R8G8B8_UNORM
:
478 case PIPE_FORMAT_B8G8R8A8_UNORM
:
482 case PIPE_FORMAT_A1R5G5B5_UNORM
:
483 *datatype
= USHORT_1_5_5_5_REV
;
486 case PIPE_FORMAT_A4R4G4B4_UNORM
:
487 *datatype
= USHORT_4_4_4_4
;
490 case PIPE_FORMAT_R5G6B5_UNORM
:
491 *datatype
= USHORT_5_6_5
;
494 case PIPE_FORMAT_U_L8
:
495 case PIPE_FORMAT_U_A8
:
496 case PIPE_FORMAT_U_I8
:
500 case PIPE_FORMAT_U_A8_L8
:
511 reduce_1d(enum pipe_format pformat
,
512 int srcWidth
, const ubyte
*srcPtr
,
513 int dstWidth
, ubyte
*dstPtr
)
518 format_to_type_comps(pformat
, &datatype
, &comps
);
520 /* we just duplicate the input row, kind of hack, saves code */
521 do_row(datatype
, comps
,
522 srcWidth
, srcPtr
, srcPtr
,
528 * Strides are in bytes. If zero, it'll be computed as width * bpp.
531 reduce_2d(enum pipe_format pformat
,
532 int srcWidth
, int srcHeight
,
533 int srcRowStride
, const ubyte
*srcPtr
,
534 int dstWidth
, int dstHeight
,
535 int dstRowStride
, ubyte
*dstPtr
)
539 const int bpt
= pf_get_size(pformat
);
540 const ubyte
*srcA
, *srcB
;
544 format_to_type_comps(pformat
, &datatype
, &comps
);
547 srcRowStride
= bpt
* srcWidth
;
550 dstRowStride
= bpt
* dstWidth
;
552 /* Compute src and dst pointers */
555 srcB
= srcA
+ srcRowStride
;
560 for (row
= 0; row
< dstHeight
; row
++) {
561 do_row(datatype
, comps
,
562 srcWidth
, srcA
, srcB
,
564 srcA
+= 2 * srcRowStride
;
565 srcB
+= 2 * srcRowStride
;
572 make_1d_mipmap(struct gen_mipmap_state
*ctx
,
573 struct pipe_texture
*pt
,
574 uint face
, uint baseLevel
, uint lastLevel
)
576 struct pipe_context
*pipe
= ctx
->pipe
;
577 struct pipe_screen
*screen
= pipe
->screen
;
578 struct pipe_winsys
*winsys
= pipe
->winsys
;
579 const uint zslice
= 0;
582 for (dstLevel
= baseLevel
+ 1; dstLevel
<= lastLevel
; dstLevel
++) {
583 const uint srcLevel
= dstLevel
- 1;
584 struct pipe_surface
*srcSurf
, *dstSurf
;
585 void *srcMap
, *dstMap
;
587 srcSurf
= screen
->get_tex_surface(screen
, pt
, face
, srcLevel
, zslice
);
588 dstSurf
= screen
->get_tex_surface(screen
, pt
, face
, dstLevel
, zslice
);
590 srcMap
= ((ubyte
*) winsys
->buffer_map(winsys
, srcSurf
->buffer
,
591 PIPE_BUFFER_USAGE_CPU_READ
)
593 dstMap
= ((ubyte
*) winsys
->buffer_map(winsys
, dstSurf
->buffer
,
594 PIPE_BUFFER_USAGE_CPU_WRITE
)
597 reduce_1d(pt
->format
,
598 srcSurf
->width
, srcMap
,
599 dstSurf
->width
, dstMap
);
601 winsys
->buffer_unmap(winsys
, srcSurf
->buffer
);
602 winsys
->buffer_unmap(winsys
, dstSurf
->buffer
);
604 pipe_surface_reference(&srcSurf
, NULL
);
605 pipe_surface_reference(&dstSurf
, NULL
);
611 make_2d_mipmap(struct gen_mipmap_state
*ctx
,
612 struct pipe_texture
*pt
,
613 uint face
, uint baseLevel
, uint lastLevel
)
615 struct pipe_context
*pipe
= ctx
->pipe
;
616 struct pipe_screen
*screen
= pipe
->screen
;
617 struct pipe_winsys
*winsys
= pipe
->winsys
;
618 const uint zslice
= 0;
620 const int bpt
= pf_get_size(pt
->format
);
622 for (dstLevel
= baseLevel
+ 1; dstLevel
<= lastLevel
; dstLevel
++) {
623 const uint srcLevel
= dstLevel
- 1;
624 struct pipe_surface
*srcSurf
, *dstSurf
;
625 ubyte
*srcMap
, *dstMap
;
627 srcSurf
= screen
->get_tex_surface(screen
, pt
, face
, srcLevel
, zslice
);
628 dstSurf
= screen
->get_tex_surface(screen
, pt
, face
, dstLevel
, zslice
);
630 srcMap
= ((ubyte
*) winsys
->buffer_map(winsys
, srcSurf
->buffer
,
631 PIPE_BUFFER_USAGE_CPU_READ
)
633 dstMap
= ((ubyte
*) winsys
->buffer_map(winsys
, dstSurf
->buffer
,
634 PIPE_BUFFER_USAGE_CPU_WRITE
)
637 reduce_2d(pt
->format
,
638 srcSurf
->width
, srcSurf
->height
,
639 srcSurf
->pitch
* bpt
, srcMap
,
640 dstSurf
->width
, dstSurf
->height
,
641 dstSurf
->pitch
* bpt
, dstMap
);
643 winsys
->buffer_unmap(winsys
, srcSurf
->buffer
);
644 winsys
->buffer_unmap(winsys
, dstSurf
->buffer
);
646 pipe_surface_reference(&srcSurf
, NULL
);
647 pipe_surface_reference(&dstSurf
, NULL
);
653 make_3d_mipmap(struct gen_mipmap_state
*ctx
,
654 struct pipe_texture
*pt
,
655 uint face
, uint baseLevel
, uint lastLevel
)
661 fallback_gen_mipmap(struct gen_mipmap_state
*ctx
,
662 struct pipe_texture
*pt
,
663 uint face
, uint baseLevel
, uint lastLevel
)
665 switch (pt
->target
) {
666 case PIPE_TEXTURE_1D
:
667 make_1d_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
669 case PIPE_TEXTURE_2D
:
670 case PIPE_TEXTURE_CUBE
:
671 make_2d_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
673 case PIPE_TEXTURE_3D
:
674 make_3d_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
683 * Create a mipmap generation context.
684 * The idea is to create one of these and re-use it each time we need to
687 struct gen_mipmap_state
*
688 util_create_gen_mipmap(struct pipe_context
*pipe
,
689 struct cso_context
*cso
)
691 struct gen_mipmap_state
*ctx
;
694 ctx
= CALLOC_STRUCT(gen_mipmap_state
);
701 /* disabled blending/masking */
702 memset(&ctx
->blend
, 0, sizeof(ctx
->blend
));
703 ctx
->blend
.rgb_src_factor
= PIPE_BLENDFACTOR_ONE
;
704 ctx
->blend
.alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
705 ctx
->blend
.rgb_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
706 ctx
->blend
.alpha_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
707 ctx
->blend
.colormask
= PIPE_MASK_RGBA
;
709 /* no-op depth/stencil/alpha */
710 memset(&ctx
->depthstencil
, 0, sizeof(ctx
->depthstencil
));
713 memset(&ctx
->rasterizer
, 0, sizeof(ctx
->rasterizer
));
714 ctx
->rasterizer
.front_winding
= PIPE_WINDING_CW
;
715 ctx
->rasterizer
.cull_mode
= PIPE_WINDING_NONE
;
716 ctx
->rasterizer
.bypass_clipping
= 1; /* bypasses viewport too */
717 /*ctx->rasterizer.bypass_vs = 1;*/
720 memset(&ctx
->sampler
, 0, sizeof(ctx
->sampler
));
721 ctx
->sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
722 ctx
->sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
723 ctx
->sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
724 ctx
->sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
725 ctx
->sampler
.normalized_coords
= 1;
727 /* viewport state (identity, verts are in wincoords) */
728 ctx
->viewport
.scale
[0] = 1.0;
729 ctx
->viewport
.scale
[1] = 1.0;
730 ctx
->viewport
.scale
[2] = 1.0;
731 ctx
->viewport
.scale
[3] = 1.0;
732 ctx
->viewport
.translate
[0] = 0.0;
733 ctx
->viewport
.translate
[1] = 0.0;
734 ctx
->viewport
.translate
[2] = 0.0;
735 ctx
->viewport
.translate
[3] = 0.0;
739 const uint semantic_names
[] = { TGSI_SEMANTIC_POSITION
,
740 TGSI_SEMANTIC_GENERIC
};
741 const uint semantic_indexes
[] = { 0, 0 };
742 ctx
->vs
= util_make_vertex_passthrough_shader(pipe
, 2, semantic_names
,
747 /* fragment shader */
748 ctx
->fs
= util_make_fragment_tex_shader(pipe
, &ctx
->frag_shader
);
750 ctx
->vbuf
= pipe
->winsys
->buffer_create(pipe
->winsys
,
752 PIPE_BUFFER_USAGE_VERTEX
,
753 sizeof(ctx
->vertices
));
759 /* vertex data that doesn't change */
760 for (i
= 0; i
< 4; i
++) {
761 ctx
->vertices
[i
][0][2] = 0.0f
; /* z */
762 ctx
->vertices
[i
][0][3] = 1.0f
; /* w */
763 ctx
->vertices
[i
][1][2] = 0.0f
; /* r */
764 ctx
->vertices
[i
][1][3] = 1.0f
; /* q */
772 set_vertex_data(struct gen_mipmap_state
*ctx
, float width
, float height
)
776 ctx
->vertices
[0][0][0] = -0.5f
; /*x*/
777 ctx
->vertices
[0][0][1] = -0.5f
; /*y*/
778 ctx
->vertices
[0][1][0] = 0.0f
; /*s*/
779 ctx
->vertices
[0][1][1] = 0.0f
; /*t*/
781 ctx
->vertices
[1][0][0] = width
- 0.5f
; /*x*/
782 ctx
->vertices
[1][0][1] = -0.5f
; /*y*/
783 ctx
->vertices
[1][1][0] = 1.0f
; /*s*/
784 ctx
->vertices
[1][1][1] = 0.0f
; /*t*/
786 ctx
->vertices
[2][0][0] = width
- 0.5f
;
787 ctx
->vertices
[2][0][1] = height
- 0.5f
;
788 ctx
->vertices
[2][1][0] = 1.0f
;
789 ctx
->vertices
[2][1][1] = 1.0f
;
791 ctx
->vertices
[3][0][0] = -0.5f
;
792 ctx
->vertices
[3][0][1] = height
- 0.5f
;
793 ctx
->vertices
[3][1][0] = 0.0f
;
794 ctx
->vertices
[3][1][1] = 1.0f
;
796 buf
= ctx
->pipe
->winsys
->buffer_map(ctx
->pipe
->winsys
, ctx
->vbuf
,
797 PIPE_BUFFER_USAGE_CPU_WRITE
);
799 memcpy(buf
, ctx
->vertices
, sizeof(ctx
->vertices
));
801 ctx
->pipe
->winsys
->buffer_unmap(ctx
->pipe
->winsys
, ctx
->vbuf
);
807 * Destroy a mipmap generation context
810 util_destroy_gen_mipmap(struct gen_mipmap_state
*ctx
)
812 struct pipe_context
*pipe
= ctx
->pipe
;
814 pipe
->delete_vs_state(pipe
, ctx
->vs
);
815 pipe
->delete_fs_state(pipe
, ctx
->fs
);
817 FREE((void*) ctx
->vert_shader
.tokens
);
818 FREE((void*) ctx
->frag_shader
.tokens
);
820 pipe
->winsys
->buffer_destroy(pipe
->winsys
, ctx
->vbuf
);
827 * Generate mipmap images. It's assumed all needed texture memory is
830 * \param pt the texture to generate mipmap levels for
831 * \param face which cube face to generate mipmaps for (0 for non-cube maps)
832 * \param baseLevel the first mipmap level to use as a src
833 * \param lastLevel the last mipmap level to generate
834 * \param filter the minification filter used to generate mipmap levels with
835 * \param filter one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST
838 util_gen_mipmap(struct gen_mipmap_state
*ctx
,
839 struct pipe_texture
*pt
,
840 uint face
, uint baseLevel
, uint lastLevel
, uint filter
)
842 struct pipe_context
*pipe
= ctx
->pipe
;
843 struct pipe_screen
*screen
= pipe
->screen
;
844 struct pipe_framebuffer_state fb
;
848 /* check if we can render in the texture's format */
849 if (!screen
->is_format_supported(screen
, pt
->format
, PIPE_SURFACE
)) {
850 fallback_gen_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
854 /* save state (restored below) */
855 cso_save_blend(ctx
->cso
);
856 cso_save_depth_stencil_alpha(ctx
->cso
);
857 cso_save_rasterizer(ctx
->cso
);
858 cso_save_samplers(ctx
->cso
);
859 cso_save_sampler_textures(ctx
->cso
);
860 cso_save_framebuffer(ctx
->cso
);
861 cso_save_fragment_shader(ctx
->cso
);
862 cso_save_vertex_shader(ctx
->cso
);
863 cso_save_viewport(ctx
->cso
);
866 cso_set_blend(ctx
->cso
, &ctx
->blend
);
867 cso_set_depth_stencil_alpha(ctx
->cso
, &ctx
->depthstencil
);
868 cso_set_rasterizer(ctx
->cso
, &ctx
->rasterizer
);
869 cso_set_viewport(ctx
->cso
, &ctx
->viewport
);
871 cso_set_fragment_shader_handle(ctx
->cso
, ctx
->fs
);
872 cso_set_vertex_shader_handle(ctx
->cso
, ctx
->vs
);
874 /* init framebuffer state */
875 memset(&fb
, 0, sizeof(fb
));
878 /* set min/mag to same filter for faster sw speed */
879 ctx
->sampler
.mag_img_filter
= filter
;
880 ctx
->sampler
.min_img_filter
= filter
;
883 * XXX for small mipmap levels, it may be faster to use the software
886 for (dstLevel
= baseLevel
+ 1; dstLevel
<= lastLevel
; dstLevel
++) {
887 const uint srcLevel
= dstLevel
- 1;
890 * Setup framebuffer / dest surface
892 fb
.cbufs
[0] = screen
->get_tex_surface(screen
, pt
, face
, dstLevel
, zslice
);
893 fb
.width
= pt
->width
[dstLevel
];
894 fb
.height
= pt
->height
[dstLevel
];
895 cso_set_framebuffer(ctx
->cso
, &fb
);
898 * Setup sampler state
899 * Note: we should only have to set the min/max LOD clamps to ensure
900 * we grab texels from the right mipmap level. But some hardware
901 * has trouble with min clamping so we also set the lod_bias to
902 * try to work around that.
904 ctx
->sampler
.min_lod
= ctx
->sampler
.max_lod
= (float) srcLevel
;
905 ctx
->sampler
.lod_bias
= (float) srcLevel
;
906 cso_single_sampler(ctx
->cso
, 0, &ctx
->sampler
);
907 cso_single_sampler_done(ctx
->cso
);
909 cso_set_sampler_textures(ctx
->cso
, 1, &pt
);
911 /* quad coords in window coords (bypassing clipping, viewport mapping) */
913 (float) pt
->width
[dstLevel
],
914 (float) pt
->height
[dstLevel
]);
915 util_draw_vertex_buffer(ctx
->pipe
, ctx
->vbuf
,
916 PIPE_PRIM_TRIANGLE_FAN
,
918 2); /* attribs/vert */
920 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
922 /* need to signal that the texture has changed _after_ rendering to it */
923 pipe
->texture_update(pipe
, pt
, face
, (1 << dstLevel
));
926 /* restore state we changed */
927 cso_restore_blend(ctx
->cso
);
928 cso_restore_depth_stencil_alpha(ctx
->cso
);
929 cso_restore_rasterizer(ctx
->cso
);
930 cso_restore_samplers(ctx
->cso
);
931 cso_restore_sampler_textures(ctx
->cso
);
932 cso_restore_framebuffer(ctx
->cso
);
933 cso_restore_fragment_shader(ctx
->cso
);
934 cso_restore_vertex_shader(ctx
->cso
);
935 cso_restore_viewport(ctx
->cso
);