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;*/
65 struct pipe_sampler_state
*vs
;
66 struct pipe_sampler_state
*fs
;
68 struct pipe_buffer
*vbuf
; /**< quad vertices */
69 float vertices
[4][2][4]; /**< vertex/texcoords for quad */
88 typedef ushort half_float
;
93 float_to_half(float f
);
96 half_to_float(half_float h
);
101 * Average together two rows of a source image to produce a single new
102 * row in the dest image. It's legal for the two source rows to point
103 * to the same data. The source width must be equal to either the
104 * dest width or two times the dest width.
105 * \param datatype GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
106 * \param comps number of components per pixel (1..4)
109 do_row(enum dtype datatype
, uint comps
, int srcWidth
,
110 const void *srcRowA
, const void *srcRowB
,
111 int dstWidth
, void *dstRow
)
113 const uint k0
= (srcWidth
== dstWidth
) ? 0 : 1;
114 const uint colStride
= (srcWidth
== dstWidth
) ? 1 : 2;
119 /* This assertion is no longer valid with non-power-of-2 textures
120 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
123 if (datatype
== UBYTE
&& comps
== 4) {
125 const ubyte(*rowA
)[4] = (const ubyte(*)[4]) srcRowA
;
126 const ubyte(*rowB
)[4] = (const ubyte(*)[4]) srcRowB
;
127 ubyte(*dst
)[4] = (ubyte(*)[4]) dstRow
;
128 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
129 i
++, j
+= colStride
, k
+= colStride
) {
130 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
131 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
132 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
133 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
136 else if (datatype
== UBYTE
&& comps
== 3) {
138 const ubyte(*rowA
)[3] = (const ubyte(*)[3]) srcRowA
;
139 const ubyte(*rowB
)[3] = (const ubyte(*)[3]) srcRowB
;
140 ubyte(*dst
)[3] = (ubyte(*)[3]) dstRow
;
141 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
142 i
++, j
+= colStride
, k
+= colStride
) {
143 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
144 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
145 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
148 else if (datatype
== UBYTE
&& comps
== 2) {
150 const ubyte(*rowA
)[2] = (const ubyte(*)[2]) srcRowA
;
151 const ubyte(*rowB
)[2] = (const ubyte(*)[2]) srcRowB
;
152 ubyte(*dst
)[2] = (ubyte(*)[2]) dstRow
;
153 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
154 i
++, j
+= colStride
, k
+= colStride
) {
155 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) >> 2;
156 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) >> 2;
159 else if (datatype
== UBYTE
&& comps
== 1) {
161 const ubyte
*rowA
= (const ubyte
*) srcRowA
;
162 const ubyte
*rowB
= (const ubyte
*) srcRowB
;
163 ubyte
*dst
= (ubyte
*) dstRow
;
164 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
165 i
++, j
+= colStride
, k
+= colStride
) {
166 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) >> 2;
170 else if (datatype
== USHORT
&& comps
== 4) {
172 const ushort(*rowA
)[4] = (const ushort(*)[4]) srcRowA
;
173 const ushort(*rowB
)[4] = (const ushort(*)[4]) srcRowB
;
174 ushort(*dst
)[4] = (ushort(*)[4]) dstRow
;
175 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
176 i
++, j
+= colStride
, k
+= colStride
) {
177 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
178 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
179 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
180 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] + rowB
[j
][3] + rowB
[k
][3]) / 4;
183 else if (datatype
== USHORT
&& comps
== 3) {
185 const ushort(*rowA
)[3] = (const ushort(*)[3]) srcRowA
;
186 const ushort(*rowB
)[3] = (const ushort(*)[3]) srcRowB
;
187 ushort(*dst
)[3] = (ushort(*)[3]) dstRow
;
188 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
189 i
++, j
+= colStride
, k
+= colStride
) {
190 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
191 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
192 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] + rowB
[j
][2] + rowB
[k
][2]) / 4;
195 else if (datatype
== USHORT
&& comps
== 2) {
197 const ushort(*rowA
)[2] = (const ushort(*)[2]) srcRowA
;
198 const ushort(*rowB
)[2] = (const ushort(*)[2]) srcRowB
;
199 ushort(*dst
)[2] = (ushort(*)[2]) dstRow
;
200 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
201 i
++, j
+= colStride
, k
+= colStride
) {
202 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] + rowB
[j
][0] + rowB
[k
][0]) / 4;
203 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] + rowB
[j
][1] + rowB
[k
][1]) / 4;
206 else if (datatype
== USHORT
&& comps
== 1) {
208 const ushort
*rowA
= (const ushort
*) srcRowA
;
209 const ushort
*rowB
= (const ushort
*) srcRowB
;
210 ushort
*dst
= (ushort
*) dstRow
;
211 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
212 i
++, j
+= colStride
, k
+= colStride
) {
213 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) / 4;
217 else if (datatype
== FLOAT
&& comps
== 4) {
219 const float(*rowA
)[4] = (const float(*)[4]) srcRowA
;
220 const float(*rowB
)[4] = (const float(*)[4]) srcRowB
;
221 float(*dst
)[4] = (float(*)[4]) dstRow
;
222 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
223 i
++, j
+= colStride
, k
+= colStride
) {
224 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
225 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
226 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
227 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
228 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
229 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
230 dst
[i
][3] = (rowA
[j
][3] + rowA
[k
][3] +
231 rowB
[j
][3] + rowB
[k
][3]) * 0.25F
;
234 else if (datatype
== FLOAT
&& comps
== 3) {
236 const float(*rowA
)[3] = (const float(*)[3]) srcRowA
;
237 const float(*rowB
)[3] = (const float(*)[3]) srcRowB
;
238 float(*dst
)[3] = (float(*)[3]) dstRow
;
239 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
240 i
++, j
+= colStride
, k
+= colStride
) {
241 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
242 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
243 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
244 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
245 dst
[i
][2] = (rowA
[j
][2] + rowA
[k
][2] +
246 rowB
[j
][2] + rowB
[k
][2]) * 0.25F
;
249 else if (datatype
== FLOAT
&& comps
== 2) {
251 const float(*rowA
)[2] = (const float(*)[2]) srcRowA
;
252 const float(*rowB
)[2] = (const float(*)[2]) srcRowB
;
253 float(*dst
)[2] = (float(*)[2]) dstRow
;
254 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
255 i
++, j
+= colStride
, k
+= colStride
) {
256 dst
[i
][0] = (rowA
[j
][0] + rowA
[k
][0] +
257 rowB
[j
][0] + rowB
[k
][0]) * 0.25F
;
258 dst
[i
][1] = (rowA
[j
][1] + rowA
[k
][1] +
259 rowB
[j
][1] + rowB
[k
][1]) * 0.25F
;
262 else if (datatype
== FLOAT
&& comps
== 1) {
264 const float *rowA
= (const float *) srcRowA
;
265 const float *rowB
= (const float *) srcRowB
;
266 float *dst
= (float *) dstRow
;
267 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
268 i
++, j
+= colStride
, k
+= colStride
) {
269 dst
[i
] = (rowA
[j
] + rowA
[k
] + rowB
[j
] + rowB
[k
]) * 0.25F
;
274 else if (datatype
== HALF_FLOAT
&& comps
== 4) {
276 const half_float(*rowA
)[4] = (const half_float(*)[4]) srcRowA
;
277 const half_float(*rowB
)[4] = (const half_float(*)[4]) srcRowB
;
278 half_float(*dst
)[4] = (half_float(*)[4]) dstRow
;
279 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
280 i
++, j
+= colStride
, k
+= colStride
) {
281 for (comp
= 0; comp
< 4; comp
++) {
282 float aj
, ak
, bj
, bk
;
283 aj
= half_to_float(rowA
[j
][comp
]);
284 ak
= half_to_float(rowA
[k
][comp
]);
285 bj
= half_to_float(rowB
[j
][comp
]);
286 bk
= half_to_float(rowB
[k
][comp
]);
287 dst
[i
][comp
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
291 else if (datatype
== HALF_FLOAT
&& comps
== 3) {
293 const half_float(*rowA
)[3] = (const half_float(*)[3]) srcRowA
;
294 const half_float(*rowB
)[3] = (const half_float(*)[3]) srcRowB
;
295 half_float(*dst
)[3] = (half_float(*)[3]) dstRow
;
296 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
297 i
++, j
+= colStride
, k
+= colStride
) {
298 for (comp
= 0; comp
< 3; comp
++) {
299 float aj
, ak
, bj
, bk
;
300 aj
= half_to_float(rowA
[j
][comp
]);
301 ak
= half_to_float(rowA
[k
][comp
]);
302 bj
= half_to_float(rowB
[j
][comp
]);
303 bk
= half_to_float(rowB
[k
][comp
]);
304 dst
[i
][comp
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
308 else if (datatype
== HALF_FLOAT
&& comps
== 2) {
310 const half_float(*rowA
)[2] = (const half_float(*)[2]) srcRowA
;
311 const half_float(*rowB
)[2] = (const half_float(*)[2]) srcRowB
;
312 half_float(*dst
)[2] = (half_float(*)[2]) dstRow
;
313 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
314 i
++, j
+= colStride
, k
+= colStride
) {
315 for (comp
= 0; comp
< 2; comp
++) {
316 float aj
, ak
, bj
, bk
;
317 aj
= half_to_float(rowA
[j
][comp
]);
318 ak
= half_to_float(rowA
[k
][comp
]);
319 bj
= half_to_float(rowB
[j
][comp
]);
320 bk
= half_to_float(rowB
[k
][comp
]);
321 dst
[i
][comp
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
325 else if (datatype
== HALF_FLOAT
&& comps
== 1) {
327 const half_float
*rowA
= (const half_float
*) srcRowA
;
328 const half_float
*rowB
= (const half_float
*) srcRowB
;
329 half_float
*dst
= (half_float
*) dstRow
;
330 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
331 i
++, j
+= colStride
, k
+= colStride
) {
332 float aj
, ak
, bj
, bk
;
333 aj
= half_to_float(rowA
[j
]);
334 ak
= half_to_float(rowA
[k
]);
335 bj
= half_to_float(rowB
[j
]);
336 bk
= half_to_float(rowB
[k
]);
337 dst
[i
] = float_to_half((aj
+ ak
+ bj
+ bk
) * 0.25F
);
342 else if (datatype
== UINT
&& comps
== 1) {
344 const uint
*rowA
= (const uint
*) srcRowA
;
345 const uint
*rowB
= (const uint
*) srcRowB
;
346 uint
*dst
= (uint
*) dstRow
;
347 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
348 i
++, j
+= colStride
, k
+= colStride
) {
349 dst
[i
] = rowA
[j
] / 4 + rowA
[k
] / 4 + rowB
[j
] / 4 + rowB
[k
] / 4;
353 else if (datatype
== USHORT_5_6_5
&& comps
== 3) {
355 const ushort
*rowA
= (const ushort
*) srcRowA
;
356 const ushort
*rowB
= (const ushort
*) srcRowB
;
357 ushort
*dst
= (ushort
*) dstRow
;
358 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
359 i
++, j
+= colStride
, k
+= colStride
) {
360 const int rowAr0
= rowA
[j
] & 0x1f;
361 const int rowAr1
= rowA
[k
] & 0x1f;
362 const int rowBr0
= rowB
[j
] & 0x1f;
363 const int rowBr1
= rowB
[k
] & 0x1f;
364 const int rowAg0
= (rowA
[j
] >> 5) & 0x3f;
365 const int rowAg1
= (rowA
[k
] >> 5) & 0x3f;
366 const int rowBg0
= (rowB
[j
] >> 5) & 0x3f;
367 const int rowBg1
= (rowB
[k
] >> 5) & 0x3f;
368 const int rowAb0
= (rowA
[j
] >> 11) & 0x1f;
369 const int rowAb1
= (rowA
[k
] >> 11) & 0x1f;
370 const int rowBb0
= (rowB
[j
] >> 11) & 0x1f;
371 const int rowBb1
= (rowB
[k
] >> 11) & 0x1f;
372 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
373 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
374 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
375 dst
[i
] = (blue
<< 11) | (green
<< 5) | red
;
378 else if (datatype
== USHORT_4_4_4_4
&& comps
== 4) {
380 const ushort
*rowA
= (const ushort
*) srcRowA
;
381 const ushort
*rowB
= (const ushort
*) srcRowB
;
382 ushort
*dst
= (ushort
*) dstRow
;
383 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
384 i
++, j
+= colStride
, k
+= colStride
) {
385 const int rowAr0
= rowA
[j
] & 0xf;
386 const int rowAr1
= rowA
[k
] & 0xf;
387 const int rowBr0
= rowB
[j
] & 0xf;
388 const int rowBr1
= rowB
[k
] & 0xf;
389 const int rowAg0
= (rowA
[j
] >> 4) & 0xf;
390 const int rowAg1
= (rowA
[k
] >> 4) & 0xf;
391 const int rowBg0
= (rowB
[j
] >> 4) & 0xf;
392 const int rowBg1
= (rowB
[k
] >> 4) & 0xf;
393 const int rowAb0
= (rowA
[j
] >> 8) & 0xf;
394 const int rowAb1
= (rowA
[k
] >> 8) & 0xf;
395 const int rowBb0
= (rowB
[j
] >> 8) & 0xf;
396 const int rowBb1
= (rowB
[k
] >> 8) & 0xf;
397 const int rowAa0
= (rowA
[j
] >> 12) & 0xf;
398 const int rowAa1
= (rowA
[k
] >> 12) & 0xf;
399 const int rowBa0
= (rowB
[j
] >> 12) & 0xf;
400 const int rowBa1
= (rowB
[k
] >> 12) & 0xf;
401 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
402 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
403 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
404 const int alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
405 dst
[i
] = (alpha
<< 12) | (blue
<< 8) | (green
<< 4) | red
;
408 else if (datatype
== USHORT_1_5_5_5_REV
&& comps
== 4) {
410 const ushort
*rowA
= (const ushort
*) srcRowA
;
411 const ushort
*rowB
= (const ushort
*) srcRowB
;
412 ushort
*dst
= (ushort
*) dstRow
;
413 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
414 i
++, j
+= colStride
, k
+= colStride
) {
415 const int rowAr0
= rowA
[j
] & 0x1f;
416 const int rowAr1
= rowA
[k
] & 0x1f;
417 const int rowBr0
= rowB
[j
] & 0x1f;
418 const int rowBr1
= rowB
[k
] & 0xf;
419 const int rowAg0
= (rowA
[j
] >> 5) & 0x1f;
420 const int rowAg1
= (rowA
[k
] >> 5) & 0x1f;
421 const int rowBg0
= (rowB
[j
] >> 5) & 0x1f;
422 const int rowBg1
= (rowB
[k
] >> 5) & 0x1f;
423 const int rowAb0
= (rowA
[j
] >> 10) & 0x1f;
424 const int rowAb1
= (rowA
[k
] >> 10) & 0x1f;
425 const int rowBb0
= (rowB
[j
] >> 10) & 0x1f;
426 const int rowBb1
= (rowB
[k
] >> 10) & 0x1f;
427 const int rowAa0
= (rowA
[j
] >> 15) & 0x1;
428 const int rowAa1
= (rowA
[k
] >> 15) & 0x1;
429 const int rowBa0
= (rowB
[j
] >> 15) & 0x1;
430 const int rowBa1
= (rowB
[k
] >> 15) & 0x1;
431 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
432 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
433 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
434 const int alpha
= (rowAa0
+ rowAa1
+ rowBa0
+ rowBa1
) >> 2;
435 dst
[i
] = (alpha
<< 15) | (blue
<< 10) | (green
<< 5) | red
;
438 else if (datatype
== UBYTE_3_3_2
&& comps
== 3) {
440 const ubyte
*rowA
= (const ubyte
*) srcRowA
;
441 const ubyte
*rowB
= (const ubyte
*) srcRowB
;
442 ubyte
*dst
= (ubyte
*) dstRow
;
443 for (i
= j
= 0, k
= k0
; i
< (uint
) dstWidth
;
444 i
++, j
+= colStride
, k
+= colStride
) {
445 const int rowAr0
= rowA
[j
] & 0x3;
446 const int rowAr1
= rowA
[k
] & 0x3;
447 const int rowBr0
= rowB
[j
] & 0x3;
448 const int rowBr1
= rowB
[k
] & 0x3;
449 const int rowAg0
= (rowA
[j
] >> 2) & 0x7;
450 const int rowAg1
= (rowA
[k
] >> 2) & 0x7;
451 const int rowBg0
= (rowB
[j
] >> 2) & 0x7;
452 const int rowBg1
= (rowB
[k
] >> 2) & 0x7;
453 const int rowAb0
= (rowA
[j
] >> 5) & 0x7;
454 const int rowAb1
= (rowA
[k
] >> 5) & 0x7;
455 const int rowBb0
= (rowB
[j
] >> 5) & 0x7;
456 const int rowBb1
= (rowB
[k
] >> 5) & 0x7;
457 const int red
= (rowAr0
+ rowAr1
+ rowBr0
+ rowBr1
) >> 2;
458 const int green
= (rowAg0
+ rowAg1
+ rowBg0
+ rowBg1
) >> 2;
459 const int blue
= (rowAb0
+ rowAb1
+ rowBb0
+ rowBb1
) >> 2;
460 dst
[i
] = (blue
<< 5) | (green
<< 2) | red
;
464 debug_printf("bad format in do_row()");
470 format_to_type_comps(enum pipe_format pformat
,
471 enum dtype
*datatype
, uint
*comps
)
474 case PIPE_FORMAT_A8R8G8B8_UNORM
:
475 case PIPE_FORMAT_B8G8R8A8_UNORM
:
479 case PIPE_FORMAT_A1R5G5B5_UNORM
:
480 *datatype
= USHORT_1_5_5_5_REV
;
483 case PIPE_FORMAT_A4R4G4B4_UNORM
:
484 *datatype
= USHORT_4_4_4_4
;
487 case PIPE_FORMAT_R5G6B5_UNORM
:
488 *datatype
= USHORT_5_6_5
;
491 case PIPE_FORMAT_U_L8
:
492 case PIPE_FORMAT_U_A8
:
493 case PIPE_FORMAT_U_I8
:
497 case PIPE_FORMAT_U_A8_L8
:
508 reduce_1d(enum pipe_format pformat
,
509 int srcWidth
, const ubyte
*srcPtr
,
510 int dstWidth
, ubyte
*dstPtr
)
515 format_to_type_comps(pformat
, &datatype
, &comps
);
517 /* we just duplicate the input row, kind of hack, saves code */
518 do_row(datatype
, comps
,
519 srcWidth
, srcPtr
, srcPtr
,
525 * Strides are in bytes. If zero, it'll be computed as width * bpp.
528 reduce_2d(enum pipe_format pformat
,
529 int srcWidth
, int srcHeight
,
530 int srcRowStride
, const ubyte
*srcPtr
,
531 int dstWidth
, int dstHeight
,
532 int dstRowStride
, ubyte
*dstPtr
)
536 const int bpt
= pf_get_size(pformat
);
537 const ubyte
*srcA
, *srcB
;
541 format_to_type_comps(pformat
, &datatype
, &comps
);
544 srcRowStride
= bpt
* srcWidth
;
547 dstRowStride
= bpt
* dstWidth
;
549 /* Compute src and dst pointers */
552 srcB
= srcA
+ srcRowStride
;
557 for (row
= 0; row
< dstHeight
; row
++) {
558 do_row(datatype
, comps
,
559 srcWidth
, srcA
, srcB
,
561 srcA
+= 2 * srcRowStride
;
562 srcB
+= 2 * srcRowStride
;
569 make_1d_mipmap(struct gen_mipmap_state
*ctx
,
570 struct pipe_texture
*pt
,
571 uint face
, uint baseLevel
, uint lastLevel
)
573 struct pipe_context
*pipe
= ctx
->pipe
;
574 struct pipe_screen
*screen
= pipe
->screen
;
575 struct pipe_winsys
*winsys
= pipe
->winsys
;
576 const uint zslice
= 0;
579 for (dstLevel
= baseLevel
+ 1; dstLevel
<= lastLevel
; dstLevel
++) {
580 const uint srcLevel
= dstLevel
- 1;
581 struct pipe_surface
*srcSurf
, *dstSurf
;
582 void *srcMap
, *dstMap
;
584 srcSurf
= screen
->get_tex_surface(screen
, pt
, face
, srcLevel
, zslice
);
585 dstSurf
= screen
->get_tex_surface(screen
, pt
, face
, dstLevel
, zslice
);
587 srcMap
= ((ubyte
*) winsys
->buffer_map(winsys
, srcSurf
->buffer
,
588 PIPE_BUFFER_USAGE_CPU_READ
)
590 dstMap
= ((ubyte
*) winsys
->buffer_map(winsys
, dstSurf
->buffer
,
591 PIPE_BUFFER_USAGE_CPU_WRITE
)
594 reduce_1d(pt
->format
,
595 srcSurf
->width
, srcMap
,
596 dstSurf
->width
, dstMap
);
598 winsys
->buffer_unmap(winsys
, srcSurf
->buffer
);
599 winsys
->buffer_unmap(winsys
, dstSurf
->buffer
);
601 pipe_surface_reference(&srcSurf
, NULL
);
602 pipe_surface_reference(&dstSurf
, NULL
);
608 make_2d_mipmap(struct gen_mipmap_state
*ctx
,
609 struct pipe_texture
*pt
,
610 uint face
, uint baseLevel
, uint lastLevel
)
612 struct pipe_context
*pipe
= ctx
->pipe
;
613 struct pipe_screen
*screen
= pipe
->screen
;
614 struct pipe_winsys
*winsys
= pipe
->winsys
;
615 const uint zslice
= 0;
617 const int bpt
= pf_get_size(pt
->format
);
619 for (dstLevel
= baseLevel
+ 1; dstLevel
<= lastLevel
; dstLevel
++) {
620 const uint srcLevel
= dstLevel
- 1;
621 struct pipe_surface
*srcSurf
, *dstSurf
;
622 ubyte
*srcMap
, *dstMap
;
624 srcSurf
= screen
->get_tex_surface(screen
, pt
, face
, srcLevel
, zslice
);
625 dstSurf
= screen
->get_tex_surface(screen
, pt
, face
, dstLevel
, zslice
);
627 srcMap
= ((ubyte
*) winsys
->buffer_map(winsys
, srcSurf
->buffer
,
628 PIPE_BUFFER_USAGE_CPU_READ
)
630 dstMap
= ((ubyte
*) winsys
->buffer_map(winsys
, dstSurf
->buffer
,
631 PIPE_BUFFER_USAGE_CPU_WRITE
)
634 reduce_2d(pt
->format
,
635 srcSurf
->width
, srcSurf
->height
,
636 srcSurf
->pitch
* bpt
, srcMap
,
637 dstSurf
->width
, dstSurf
->height
,
638 dstSurf
->pitch
* bpt
, dstMap
);
640 winsys
->buffer_unmap(winsys
, srcSurf
->buffer
);
641 winsys
->buffer_unmap(winsys
, dstSurf
->buffer
);
643 pipe_surface_reference(&srcSurf
, NULL
);
644 pipe_surface_reference(&dstSurf
, NULL
);
650 make_3d_mipmap(struct gen_mipmap_state
*ctx
,
651 struct pipe_texture
*pt
,
652 uint face
, uint baseLevel
, uint lastLevel
)
658 fallback_gen_mipmap(struct gen_mipmap_state
*ctx
,
659 struct pipe_texture
*pt
,
660 uint face
, uint baseLevel
, uint lastLevel
)
662 switch (pt
->target
) {
663 case PIPE_TEXTURE_1D
:
664 make_1d_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
666 case PIPE_TEXTURE_2D
:
667 case PIPE_TEXTURE_CUBE
:
668 make_2d_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
670 case PIPE_TEXTURE_3D
:
671 make_3d_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
680 * Create a mipmap generation context.
681 * The idea is to create one of these and re-use it each time we need to
684 struct gen_mipmap_state
*
685 util_create_gen_mipmap(struct pipe_context
*pipe
,
686 struct cso_context
*cso
)
688 struct gen_mipmap_state
*ctx
;
691 ctx
= CALLOC_STRUCT(gen_mipmap_state
);
698 /* disabled blending/masking */
699 memset(&ctx
->blend
, 0, sizeof(ctx
->blend
));
700 ctx
->blend
.rgb_src_factor
= PIPE_BLENDFACTOR_ONE
;
701 ctx
->blend
.alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
702 ctx
->blend
.rgb_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
703 ctx
->blend
.alpha_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
704 ctx
->blend
.colormask
= PIPE_MASK_RGBA
;
706 /* no-op depth/stencil/alpha */
707 memset(&ctx
->depthstencil
, 0, sizeof(ctx
->depthstencil
));
710 memset(&ctx
->rasterizer
, 0, sizeof(ctx
->rasterizer
));
711 ctx
->rasterizer
.front_winding
= PIPE_WINDING_CW
;
712 ctx
->rasterizer
.cull_mode
= PIPE_WINDING_NONE
;
713 ctx
->rasterizer
.bypass_clipping
= 1; /* bypasses viewport too */
714 /*ctx->rasterizer.bypass_vs = 1;*/
717 memset(&ctx
->sampler
, 0, sizeof(ctx
->sampler
));
718 ctx
->sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
719 ctx
->sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
720 ctx
->sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
721 ctx
->sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NEAREST
;
722 ctx
->sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
723 ctx
->sampler
.normalized_coords
= 1;
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;
740 const uint semantic_names
[] = { TGSI_SEMANTIC_POSITION
,
741 TGSI_SEMANTIC_GENERIC
};
742 const uint semantic_indexes
[] = { 0, 0 };
743 ctx
->vs
= util_make_vertex_passthrough_shader(pipe
, 2, semantic_names
,
747 /* fragment shader */
748 ctx
->fs
= util_make_fragment_tex_shader(pipe
);
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 pipe
->winsys
->buffer_destroy(pipe
->winsys
, ctx
->vbuf
);
825 simple_viewport(struct pipe_context
*pipe
, uint width
, uint height
)
827 struct pipe_viewport_state vp
;
829 vp
.scale
[0] = 0.5 * width
;
830 vp
.scale
[1] = -0.5 * height
;
833 vp
.translate
[0] = 0.5 * width
;
834 vp
.translate
[1] = 0.5 * height
;
835 vp
.translate
[2] = 0.0;
836 vp
.translate
[3] = 0.0;
838 pipe
->set_viewport_state(pipe
, &vp
);
844 * Generate mipmap images. It's assumed all needed texture memory is
847 * \param pt the texture to generate mipmap levels for
848 * \param face which cube face to generate mipmaps for (0 for non-cube maps)
849 * \param baseLevel the first mipmap level to use as a src
850 * \param lastLevel the last mipmap level to generate
851 * \param filter the minification filter used to generate mipmap levels with
854 util_gen_mipmap_filter(struct gen_mipmap_state
*ctx
,
855 struct pipe_texture
*pt
,
856 uint face
, uint baseLevel
, uint lastLevel
, uint filter
)
858 struct pipe_context
*pipe
= ctx
->pipe
;
859 struct pipe_screen
*screen
= pipe
->screen
;
860 struct pipe_framebuffer_state fb
;
864 /* check if we can render in the texture's format */
865 if (!screen
->is_format_supported(screen
, pt
->format
, PIPE_SURFACE
)) {
866 fallback_gen_mipmap(ctx
, pt
, face
, baseLevel
, lastLevel
);
870 /* save state (restored below) */
871 cso_save_blend(ctx
->cso
);
872 cso_save_depth_stencil_alpha(ctx
->cso
);
873 cso_save_rasterizer(ctx
->cso
);
874 cso_save_samplers(ctx
->cso
);
875 cso_save_sampler_textures(ctx
->cso
);
876 cso_save_framebuffer(ctx
->cso
);
879 cso_set_blend(ctx
->cso
, &ctx
->blend
);
880 cso_set_depth_stencil_alpha(ctx
->cso
, &ctx
->depthstencil
);
881 cso_set_rasterizer(ctx
->cso
, &ctx
->rasterizer
);
883 pipe
->bind_vs_state(pipe
, ctx
->vs
);
884 pipe
->bind_fs_state(pipe
, ctx
->fs
);
886 pipe
->set_viewport_state(pipe
, &ctx
->viewport
);
889 /* init framebuffer state */
890 memset(&fb
, 0, sizeof(fb
));
894 * XXX for small mipmap levels, it may be faster to use the software
897 for (dstLevel
= baseLevel
+ 1; dstLevel
<= lastLevel
; dstLevel
++) {
898 const uint srcLevel
= dstLevel
- 1;
901 * Setup framebuffer / dest surface
903 fb
.cbufs
[0] = screen
->get_tex_surface(screen
, pt
, face
, dstLevel
, zslice
);
904 fb
.width
= pt
->width
[dstLevel
];
905 fb
.height
= pt
->height
[dstLevel
];
906 cso_set_framebuffer(ctx
->cso
, &fb
);
909 * Setup sampler state
910 * Note: we should only have to set the min/max LOD clamps to ensure
911 * we grab texels from the right mipmap level. But some hardware
912 * has trouble with min clamping so we also set the lod_bias to
913 * try to work around that.
915 ctx
->sampler
.min_lod
= ctx
->sampler
.max_lod
= (float) srcLevel
;
916 ctx
->sampler
.lod_bias
= (float) srcLevel
;
917 ctx
->sampler
.min_img_filter
= filter
;
918 cso_single_sampler(ctx
->cso
, 0, &ctx
->sampler
);
919 cso_single_sampler_done(ctx
->cso
);
921 simple_viewport(pipe
, pt
->width
[dstLevel
], pt
->height
[dstLevel
]);
924 pipe
->set_sampler_textures(pipe
, 1, &pt
);
926 /* quad coords in window coords (bypassing clipping, viewport mapping) */
928 (float) pt
->width
[dstLevel
],
929 (float) pt
->height
[dstLevel
]);
930 util_draw_vertex_buffer(ctx
->pipe
, ctx
->vbuf
,
931 PIPE_PRIM_TRIANGLE_FAN
,
933 2); /* attribs/vert */
935 pipe
->flush(pipe
, PIPE_FLUSH_WAIT
);
937 /* need to signal that the texture has changed _after_ rendering to it */
938 pipe
->texture_update(pipe
, pt
, face
, (1 << dstLevel
));
941 /* restore state we changed */
942 cso_restore_blend(ctx
->cso
);
943 cso_restore_depth_stencil_alpha(ctx
->cso
);
944 cso_restore_rasterizer(ctx
->cso
);
945 cso_restore_samplers(ctx
->cso
);
946 cso_restore_sampler_textures(ctx
->cso
);
947 cso_restore_framebuffer(ctx
->cso
);
952 * Generate mipmap images with a linear minification filter.
953 * See util_gen_mipmap_filter for more info.
955 * \param pt the texture to generate mipmap levels for
956 * \param face which cube face to generate mipmaps for (0 for non-cube maps)
957 * \param baseLevel the first mipmap level to use as a src
958 * \param lastLevel the last mipmap level to generate
961 util_gen_mipmap(struct gen_mipmap_state
*ctx
,
962 struct pipe_texture
*pt
,
963 uint face
, uint baseLevel
, uint lastLevel
)
965 util_gen_mipmap_filter( ctx
, pt
, face
, baseLevel
, lastLevel
, PIPE_TEX_FILTER_LINEAR
);