Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / gallium / auxiliary / util / u_gen_mipmap.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28 /**
29 * @file
30 * Mipmap generation utility
31 *
32 * @author Brian Paul
33 */
34
35
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_winsys.h"
41 #include "pipe/p_shader_tokens.h"
42
43 #include "util/u_memory.h"
44 #include "util/u_draw_quad.h"
45 #include "util/u_gen_mipmap.h"
46 #include "util/u_simple_shaders.h"
47
48 #include "tgsi/tgsi_build.h"
49 #include "tgsi/tgsi_dump.h"
50 #include "tgsi/tgsi_parse.h"
51
52 #include "cso_cache/cso_context.h"
53
54
55 struct gen_mipmap_state
56 {
57 struct pipe_context *pipe;
58 struct cso_context *cso;
59
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
66 struct pipe_shader_state vert_shader;
67 struct pipe_shader_state frag_shader;
68 void *vs;
69 void *fs;
70
71 struct pipe_buffer *vbuf; /**< quad vertices */
72 float vertices[4][2][4]; /**< vertex/texcoords for quad */
73 };
74
75
76
77 enum dtype
78 {
79 UBYTE,
80 UBYTE_3_3_2,
81 USHORT,
82 USHORT_4_4_4_4,
83 USHORT_5_6_5,
84 USHORT_1_5_5_5_REV,
85 UINT,
86 FLOAT,
87 HALF_FLOAT
88 };
89
90
91 typedef ushort half_float;
92
93
94 #if 0
95 extern half_float
96 float_to_half(float f);
97
98 extern float
99 half_to_float(half_float h);
100 #endif
101
102
103 /**
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)
110 */
111 static void
112 do_row(enum dtype datatype, uint comps, int srcWidth,
113 const void *srcRowA, const void *srcRowB,
114 int dstWidth, void *dstRow)
115 {
116 const uint k0 = (srcWidth == dstWidth) ? 0 : 1;
117 const uint colStride = (srcWidth == dstWidth) ? 1 : 2;
118
119 assert(comps >= 1);
120 assert(comps <= 4);
121
122 /* This assertion is no longer valid with non-power-of-2 textures
123 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
124 */
125
126 if (datatype == UBYTE && comps == 4) {
127 uint i, j, k;
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;
137 }
138 }
139 else if (datatype == UBYTE && comps == 3) {
140 uint i, j, k;
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;
149 }
150 }
151 else if (datatype == UBYTE && comps == 2) {
152 uint i, j, k;
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;
160 }
161 }
162 else if (datatype == UBYTE && comps == 1) {
163 uint i, j, k;
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;
170 }
171 }
172
173 else if (datatype == USHORT && comps == 4) {
174 uint i, j, k;
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;
184 }
185 }
186 else if (datatype == USHORT && comps == 3) {
187 uint i, j, k;
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;
196 }
197 }
198 else if (datatype == USHORT && comps == 2) {
199 uint i, j, k;
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;
207 }
208 }
209 else if (datatype == USHORT && comps == 1) {
210 uint i, j, k;
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;
217 }
218 }
219
220 else if (datatype == FLOAT && comps == 4) {
221 uint i, j, k;
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;
235 }
236 }
237 else if (datatype == FLOAT && comps == 3) {
238 uint i, j, k;
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;
250 }
251 }
252 else if (datatype == FLOAT && comps == 2) {
253 uint i, j, k;
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;
263 }
264 }
265 else if (datatype == FLOAT && comps == 1) {
266 uint i, j, k;
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;
273 }
274 }
275
276 #if 0
277 else if (datatype == HALF_FLOAT && comps == 4) {
278 uint i, j, k, comp;
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);
291 }
292 }
293 }
294 else if (datatype == HALF_FLOAT && comps == 3) {
295 uint i, j, k, comp;
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);
308 }
309 }
310 }
311 else if (datatype == HALF_FLOAT && comps == 2) {
312 uint i, j, k, comp;
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);
325 }
326 }
327 }
328 else if (datatype == HALF_FLOAT && comps == 1) {
329 uint i, j, k;
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);
341 }
342 }
343 #endif
344
345 else if (datatype == UINT && comps == 1) {
346 uint i, j, k;
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;
353 }
354 }
355
356 else if (datatype == USHORT_5_6_5 && comps == 3) {
357 uint i, j, k;
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;
379 }
380 }
381 else if (datatype == USHORT_4_4_4_4 && comps == 4) {
382 uint i, j, k;
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;
409 }
410 }
411 else if (datatype == USHORT_1_5_5_5_REV && comps == 4) {
412 uint i, j, k;
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;
439 }
440 }
441 else if (datatype == UBYTE_3_3_2 && comps == 3) {
442 uint i, j, k;
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;
464 }
465 }
466 else {
467 debug_printf("bad format in do_row()");
468 }
469 }
470
471
472 static void
473 format_to_type_comps(enum pipe_format pformat,
474 enum dtype *datatype, uint *comps)
475 {
476 switch (pformat) {
477 case PIPE_FORMAT_A8R8G8B8_UNORM:
478 case PIPE_FORMAT_X8R8G8B8_UNORM:
479 case PIPE_FORMAT_B8G8R8A8_UNORM:
480 case PIPE_FORMAT_B8G8R8X8_UNORM:
481 *datatype = UBYTE;
482 *comps = 4;
483 return;
484 case PIPE_FORMAT_A1R5G5B5_UNORM:
485 *datatype = USHORT_1_5_5_5_REV;
486 *comps = 4;
487 return;
488 case PIPE_FORMAT_A4R4G4B4_UNORM:
489 *datatype = USHORT_4_4_4_4;
490 *comps = 4;
491 return;
492 case PIPE_FORMAT_R5G6B5_UNORM:
493 *datatype = USHORT_5_6_5;
494 *comps = 3;
495 return;
496 case PIPE_FORMAT_L8_UNORM:
497 case PIPE_FORMAT_A8_UNORM:
498 case PIPE_FORMAT_I8_UNORM:
499 *datatype = UBYTE;
500 *comps = 1;
501 return;
502 case PIPE_FORMAT_A8L8_UNORM:
503 *datatype = UBYTE;
504 *comps = 2;
505 return;
506 default:
507 assert(0);
508 *datatype = UBYTE;
509 *comps = 0;
510 break;
511 }
512 }
513
514
515 static void
516 reduce_1d(enum pipe_format pformat,
517 int srcWidth, const ubyte *srcPtr,
518 int dstWidth, ubyte *dstPtr)
519 {
520 enum dtype datatype;
521 uint comps;
522
523 format_to_type_comps(pformat, &datatype, &comps);
524
525 /* we just duplicate the input row, kind of hack, saves code */
526 do_row(datatype, comps,
527 srcWidth, srcPtr, srcPtr,
528 dstWidth, dstPtr);
529 }
530
531
532 /**
533 * Strides are in bytes. If zero, it'll be computed as width * bpp.
534 */
535 static void
536 reduce_2d(enum pipe_format pformat,
537 int srcWidth, int srcHeight,
538 int srcRowStride, const ubyte *srcPtr,
539 int dstWidth, int dstHeight,
540 int dstRowStride, ubyte *dstPtr)
541 {
542 enum dtype datatype;
543 uint comps;
544 const int bpt = pf_get_size(pformat);
545 const ubyte *srcA, *srcB;
546 ubyte *dst;
547 int row;
548
549 format_to_type_comps(pformat, &datatype, &comps);
550
551 if (!srcRowStride)
552 srcRowStride = bpt * srcWidth;
553
554 if (!dstRowStride)
555 dstRowStride = bpt * dstWidth;
556
557 /* Compute src and dst pointers */
558 srcA = srcPtr;
559 if (srcHeight > 1)
560 srcB = srcA + srcRowStride;
561 else
562 srcB = srcA;
563 dst = dstPtr;
564
565 for (row = 0; row < dstHeight; row++) {
566 do_row(datatype, comps,
567 srcWidth, srcA, srcB,
568 dstWidth, dst);
569 srcA += 2 * srcRowStride;
570 srcB += 2 * srcRowStride;
571 dst += dstRowStride;
572 }
573 }
574
575
576 static void
577 make_1d_mipmap(struct gen_mipmap_state *ctx,
578 struct pipe_texture *pt,
579 uint face, uint baseLevel, uint lastLevel)
580 {
581 struct pipe_context *pipe = ctx->pipe;
582 struct pipe_screen *screen = pipe->screen;
583 const uint zslice = 0;
584 uint dstLevel;
585
586 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
587 const uint srcLevel = dstLevel - 1;
588 struct pipe_surface *srcSurf, *dstSurf;
589 void *srcMap, *dstMap;
590
591 srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice,
592 PIPE_BUFFER_USAGE_CPU_READ);
593
594 dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice,
595 PIPE_BUFFER_USAGE_CPU_WRITE);
596
597 srcMap = ((ubyte *) pipe_buffer_map(screen, srcSurf->buffer,
598 PIPE_BUFFER_USAGE_CPU_READ)
599 + srcSurf->offset);
600 dstMap = ((ubyte *) pipe_buffer_map(screen, dstSurf->buffer,
601 PIPE_BUFFER_USAGE_CPU_WRITE)
602 + dstSurf->offset);
603
604 reduce_1d(pt->format,
605 srcSurf->width, srcMap,
606 dstSurf->width, dstMap);
607
608 pipe_buffer_unmap(screen, srcSurf->buffer);
609 pipe_buffer_unmap(screen, dstSurf->buffer);
610
611 pipe_surface_reference(&srcSurf, NULL);
612 pipe_surface_reference(&dstSurf, NULL);
613 }
614 }
615
616
617 static void
618 make_2d_mipmap(struct gen_mipmap_state *ctx,
619 struct pipe_texture *pt,
620 uint face, uint baseLevel, uint lastLevel)
621 {
622 struct pipe_context *pipe = ctx->pipe;
623 struct pipe_screen *screen = pipe->screen;
624 const uint zslice = 0;
625 uint dstLevel;
626
627 assert(pt->block.width == 1);
628 assert(pt->block.height == 1);
629
630 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
631 const uint srcLevel = dstLevel - 1;
632 struct pipe_surface *srcSurf, *dstSurf;
633 ubyte *srcMap, *dstMap;
634
635 srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice,
636 PIPE_BUFFER_USAGE_CPU_READ);
637 dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice,
638 PIPE_BUFFER_USAGE_CPU_WRITE);
639
640 srcMap = ((ubyte *) pipe_buffer_map(screen, srcSurf->buffer,
641 PIPE_BUFFER_USAGE_CPU_READ)
642 + srcSurf->offset);
643 dstMap = ((ubyte *) pipe_buffer_map(screen, dstSurf->buffer,
644 PIPE_BUFFER_USAGE_CPU_WRITE)
645 + dstSurf->offset);
646
647 reduce_2d(pt->format,
648 srcSurf->width, srcSurf->height,
649 srcSurf->stride, srcMap,
650 dstSurf->width, dstSurf->height,
651 dstSurf->stride, dstMap);
652
653 pipe_buffer_unmap(screen, srcSurf->buffer);
654 pipe_buffer_unmap(screen, dstSurf->buffer);
655
656 pipe_surface_reference(&srcSurf, NULL);
657 pipe_surface_reference(&dstSurf, NULL);
658 }
659 }
660
661
662 static void
663 make_3d_mipmap(struct gen_mipmap_state *ctx,
664 struct pipe_texture *pt,
665 uint face, uint baseLevel, uint lastLevel)
666 {
667 }
668
669
670 static void
671 fallback_gen_mipmap(struct gen_mipmap_state *ctx,
672 struct pipe_texture *pt,
673 uint face, uint baseLevel, uint lastLevel)
674 {
675 switch (pt->target) {
676 case PIPE_TEXTURE_1D:
677 make_1d_mipmap(ctx, pt, face, baseLevel, lastLevel);
678 break;
679 case PIPE_TEXTURE_2D:
680 case PIPE_TEXTURE_CUBE:
681 make_2d_mipmap(ctx, pt, face, baseLevel, lastLevel);
682 break;
683 case PIPE_TEXTURE_3D:
684 make_3d_mipmap(ctx, pt, face, baseLevel, lastLevel);
685 break;
686 default:
687 assert(0);
688 }
689 }
690
691
692 /**
693 * Create a mipmap generation context.
694 * The idea is to create one of these and re-use it each time we need to
695 * generate a mipmap.
696 */
697 struct gen_mipmap_state *
698 util_create_gen_mipmap(struct pipe_context *pipe,
699 struct cso_context *cso)
700 {
701 struct gen_mipmap_state *ctx;
702 uint i;
703
704 ctx = CALLOC_STRUCT(gen_mipmap_state);
705 if (!ctx)
706 return NULL;
707
708 ctx->pipe = pipe;
709 ctx->cso = cso;
710
711 /* disabled blending/masking */
712 memset(&ctx->blend, 0, sizeof(ctx->blend));
713 ctx->blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
714 ctx->blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
715 ctx->blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
716 ctx->blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
717 ctx->blend.colormask = PIPE_MASK_RGBA;
718
719 /* no-op depth/stencil/alpha */
720 memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil));
721
722 /* rasterizer */
723 memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer));
724 ctx->rasterizer.front_winding = PIPE_WINDING_CW;
725 ctx->rasterizer.cull_mode = PIPE_WINDING_NONE;
726 ctx->rasterizer.bypass_clipping = 1;
727 /*ctx->rasterizer.bypass_vs = 1;*/
728 ctx->rasterizer.gl_rasterization_rules = 1;
729
730 /* sampler state */
731 memset(&ctx->sampler, 0, sizeof(ctx->sampler));
732 ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
733 ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
734 ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
735 ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
736 ctx->sampler.normalized_coords = 1;
737
738 /* viewport state (identity, verts are in wincoords) */
739 ctx->viewport.scale[0] = 1.0;
740 ctx->viewport.scale[1] = 1.0;
741 ctx->viewport.scale[2] = 1.0;
742 ctx->viewport.scale[3] = 1.0;
743 ctx->viewport.translate[0] = 0.0;
744 ctx->viewport.translate[1] = 0.0;
745 ctx->viewport.translate[2] = 0.0;
746 ctx->viewport.translate[3] = 0.0;
747
748 /* vertex shader */
749 {
750 const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
751 TGSI_SEMANTIC_GENERIC };
752 const uint semantic_indexes[] = { 0, 0 };
753 ctx->vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names,
754 semantic_indexes,
755 &ctx->vert_shader);
756 }
757
758 /* fragment shader */
759 ctx->fs = util_make_fragment_tex_shader(pipe, &ctx->frag_shader);
760
761 ctx->vbuf = pipe_buffer_create(pipe->screen,
762 32,
763 PIPE_BUFFER_USAGE_VERTEX,
764 sizeof(ctx->vertices));
765 if (!ctx->vbuf) {
766 FREE(ctx);
767 return NULL;
768 }
769
770 /* vertex data that doesn't change */
771 for (i = 0; i < 4; i++) {
772 ctx->vertices[i][0][2] = 0.0f; /* z */
773 ctx->vertices[i][0][3] = 1.0f; /* w */
774 ctx->vertices[i][1][2] = 0.0f; /* r */
775 ctx->vertices[i][1][3] = 1.0f; /* q */
776 }
777
778 return ctx;
779 }
780
781
782 static void
783 set_vertex_data(struct gen_mipmap_state *ctx, float width, float height)
784 {
785 void *buf;
786
787 ctx->vertices[0][0][0] = 0.0f; /*x*/
788 ctx->vertices[0][0][1] = 0.0f; /*y*/
789 ctx->vertices[0][1][0] = 0.0f; /*s*/
790 ctx->vertices[0][1][1] = 0.0f; /*t*/
791
792 ctx->vertices[1][0][0] = width;
793 ctx->vertices[1][0][1] = 0.0f;
794 ctx->vertices[1][1][0] = 1.0f;
795 ctx->vertices[1][1][1] = 0.0f;
796
797 ctx->vertices[2][0][0] = width;
798 ctx->vertices[2][0][1] = height;
799 ctx->vertices[2][1][0] = 1.0f;
800 ctx->vertices[2][1][1] = 1.0f;
801
802 ctx->vertices[3][0][0] = 0.0f;
803 ctx->vertices[3][0][1] = height;
804 ctx->vertices[3][1][0] = 0.0f;
805 ctx->vertices[3][1][1] = 1.0f;
806
807 buf = pipe_buffer_map(ctx->pipe->screen, ctx->vbuf,
808 PIPE_BUFFER_USAGE_CPU_WRITE);
809
810 memcpy(buf, ctx->vertices, sizeof(ctx->vertices));
811
812 pipe_buffer_unmap(ctx->pipe->screen, ctx->vbuf);
813 }
814
815
816
817 /**
818 * Destroy a mipmap generation context
819 */
820 void
821 util_destroy_gen_mipmap(struct gen_mipmap_state *ctx)
822 {
823 struct pipe_context *pipe = ctx->pipe;
824
825 pipe->delete_vs_state(pipe, ctx->vs);
826 pipe->delete_fs_state(pipe, ctx->fs);
827
828 FREE((void*) ctx->vert_shader.tokens);
829 FREE((void*) ctx->frag_shader.tokens);
830
831 pipe_buffer_reference(pipe->screen, &ctx->vbuf, NULL);
832
833 FREE(ctx);
834 }
835
836
837 /**
838 * Generate mipmap images. It's assumed all needed texture memory is
839 * already allocated.
840 *
841 * \param pt the texture to generate mipmap levels for
842 * \param face which cube face to generate mipmaps for (0 for non-cube maps)
843 * \param baseLevel the first mipmap level to use as a src
844 * \param lastLevel the last mipmap level to generate
845 * \param filter the minification filter used to generate mipmap levels with
846 * \param filter one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST
847 */
848 void
849 util_gen_mipmap(struct gen_mipmap_state *ctx,
850 struct pipe_texture *pt,
851 uint face, uint baseLevel, uint lastLevel, uint filter)
852 {
853 struct pipe_context *pipe = ctx->pipe;
854 struct pipe_screen *screen = pipe->screen;
855 struct pipe_framebuffer_state fb;
856 uint dstLevel;
857 uint zslice = 0;
858
859 /* check if we can render in the texture's format */
860 if (!screen->is_format_supported(screen, pt->format, PIPE_TEXTURE_2D,
861 PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
862 fallback_gen_mipmap(ctx, pt, face, baseLevel, lastLevel);
863 return;
864 }
865
866 /* save state (restored below) */
867 cso_save_blend(ctx->cso);
868 cso_save_depth_stencil_alpha(ctx->cso);
869 cso_save_rasterizer(ctx->cso);
870 cso_save_samplers(ctx->cso);
871 cso_save_sampler_textures(ctx->cso);
872 cso_save_framebuffer(ctx->cso);
873 cso_save_fragment_shader(ctx->cso);
874 cso_save_vertex_shader(ctx->cso);
875 cso_save_viewport(ctx->cso);
876
877 /* bind our state */
878 cso_set_blend(ctx->cso, &ctx->blend);
879 cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
880 cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
881 cso_set_viewport(ctx->cso, &ctx->viewport);
882
883 cso_set_fragment_shader_handle(ctx->cso, ctx->fs);
884 cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
885
886 /* init framebuffer state */
887 memset(&fb, 0, sizeof(fb));
888 fb.num_cbufs = 1;
889
890 /* set min/mag to same filter for faster sw speed */
891 ctx->sampler.mag_img_filter = filter;
892 ctx->sampler.min_img_filter = filter;
893
894 /*
895 * XXX for small mipmap levels, it may be faster to use the software
896 * fallback path...
897 */
898 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
899 const uint srcLevel = dstLevel - 1;
900
901 struct pipe_surface *surf =
902 screen->get_tex_surface(screen, pt, face, dstLevel, zslice,
903 PIPE_BUFFER_USAGE_GPU_WRITE);
904
905 /*
906 * Setup framebuffer / dest surface
907 */
908 fb.cbufs[0] = surf;
909 fb.width = pt->width[dstLevel];
910 fb.height = pt->height[dstLevel];
911 cso_set_framebuffer(ctx->cso, &fb);
912
913 /*
914 * Setup sampler state
915 * Note: we should only have to set the min/max LOD clamps to ensure
916 * we grab texels from the right mipmap level. But some hardware
917 * has trouble with min clamping so we also set the lod_bias to
918 * try to work around that.
919 */
920 ctx->sampler.min_lod = ctx->sampler.max_lod = (float) srcLevel;
921 ctx->sampler.lod_bias = (float) srcLevel;
922 cso_single_sampler(ctx->cso, 0, &ctx->sampler);
923 cso_single_sampler_done(ctx->cso);
924
925 cso_set_sampler_textures(ctx->cso, 1, &pt);
926
927 /* quad coords in window coords (bypassing clipping, viewport mapping) */
928 set_vertex_data(ctx,
929 (float) pt->width[dstLevel],
930 (float) pt->height[dstLevel]);
931 util_draw_vertex_buffer(ctx->pipe, ctx->vbuf,
932 PIPE_PRIM_TRIANGLE_FAN,
933 4, /* verts */
934 2); /* attribs/vert */
935
936 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
937
938 /* need to signal that the texture has changed _after_ rendering to it */
939 pipe_surface_reference( &surf, NULL );
940 }
941
942 /* restore state we changed */
943 cso_restore_blend(ctx->cso);
944 cso_restore_depth_stencil_alpha(ctx->cso);
945 cso_restore_rasterizer(ctx->cso);
946 cso_restore_samplers(ctx->cso);
947 cso_restore_sampler_textures(ctx->cso);
948 cso_restore_framebuffer(ctx->cso);
949 cso_restore_fragment_shader(ctx->cso);
950 cso_restore_vertex_shader(ctx->cso);
951 cso_restore_viewport(ctx->cso);
952 }