Tizen 2.0 Release
[profile/ivi/osmesa.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  * Copyright 2008  VMware, Inc.  All rights reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28
29 /**
30  * @file
31  * Mipmap generation utility
32  *  
33  * @author Brian Paul
34  */
35
36
37 #include "pipe/p_context.h"
38 #include "util/u_debug.h"
39 #include "pipe/p_defines.h"
40 #include "util/u_inlines.h"
41 #include "pipe/p_shader_tokens.h"
42 #include "pipe/p_state.h"
43
44 #include "util/u_format.h"
45 #include "util/u_memory.h"
46 #include "util/u_draw_quad.h"
47 #include "util/u_gen_mipmap.h"
48 #include "util/u_simple_shaders.h"
49 #include "util/u_math.h"
50 #include "util/u_texture.h"
51 #include "util/u_half.h"
52 #include "util/u_surface.h"
53
54 #include "cso_cache/cso_context.h"
55
56
57 struct gen_mipmap_state
58 {
59    struct pipe_context *pipe;
60    struct cso_context *cso;
61
62    struct pipe_blend_state blend;
63    struct pipe_depth_stencil_alpha_state depthstencil;
64    struct pipe_rasterizer_state rasterizer;
65    struct pipe_sampler_state sampler;
66    struct pipe_clip_state clip;
67    struct pipe_vertex_element velem[2];
68
69    void *vs;
70    void *fs[TGSI_TEXTURE_COUNT]; /**< Not all are used, but simplifies code */
71
72    struct pipe_resource *vbuf;  /**< quad vertices */
73    unsigned vbuf_slot;
74
75    float vertices[4][2][4];   /**< vertex/texcoords for quad */
76 };
77
78
79
80 enum dtype
81 {
82    DTYPE_UBYTE,
83    DTYPE_UBYTE_3_3_2,
84    DTYPE_USHORT,
85    DTYPE_USHORT_4_4_4_4,
86    DTYPE_USHORT_5_6_5,
87    DTYPE_USHORT_1_5_5_5_REV,
88    DTYPE_UINT,
89    DTYPE_FLOAT,
90    DTYPE_HALF_FLOAT
91 };
92
93
94 typedef uint16_t half_float;
95
96
97 /**
98  * \name Support macros for do_row and do_row_3d
99  *
100  * The macro madness is here for two reasons.  First, it compacts the code
101  * slightly.  Second, it makes it much easier to adjust the specifics of the
102  * filter to tune the rounding characteristics.
103  */
104 /*@{*/
105 #define DECLARE_ROW_POINTERS(t, e) \
106       const t(*rowA)[e] = (const t(*)[e]) srcRowA; \
107       const t(*rowB)[e] = (const t(*)[e]) srcRowB; \
108       const t(*rowC)[e] = (const t(*)[e]) srcRowC; \
109       const t(*rowD)[e] = (const t(*)[e]) srcRowD; \
110       t(*dst)[e] = (t(*)[e]) dstRow
111
112 #define DECLARE_ROW_POINTERS0(t) \
113       const t *rowA = (const t *) srcRowA; \
114       const t *rowB = (const t *) srcRowB; \
115       const t *rowC = (const t *) srcRowC; \
116       const t *rowD = (const t *) srcRowD; \
117       t *dst = (t *) dstRow
118
119 #define FILTER_SUM_3D(Aj, Ak, Bj, Bk, Cj, Ck, Dj, Dk) \
120    ((unsigned) Aj + (unsigned) Ak \
121     + (unsigned) Bj + (unsigned) Bk \
122     + (unsigned) Cj + (unsigned) Ck \
123     + (unsigned) Dj + (unsigned) Dk \
124     + 4) >> 3
125
126 #define FILTER_3D(e) \
127    do { \
128       dst[i][e] = FILTER_SUM_3D(rowA[j][e], rowA[k][e], \
129                                 rowB[j][e], rowB[k][e], \
130                                 rowC[j][e], rowC[k][e], \
131                                 rowD[j][e], rowD[k][e]); \
132    } while(0)
133
134 #define FILTER_F_3D(e) \
135    do { \
136       dst[i][e] = (rowA[j][e] + rowA[k][e] \
137                    + rowB[j][e] + rowB[k][e] \
138                    + rowC[j][e] + rowC[k][e] \
139                    + rowD[j][e] + rowD[k][e]) * 0.125F; \
140    } while(0)
141
142 #define FILTER_HF_3D(e) \
143    do { \
144       const float aj = util_half_to_float(rowA[j][e]); \
145       const float ak = util_half_to_float(rowA[k][e]); \
146       const float bj = util_half_to_float(rowB[j][e]); \
147       const float bk = util_half_to_float(rowB[k][e]); \
148       const float cj = util_half_to_float(rowC[j][e]); \
149       const float ck = util_half_to_float(rowC[k][e]); \
150       const float dj = util_half_to_float(rowD[j][e]); \
151       const float dk = util_half_to_float(rowD[k][e]); \
152       dst[i][e] = util_float_to_half((aj + ak + bj + bk + cj + ck + dj + dk) \
153                                       * 0.125F); \
154    } while(0)
155 /*@}*/
156
157
158 /**
159  * Average together two rows of a source image to produce a single new
160  * row in the dest image.  It's legal for the two source rows to point
161  * to the same data.  The source width must be equal to either the
162  * dest width or two times the dest width.
163  * \param datatype  GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
164  * \param comps  number of components per pixel (1..4)
165  */
166 static void
167 do_row(enum dtype datatype, uint comps, int srcWidth,
168        const void *srcRowA, const void *srcRowB,
169        int dstWidth, void *dstRow)
170 {
171    const uint k0 = (srcWidth == dstWidth) ? 0 : 1;
172    const uint colStride = (srcWidth == dstWidth) ? 1 : 2;
173
174    assert(comps >= 1);
175    assert(comps <= 4);
176
177    /* This assertion is no longer valid with non-power-of-2 textures
178    assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
179    */
180
181    if (datatype == DTYPE_UBYTE && comps == 4) {
182       uint i, j, k;
183       const ubyte(*rowA)[4] = (const ubyte(*)[4]) srcRowA;
184       const ubyte(*rowB)[4] = (const ubyte(*)[4]) srcRowB;
185       ubyte(*dst)[4] = (ubyte(*)[4]) dstRow;
186       for (i = j = 0, k = k0; i < (uint) dstWidth;
187            i++, j += colStride, k += colStride) {
188          dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
189          dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
190          dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
191          dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
192       }
193    }
194    else if (datatype == DTYPE_UBYTE && comps == 3) {
195       uint i, j, k;
196       const ubyte(*rowA)[3] = (const ubyte(*)[3]) srcRowA;
197       const ubyte(*rowB)[3] = (const ubyte(*)[3]) srcRowB;
198       ubyte(*dst)[3] = (ubyte(*)[3]) dstRow;
199       for (i = j = 0, k = k0; i < (uint) dstWidth;
200            i++, j += colStride, k += colStride) {
201          dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
202          dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
203          dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
204       }
205    }
206    else if (datatype == DTYPE_UBYTE && comps == 2) {
207       uint i, j, k;
208       const ubyte(*rowA)[2] = (const ubyte(*)[2]) srcRowA;
209       const ubyte(*rowB)[2] = (const ubyte(*)[2]) srcRowB;
210       ubyte(*dst)[2] = (ubyte(*)[2]) dstRow;
211       for (i = j = 0, k = k0; i < (uint) dstWidth;
212            i++, j += colStride, k += colStride) {
213          dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) >> 2;
214          dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) >> 2;
215       }
216    }
217    else if (datatype == DTYPE_UBYTE && comps == 1) {
218       uint i, j, k;
219       const ubyte *rowA = (const ubyte *) srcRowA;
220       const ubyte *rowB = (const ubyte *) srcRowB;
221       ubyte *dst = (ubyte *) dstRow;
222       for (i = j = 0, k = k0; i < (uint) dstWidth;
223            i++, j += colStride, k += colStride) {
224          dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
225       }
226    }
227
228    else if (datatype == DTYPE_USHORT && comps == 4) {
229       uint i, j, k;
230       const ushort(*rowA)[4] = (const ushort(*)[4]) srcRowA;
231       const ushort(*rowB)[4] = (const ushort(*)[4]) srcRowB;
232       ushort(*dst)[4] = (ushort(*)[4]) dstRow;
233       for (i = j = 0, k = k0; i < (uint) dstWidth;
234            i++, j += colStride, k += colStride) {
235          dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
236          dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
237          dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
238          dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
239       }
240    }
241    else if (datatype == DTYPE_USHORT && comps == 3) {
242       uint i, j, k;
243       const ushort(*rowA)[3] = (const ushort(*)[3]) srcRowA;
244       const ushort(*rowB)[3] = (const ushort(*)[3]) srcRowB;
245       ushort(*dst)[3] = (ushort(*)[3]) dstRow;
246       for (i = j = 0, k = k0; i < (uint) dstWidth;
247            i++, j += colStride, k += colStride) {
248          dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
249          dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
250          dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
251       }
252    }
253    else if (datatype == DTYPE_USHORT && comps == 2) {
254       uint i, j, k;
255       const ushort(*rowA)[2] = (const ushort(*)[2]) srcRowA;
256       const ushort(*rowB)[2] = (const ushort(*)[2]) srcRowB;
257       ushort(*dst)[2] = (ushort(*)[2]) dstRow;
258       for (i = j = 0, k = k0; i < (uint) dstWidth;
259            i++, j += colStride, k += colStride) {
260          dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
261          dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
262       }
263    }
264    else if (datatype == DTYPE_USHORT && comps == 1) {
265       uint i, j, k;
266       const ushort *rowA = (const ushort *) srcRowA;
267       const ushort *rowB = (const ushort *) srcRowB;
268       ushort *dst = (ushort *) dstRow;
269       for (i = j = 0, k = k0; i < (uint) dstWidth;
270            i++, j += colStride, k += colStride) {
271          dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
272       }
273    }
274
275    else if (datatype == DTYPE_FLOAT && comps == 4) {
276       uint i, j, k;
277       const float(*rowA)[4] = (const float(*)[4]) srcRowA;
278       const float(*rowB)[4] = (const float(*)[4]) srcRowB;
279       float(*dst)[4] = (float(*)[4]) dstRow;
280       for (i = j = 0, k = k0; i < (uint) dstWidth;
281            i++, j += colStride, k += colStride) {
282          dst[i][0] = (rowA[j][0] + rowA[k][0] +
283                       rowB[j][0] + rowB[k][0]) * 0.25F;
284          dst[i][1] = (rowA[j][1] + rowA[k][1] +
285                       rowB[j][1] + rowB[k][1]) * 0.25F;
286          dst[i][2] = (rowA[j][2] + rowA[k][2] +
287                       rowB[j][2] + rowB[k][2]) * 0.25F;
288          dst[i][3] = (rowA[j][3] + rowA[k][3] +
289                       rowB[j][3] + rowB[k][3]) * 0.25F;
290       }
291    }
292    else if (datatype == DTYPE_FLOAT && comps == 3) {
293       uint i, j, k;
294       const float(*rowA)[3] = (const float(*)[3]) srcRowA;
295       const float(*rowB)[3] = (const float(*)[3]) srcRowB;
296       float(*dst)[3] = (float(*)[3]) dstRow;
297       for (i = j = 0, k = k0; i < (uint) dstWidth;
298            i++, j += colStride, k += colStride) {
299          dst[i][0] = (rowA[j][0] + rowA[k][0] +
300                       rowB[j][0] + rowB[k][0]) * 0.25F;
301          dst[i][1] = (rowA[j][1] + rowA[k][1] +
302                       rowB[j][1] + rowB[k][1]) * 0.25F;
303          dst[i][2] = (rowA[j][2] + rowA[k][2] +
304                       rowB[j][2] + rowB[k][2]) * 0.25F;
305       }
306    }
307    else if (datatype == DTYPE_FLOAT && comps == 2) {
308       uint i, j, k;
309       const float(*rowA)[2] = (const float(*)[2]) srcRowA;
310       const float(*rowB)[2] = (const float(*)[2]) srcRowB;
311       float(*dst)[2] = (float(*)[2]) dstRow;
312       for (i = j = 0, k = k0; i < (uint) dstWidth;
313            i++, j += colStride, k += colStride) {
314          dst[i][0] = (rowA[j][0] + rowA[k][0] +
315                       rowB[j][0] + rowB[k][0]) * 0.25F;
316          dst[i][1] = (rowA[j][1] + rowA[k][1] +
317                       rowB[j][1] + rowB[k][1]) * 0.25F;
318       }
319    }
320    else if (datatype == DTYPE_FLOAT && comps == 1) {
321       uint i, j, k;
322       const float *rowA = (const float *) srcRowA;
323       const float *rowB = (const float *) srcRowB;
324       float *dst = (float *) dstRow;
325       for (i = j = 0, k = k0; i < (uint) dstWidth;
326            i++, j += colStride, k += colStride) {
327          dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
328       }
329    }
330
331    else if (datatype == DTYPE_HALF_FLOAT && comps == 4) {
332       uint i, j, k, comp;
333       const half_float(*rowA)[4] = (const half_float(*)[4]) srcRowA;
334       const half_float(*rowB)[4] = (const half_float(*)[4]) srcRowB;
335       half_float(*dst)[4] = (half_float(*)[4]) dstRow;
336       for (i = j = 0, k = k0; i < (uint) dstWidth;
337            i++, j += colStride, k += colStride) {
338          for (comp = 0; comp < 4; comp++) {
339             float aj, ak, bj, bk;
340             aj = util_half_to_float(rowA[j][comp]);
341             ak = util_half_to_float(rowA[k][comp]);
342             bj = util_half_to_float(rowB[j][comp]);
343             bk = util_half_to_float(rowB[k][comp]);
344             dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
345          }
346       }
347    }
348    else if (datatype == DTYPE_HALF_FLOAT && comps == 3) {
349       uint i, j, k, comp;
350       const half_float(*rowA)[3] = (const half_float(*)[3]) srcRowA;
351       const half_float(*rowB)[3] = (const half_float(*)[3]) srcRowB;
352       half_float(*dst)[3] = (half_float(*)[3]) dstRow;
353       for (i = j = 0, k = k0; i < (uint) dstWidth;
354            i++, j += colStride, k += colStride) {
355          for (comp = 0; comp < 3; comp++) {
356             float aj, ak, bj, bk;
357             aj = util_half_to_float(rowA[j][comp]);
358             ak = util_half_to_float(rowA[k][comp]);
359             bj = util_half_to_float(rowB[j][comp]);
360             bk = util_half_to_float(rowB[k][comp]);
361             dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
362          }
363       }
364    }
365    else if (datatype == DTYPE_HALF_FLOAT && comps == 2) {
366       uint i, j, k, comp;
367       const half_float(*rowA)[2] = (const half_float(*)[2]) srcRowA;
368       const half_float(*rowB)[2] = (const half_float(*)[2]) srcRowB;
369       half_float(*dst)[2] = (half_float(*)[2]) dstRow;
370       for (i = j = 0, k = k0; i < (uint) dstWidth;
371            i++, j += colStride, k += colStride) {
372          for (comp = 0; comp < 2; comp++) {
373             float aj, ak, bj, bk;
374             aj = util_half_to_float(rowA[j][comp]);
375             ak = util_half_to_float(rowA[k][comp]);
376             bj = util_half_to_float(rowB[j][comp]);
377             bk = util_half_to_float(rowB[k][comp]);
378             dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
379          }
380       }
381    }
382    else if (datatype == DTYPE_HALF_FLOAT && comps == 1) {
383       uint i, j, k;
384       const half_float *rowA = (const half_float *) srcRowA;
385       const half_float *rowB = (const half_float *) srcRowB;
386       half_float *dst = (half_float *) dstRow;
387       for (i = j = 0, k = k0; i < (uint) dstWidth;
388            i++, j += colStride, k += colStride) {
389          float aj, ak, bj, bk;
390          aj = util_half_to_float(rowA[j]);
391          ak = util_half_to_float(rowA[k]);
392          bj = util_half_to_float(rowB[j]);
393          bk = util_half_to_float(rowB[k]);
394          dst[i] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
395       }
396    }
397
398    else if (datatype == DTYPE_UINT && comps == 1) {
399       uint i, j, k;
400       const uint *rowA = (const uint *) srcRowA;
401       const uint *rowB = (const uint *) srcRowB;
402       uint *dst = (uint *) dstRow;
403       for (i = j = 0, k = k0; i < (uint) dstWidth;
404            i++, j += colStride, k += colStride) {
405          dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
406       }
407    }
408
409    else if (datatype == DTYPE_USHORT_5_6_5 && comps == 3) {
410       uint i, j, k;
411       const ushort *rowA = (const ushort *) srcRowA;
412       const ushort *rowB = (const ushort *) srcRowB;
413       ushort *dst = (ushort *) dstRow;
414       for (i = j = 0, k = k0; i < (uint) dstWidth;
415            i++, j += colStride, k += colStride) {
416          const int rowAr0 = rowA[j] & 0x1f;
417          const int rowAr1 = rowA[k] & 0x1f;
418          const int rowBr0 = rowB[j] & 0x1f;
419          const int rowBr1 = rowB[k] & 0x1f;
420          const int rowAg0 = (rowA[j] >> 5) & 0x3f;
421          const int rowAg1 = (rowA[k] >> 5) & 0x3f;
422          const int rowBg0 = (rowB[j] >> 5) & 0x3f;
423          const int rowBg1 = (rowB[k] >> 5) & 0x3f;
424          const int rowAb0 = (rowA[j] >> 11) & 0x1f;
425          const int rowAb1 = (rowA[k] >> 11) & 0x1f;
426          const int rowBb0 = (rowB[j] >> 11) & 0x1f;
427          const int rowBb1 = (rowB[k] >> 11) & 0x1f;
428          const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
429          const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
430          const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
431          dst[i] = (blue << 11) | (green << 5) | red;
432       }
433    }
434    else if (datatype == DTYPE_USHORT_4_4_4_4 && comps == 4) {
435       uint i, j, k;
436       const ushort *rowA = (const ushort *) srcRowA;
437       const ushort *rowB = (const ushort *) srcRowB;
438       ushort *dst = (ushort *) dstRow;
439       for (i = j = 0, k = k0; i < (uint) dstWidth;
440            i++, j += colStride, k += colStride) {
441          const int rowAr0 = rowA[j] & 0xf;
442          const int rowAr1 = rowA[k] & 0xf;
443          const int rowBr0 = rowB[j] & 0xf;
444          const int rowBr1 = rowB[k] & 0xf;
445          const int rowAg0 = (rowA[j] >> 4) & 0xf;
446          const int rowAg1 = (rowA[k] >> 4) & 0xf;
447          const int rowBg0 = (rowB[j] >> 4) & 0xf;
448          const int rowBg1 = (rowB[k] >> 4) & 0xf;
449          const int rowAb0 = (rowA[j] >> 8) & 0xf;
450          const int rowAb1 = (rowA[k] >> 8) & 0xf;
451          const int rowBb0 = (rowB[j] >> 8) & 0xf;
452          const int rowBb1 = (rowB[k] >> 8) & 0xf;
453          const int rowAa0 = (rowA[j] >> 12) & 0xf;
454          const int rowAa1 = (rowA[k] >> 12) & 0xf;
455          const int rowBa0 = (rowB[j] >> 12) & 0xf;
456          const int rowBa1 = (rowB[k] >> 12) & 0xf;
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          const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
461          dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
462       }
463    }
464    else if (datatype == DTYPE_USHORT_1_5_5_5_REV && comps == 4) {
465       uint i, j, k;
466       const ushort *rowA = (const ushort *) srcRowA;
467       const ushort *rowB = (const ushort *) srcRowB;
468       ushort *dst = (ushort *) dstRow;
469       for (i = j = 0, k = k0; i < (uint) dstWidth;
470            i++, j += colStride, k += colStride) {
471          const int rowAr0 = rowA[j] & 0x1f;
472          const int rowAr1 = rowA[k] & 0x1f;
473          const int rowBr0 = rowB[j] & 0x1f;
474          const int rowBr1 = rowB[k] & 0x1f;
475          const int rowAg0 = (rowA[j] >> 5) & 0x1f;
476          const int rowAg1 = (rowA[k] >> 5) & 0x1f;
477          const int rowBg0 = (rowB[j] >> 5) & 0x1f;
478          const int rowBg1 = (rowB[k] >> 5) & 0x1f;
479          const int rowAb0 = (rowA[j] >> 10) & 0x1f;
480          const int rowAb1 = (rowA[k] >> 10) & 0x1f;
481          const int rowBb0 = (rowB[j] >> 10) & 0x1f;
482          const int rowBb1 = (rowB[k] >> 10) & 0x1f;
483          const int rowAa0 = (rowA[j] >> 15) & 0x1;
484          const int rowAa1 = (rowA[k] >> 15) & 0x1;
485          const int rowBa0 = (rowB[j] >> 15) & 0x1;
486          const int rowBa1 = (rowB[k] >> 15) & 0x1;
487          const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
488          const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
489          const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
490          const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
491          dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
492       }
493    }
494    else if (datatype == DTYPE_UBYTE_3_3_2 && comps == 3) {
495       uint i, j, k;
496       const ubyte *rowA = (const ubyte *) srcRowA;
497       const ubyte *rowB = (const ubyte *) srcRowB;
498       ubyte *dst = (ubyte *) dstRow;
499       for (i = j = 0, k = k0; i < (uint) dstWidth;
500            i++, j += colStride, k += colStride) {
501          const int rowAr0 = rowA[j] & 0x3;
502          const int rowAr1 = rowA[k] & 0x3;
503          const int rowBr0 = rowB[j] & 0x3;
504          const int rowBr1 = rowB[k] & 0x3;
505          const int rowAg0 = (rowA[j] >> 2) & 0x7;
506          const int rowAg1 = (rowA[k] >> 2) & 0x7;
507          const int rowBg0 = (rowB[j] >> 2) & 0x7;
508          const int rowBg1 = (rowB[k] >> 2) & 0x7;
509          const int rowAb0 = (rowA[j] >> 5) & 0x7;
510          const int rowAb1 = (rowA[k] >> 5) & 0x7;
511          const int rowBb0 = (rowB[j] >> 5) & 0x7;
512          const int rowBb1 = (rowB[k] >> 5) & 0x7;
513          const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
514          const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
515          const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
516          dst[i] = (blue << 5) | (green << 2) | red;
517       }
518    }
519    else {
520       debug_printf("bad format in do_row()");
521    }
522 }
523
524
525 /**
526  * Average together four rows of a source image to produce a single new
527  * row in the dest image.  It's legal for the two source rows to point
528  * to the same data.  The source width must be equal to either the
529  * dest width or two times the dest width.
530  *
531  * \param datatype  GL pixel type \c GL_UNSIGNED_BYTE, \c GL_UNSIGNED_SHORT,
532  *                  \c GL_FLOAT, etc.
533  * \param comps     number of components per pixel (1..4)
534  * \param srcWidth  Width of a row in the source data
535  * \param srcRowA   Pointer to one of the rows of source data
536  * \param srcRowB   Pointer to one of the rows of source data
537  * \param srcRowC   Pointer to one of the rows of source data
538  * \param srcRowD   Pointer to one of the rows of source data
539  * \param dstWidth  Width of a row in the destination data
540  * \param srcRowA   Pointer to the row of destination data
541  */
542 static void
543 do_row_3D(enum dtype datatype, uint comps, int srcWidth,
544           const void *srcRowA, const void *srcRowB,
545           const void *srcRowC, const void *srcRowD,
546           int dstWidth, void *dstRow)
547 {
548    const uint k0 = (srcWidth == dstWidth) ? 0 : 1;
549    const uint colStride = (srcWidth == dstWidth) ? 1 : 2;
550    uint i, j, k;
551
552    assert(comps >= 1);
553    assert(comps <= 4);
554
555    if ((datatype == DTYPE_UBYTE) && (comps == 4)) {
556       DECLARE_ROW_POINTERS(ubyte, 4);
557
558       for (i = j = 0, k = k0; i < (uint) dstWidth;
559            i++, j += colStride, k += colStride) {
560          FILTER_3D(0);
561          FILTER_3D(1);
562          FILTER_3D(2);
563          FILTER_3D(3);
564       }
565    }
566    else if ((datatype == DTYPE_UBYTE) && (comps == 3)) {
567       DECLARE_ROW_POINTERS(ubyte, 3);
568
569       for (i = j = 0, k = k0; i < (uint) dstWidth;
570            i++, j += colStride, k += colStride) {
571          FILTER_3D(0);
572          FILTER_3D(1);
573          FILTER_3D(2);
574       }
575    }
576    else if ((datatype == DTYPE_UBYTE) && (comps == 2)) {
577       DECLARE_ROW_POINTERS(ubyte, 2);
578
579       for (i = j = 0, k = k0; i < (uint) dstWidth;
580            i++, j += colStride, k += colStride) {
581          FILTER_3D(0);
582          FILTER_3D(1);
583       }
584    }
585    else if ((datatype == DTYPE_UBYTE) && (comps == 1)) {
586       DECLARE_ROW_POINTERS(ubyte, 1);
587
588       for (i = j = 0, k = k0; i < (uint) dstWidth;
589            i++, j += colStride, k += colStride) {
590          FILTER_3D(0);
591       }
592    }
593    else if ((datatype == DTYPE_USHORT) && (comps == 4)) {
594       DECLARE_ROW_POINTERS(ushort, 4);
595
596       for (i = j = 0, k = k0; i < (uint) dstWidth;
597            i++, j += colStride, k += colStride) {
598          FILTER_3D(0);
599          FILTER_3D(1);
600          FILTER_3D(2);
601          FILTER_3D(3);
602       }
603    }
604    else if ((datatype == DTYPE_USHORT) && (comps == 3)) {
605       DECLARE_ROW_POINTERS(ushort, 3);
606
607       for (i = j = 0, k = k0; i < (uint) dstWidth;
608            i++, j += colStride, k += colStride) {
609          FILTER_3D(0);
610          FILTER_3D(1);
611          FILTER_3D(2);
612       }
613    }
614    else if ((datatype == DTYPE_USHORT) && (comps == 2)) {
615       DECLARE_ROW_POINTERS(ushort, 2);
616
617       for (i = j = 0, k = k0; i < (uint) dstWidth;
618            i++, j += colStride, k += colStride) {
619          FILTER_3D(0);
620          FILTER_3D(1);
621       }
622    }
623    else if ((datatype == DTYPE_USHORT) && (comps == 1)) {
624       DECLARE_ROW_POINTERS(ushort, 1);
625
626       for (i = j = 0, k = k0; i < (uint) dstWidth;
627            i++, j += colStride, k += colStride) {
628          FILTER_3D(0);
629       }
630    }
631    else if ((datatype == DTYPE_FLOAT) && (comps == 4)) {
632       DECLARE_ROW_POINTERS(float, 4);
633
634       for (i = j = 0, k = k0; i < (uint) dstWidth;
635            i++, j += colStride, k += colStride) {
636          FILTER_F_3D(0);
637          FILTER_F_3D(1);
638          FILTER_F_3D(2);
639          FILTER_F_3D(3);
640       }
641    }
642    else if ((datatype == DTYPE_FLOAT) && (comps == 3)) {
643       DECLARE_ROW_POINTERS(float, 3);
644
645       for (i = j = 0, k = k0; i < (uint) dstWidth;
646            i++, j += colStride, k += colStride) {
647          FILTER_F_3D(0);
648          FILTER_F_3D(1);
649          FILTER_F_3D(2);
650       }
651    }
652    else if ((datatype == DTYPE_FLOAT) && (comps == 2)) {
653       DECLARE_ROW_POINTERS(float, 2);
654
655       for (i = j = 0, k = k0; i < (uint) dstWidth;
656            i++, j += colStride, k += colStride) {
657          FILTER_F_3D(0);
658          FILTER_F_3D(1);
659       }
660    }
661    else if ((datatype == DTYPE_FLOAT) && (comps == 1)) {
662       DECLARE_ROW_POINTERS(float, 1);
663
664       for (i = j = 0, k = k0; i < (uint) dstWidth;
665            i++, j += colStride, k += colStride) {
666          FILTER_F_3D(0);
667       }
668    }
669    else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 4)) {
670       DECLARE_ROW_POINTERS(half_float, 4);
671
672       for (i = j = 0, k = k0; i < (uint) dstWidth;
673            i++, j += colStride, k += colStride) {
674          FILTER_HF_3D(0);
675          FILTER_HF_3D(1);
676          FILTER_HF_3D(2);
677          FILTER_HF_3D(3);
678       }
679    }
680    else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 3)) {
681       DECLARE_ROW_POINTERS(half_float, 4);
682
683       for (i = j = 0, k = k0; i < (uint) dstWidth;
684            i++, j += colStride, k += colStride) {
685          FILTER_HF_3D(0);
686          FILTER_HF_3D(1);
687          FILTER_HF_3D(2);
688       }
689    }
690    else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 2)) {
691       DECLARE_ROW_POINTERS(half_float, 4);
692
693       for (i = j = 0, k = k0; i < (uint) dstWidth;
694            i++, j += colStride, k += colStride) {
695          FILTER_HF_3D(0);
696          FILTER_HF_3D(1);
697       }
698    }
699    else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 1)) {
700       DECLARE_ROW_POINTERS(half_float, 4);
701
702       for (i = j = 0, k = k0; i < (uint) dstWidth;
703            i++, j += colStride, k += colStride) {
704          FILTER_HF_3D(0);
705       }
706    }
707    else if ((datatype == DTYPE_UINT) && (comps == 1)) {
708       const uint *rowA = (const uint *) srcRowA;
709       const uint *rowB = (const uint *) srcRowB;
710       const uint *rowC = (const uint *) srcRowC;
711       const uint *rowD = (const uint *) srcRowD;
712       float *dst = (float *) dstRow;
713
714       for (i = j = 0, k = k0; i < (uint) dstWidth;
715            i++, j += colStride, k += colStride) {
716          const uint64_t tmp = (((uint64_t) rowA[j] + (uint64_t) rowA[k])
717                                + ((uint64_t) rowB[j] + (uint64_t) rowB[k])
718                                + ((uint64_t) rowC[j] + (uint64_t) rowC[k])
719                                + ((uint64_t) rowD[j] + (uint64_t) rowD[k]));
720          dst[i] = (float)((double) tmp * 0.125);
721       }
722    }
723    else if ((datatype == DTYPE_USHORT_5_6_5) && (comps == 3)) {
724       DECLARE_ROW_POINTERS0(ushort);
725
726       for (i = j = 0, k = k0; i < (uint) dstWidth;
727            i++, j += colStride, k += colStride) {
728          const int rowAr0 = rowA[j] & 0x1f;
729          const int rowAr1 = rowA[k] & 0x1f;
730          const int rowBr0 = rowB[j] & 0x1f;
731          const int rowBr1 = rowB[k] & 0x1f;
732          const int rowCr0 = rowC[j] & 0x1f;
733          const int rowCr1 = rowC[k] & 0x1f;
734          const int rowDr0 = rowD[j] & 0x1f;
735          const int rowDr1 = rowD[k] & 0x1f;
736          const int rowAg0 = (rowA[j] >> 5) & 0x3f;
737          const int rowAg1 = (rowA[k] >> 5) & 0x3f;
738          const int rowBg0 = (rowB[j] >> 5) & 0x3f;
739          const int rowBg1 = (rowB[k] >> 5) & 0x3f;
740          const int rowCg0 = (rowC[j] >> 5) & 0x3f;
741          const int rowCg1 = (rowC[k] >> 5) & 0x3f;
742          const int rowDg0 = (rowD[j] >> 5) & 0x3f;
743          const int rowDg1 = (rowD[k] >> 5) & 0x3f;
744          const int rowAb0 = (rowA[j] >> 11) & 0x1f;
745          const int rowAb1 = (rowA[k] >> 11) & 0x1f;
746          const int rowBb0 = (rowB[j] >> 11) & 0x1f;
747          const int rowBb1 = (rowB[k] >> 11) & 0x1f;
748          const int rowCb0 = (rowC[j] >> 11) & 0x1f;
749          const int rowCb1 = (rowC[k] >> 11) & 0x1f;
750          const int rowDb0 = (rowD[j] >> 11) & 0x1f;
751          const int rowDb1 = (rowD[k] >> 11) & 0x1f;
752          const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
753                                        rowCr0, rowCr1, rowDr0, rowDr1);
754          const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
755                                        rowCg0, rowCg1, rowDg0, rowDg1);
756          const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
757                                        rowCb0, rowCb1, rowDb0, rowDb1);
758          dst[i] = (b << 11) | (g << 5) | r;
759       }
760    }
761    else if ((datatype == DTYPE_USHORT_4_4_4_4) && (comps == 4)) {
762       DECLARE_ROW_POINTERS0(ushort);
763
764       for (i = j = 0, k = k0; i < (uint) dstWidth;
765            i++, j += colStride, k += colStride) {
766          const int rowAr0 = rowA[j] & 0xf;
767          const int rowAr1 = rowA[k] & 0xf;
768          const int rowBr0 = rowB[j] & 0xf;
769          const int rowBr1 = rowB[k] & 0xf;
770          const int rowCr0 = rowC[j] & 0xf;
771          const int rowCr1 = rowC[k] & 0xf;
772          const int rowDr0 = rowD[j] & 0xf;
773          const int rowDr1 = rowD[k] & 0xf;
774          const int rowAg0 = (rowA[j] >> 4) & 0xf;
775          const int rowAg1 = (rowA[k] >> 4) & 0xf;
776          const int rowBg0 = (rowB[j] >> 4) & 0xf;
777          const int rowBg1 = (rowB[k] >> 4) & 0xf;
778          const int rowCg0 = (rowC[j] >> 4) & 0xf;
779          const int rowCg1 = (rowC[k] >> 4) & 0xf;
780          const int rowDg0 = (rowD[j] >> 4) & 0xf;
781          const int rowDg1 = (rowD[k] >> 4) & 0xf;
782          const int rowAb0 = (rowA[j] >> 8) & 0xf;
783          const int rowAb1 = (rowA[k] >> 8) & 0xf;
784          const int rowBb0 = (rowB[j] >> 8) & 0xf;
785          const int rowBb1 = (rowB[k] >> 8) & 0xf;
786          const int rowCb0 = (rowC[j] >> 8) & 0xf;
787          const int rowCb1 = (rowC[k] >> 8) & 0xf;
788          const int rowDb0 = (rowD[j] >> 8) & 0xf;
789          const int rowDb1 = (rowD[k] >> 8) & 0xf;
790          const int rowAa0 = (rowA[j] >> 12) & 0xf;
791          const int rowAa1 = (rowA[k] >> 12) & 0xf;
792          const int rowBa0 = (rowB[j] >> 12) & 0xf;
793          const int rowBa1 = (rowB[k] >> 12) & 0xf;
794          const int rowCa0 = (rowC[j] >> 12) & 0xf;
795          const int rowCa1 = (rowC[k] >> 12) & 0xf;
796          const int rowDa0 = (rowD[j] >> 12) & 0xf;
797          const int rowDa1 = (rowD[k] >> 12) & 0xf;
798          const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
799                                        rowCr0, rowCr1, rowDr0, rowDr1);
800          const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
801                                        rowCg0, rowCg1, rowDg0, rowDg1);
802          const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
803                                        rowCb0, rowCb1, rowDb0, rowDb1);
804          const int a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
805                                        rowCa0, rowCa1, rowDa0, rowDa1);
806
807          dst[i] = (a << 12) | (b << 8) | (g << 4) | r;
808       }
809    }
810    else if ((datatype == DTYPE_USHORT_1_5_5_5_REV) && (comps == 4)) {
811       DECLARE_ROW_POINTERS0(ushort);
812
813       for (i = j = 0, k = k0; i < (uint) dstWidth;
814            i++, j += colStride, k += colStride) {
815          const int rowAr0 = rowA[j] & 0x1f;
816          const int rowAr1 = rowA[k] & 0x1f;
817          const int rowBr0 = rowB[j] & 0x1f;
818          const int rowBr1 = rowB[k] & 0x1f;
819          const int rowCr0 = rowC[j] & 0x1f;
820          const int rowCr1 = rowC[k] & 0x1f;
821          const int rowDr0 = rowD[j] & 0x1f;
822          const int rowDr1 = rowD[k] & 0x1f;
823          const int rowAg0 = (rowA[j] >> 5) & 0x1f;
824          const int rowAg1 = (rowA[k] >> 5) & 0x1f;
825          const int rowBg0 = (rowB[j] >> 5) & 0x1f;
826          const int rowBg1 = (rowB[k] >> 5) & 0x1f;
827          const int rowCg0 = (rowC[j] >> 5) & 0x1f;
828          const int rowCg1 = (rowC[k] >> 5) & 0x1f;
829          const int rowDg0 = (rowD[j] >> 5) & 0x1f;
830          const int rowDg1 = (rowD[k] >> 5) & 0x1f;
831          const int rowAb0 = (rowA[j] >> 10) & 0x1f;
832          const int rowAb1 = (rowA[k] >> 10) & 0x1f;
833          const int rowBb0 = (rowB[j] >> 10) & 0x1f;
834          const int rowBb1 = (rowB[k] >> 10) & 0x1f;
835          const int rowCb0 = (rowC[j] >> 10) & 0x1f;
836          const int rowCb1 = (rowC[k] >> 10) & 0x1f;
837          const int rowDb0 = (rowD[j] >> 10) & 0x1f;
838          const int rowDb1 = (rowD[k] >> 10) & 0x1f;
839          const int rowAa0 = (rowA[j] >> 15) & 0x1;
840          const int rowAa1 = (rowA[k] >> 15) & 0x1;
841          const int rowBa0 = (rowB[j] >> 15) & 0x1;
842          const int rowBa1 = (rowB[k] >> 15) & 0x1;
843          const int rowCa0 = (rowC[j] >> 15) & 0x1;
844          const int rowCa1 = (rowC[k] >> 15) & 0x1;
845          const int rowDa0 = (rowD[j] >> 15) & 0x1;
846          const int rowDa1 = (rowD[k] >> 15) & 0x1;
847          const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
848                                        rowCr0, rowCr1, rowDr0, rowDr1);
849          const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
850                                        rowCg0, rowCg1, rowDg0, rowDg1);
851          const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
852                                        rowCb0, rowCb1, rowDb0, rowDb1);
853          const int a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
854                                        rowCa0, rowCa1, rowDa0, rowDa1);
855
856          dst[i] = (a << 15) | (b << 10) | (g << 5) | r;
857       }
858    }
859    else if ((datatype == DTYPE_UBYTE_3_3_2) && (comps == 3)) {
860       DECLARE_ROW_POINTERS0(ushort);
861
862       for (i = j = 0, k = k0; i < (uint) dstWidth;
863            i++, j += colStride, k += colStride) {
864          const int rowAr0 = rowA[j] & 0x3;
865          const int rowAr1 = rowA[k] & 0x3;
866          const int rowBr0 = rowB[j] & 0x3;
867          const int rowBr1 = rowB[k] & 0x3;
868          const int rowCr0 = rowC[j] & 0x3;
869          const int rowCr1 = rowC[k] & 0x3;
870          const int rowDr0 = rowD[j] & 0x3;
871          const int rowDr1 = rowD[k] & 0x3;
872          const int rowAg0 = (rowA[j] >> 2) & 0x7;
873          const int rowAg1 = (rowA[k] >> 2) & 0x7;
874          const int rowBg0 = (rowB[j] >> 2) & 0x7;
875          const int rowBg1 = (rowB[k] >> 2) & 0x7;
876          const int rowCg0 = (rowC[j] >> 2) & 0x7;
877          const int rowCg1 = (rowC[k] >> 2) & 0x7;
878          const int rowDg0 = (rowD[j] >> 2) & 0x7;
879          const int rowDg1 = (rowD[k] >> 2) & 0x7;
880          const int rowAb0 = (rowA[j] >> 5) & 0x7;
881          const int rowAb1 = (rowA[k] >> 5) & 0x7;
882          const int rowBb0 = (rowB[j] >> 5) & 0x7;
883          const int rowBb1 = (rowB[k] >> 5) & 0x7;
884          const int rowCb0 = (rowC[j] >> 5) & 0x7;
885          const int rowCb1 = (rowC[k] >> 5) & 0x7;
886          const int rowDb0 = (rowD[j] >> 5) & 0x7;
887          const int rowDb1 = (rowD[k] >> 5) & 0x7;
888          const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
889                                        rowCr0, rowCr1, rowDr0, rowDr1);
890          const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
891                                        rowCg0, rowCg1, rowDg0, rowDg1);
892          const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
893                                        rowCb0, rowCb1, rowDb0, rowDb1);
894          dst[i] = (b << 5) | (g << 2) | r;
895       }
896    }
897    else {
898       debug_printf("bad format in do_row_3D()");
899    }
900 }
901
902
903
904 static void
905 format_to_type_comps(enum pipe_format pformat,
906                      enum dtype *datatype, uint *comps)
907 {
908    /* XXX I think this could be implemented in terms of the pf_*() functions */
909    switch (pformat) {
910    case PIPE_FORMAT_B8G8R8A8_UNORM:
911    case PIPE_FORMAT_B8G8R8X8_UNORM:
912    case PIPE_FORMAT_A8R8G8B8_UNORM:
913    case PIPE_FORMAT_X8R8G8B8_UNORM:
914    case PIPE_FORMAT_A8B8G8R8_SRGB:
915    case PIPE_FORMAT_X8B8G8R8_SRGB:
916    case PIPE_FORMAT_B8G8R8A8_SRGB:
917    case PIPE_FORMAT_B8G8R8X8_SRGB:
918    case PIPE_FORMAT_A8R8G8B8_SRGB:
919    case PIPE_FORMAT_X8R8G8B8_SRGB:
920    case PIPE_FORMAT_R8G8B8_SRGB:
921       *datatype = DTYPE_UBYTE;
922       *comps = 4;
923       return;
924    case PIPE_FORMAT_B5G5R5X1_UNORM:
925    case PIPE_FORMAT_B5G5R5A1_UNORM:
926       *datatype = DTYPE_USHORT_1_5_5_5_REV;
927       *comps = 4;
928       return;
929    case PIPE_FORMAT_B4G4R4A4_UNORM:
930       *datatype = DTYPE_USHORT_4_4_4_4;
931       *comps = 4;
932       return;
933    case PIPE_FORMAT_B5G6R5_UNORM:
934       *datatype = DTYPE_USHORT_5_6_5;
935       *comps = 3;
936       return;
937    case PIPE_FORMAT_L8_UNORM:
938    case PIPE_FORMAT_L8_SRGB:
939    case PIPE_FORMAT_A8_UNORM:
940    case PIPE_FORMAT_I8_UNORM:
941       *datatype = DTYPE_UBYTE;
942       *comps = 1;
943       return;
944    case PIPE_FORMAT_L8A8_UNORM:
945    case PIPE_FORMAT_L8A8_SRGB:
946       *datatype = DTYPE_UBYTE;
947       *comps = 2;
948       return;
949    default:
950       assert(0);
951       *datatype = DTYPE_UBYTE;
952       *comps = 0;
953       break;
954    }
955 }
956
957
958 static void
959 reduce_1d(enum pipe_format pformat,
960           int srcWidth, const ubyte *srcPtr,
961           int dstWidth, ubyte *dstPtr)
962 {
963    enum dtype datatype;
964    uint comps;
965
966    format_to_type_comps(pformat, &datatype, &comps);
967
968    /* we just duplicate the input row, kind of hack, saves code */
969    do_row(datatype, comps,
970           srcWidth, srcPtr, srcPtr,
971           dstWidth, dstPtr);
972 }
973
974
975 /**
976  * Strides are in bytes.  If zero, it'll be computed as width * bpp.
977  */
978 static void
979 reduce_2d(enum pipe_format pformat,
980           int srcWidth, int srcHeight,
981           int srcRowStride, const ubyte *srcPtr,
982           int dstWidth, int dstHeight,
983           int dstRowStride, ubyte *dstPtr)
984 {
985    enum dtype datatype;
986    uint comps;
987    const int bpt = util_format_get_blocksize(pformat);
988    const ubyte *srcA, *srcB;
989    ubyte *dst;
990    int row;
991
992    format_to_type_comps(pformat, &datatype, &comps);
993
994    if (!srcRowStride)
995       srcRowStride = bpt * srcWidth;
996
997    if (!dstRowStride)
998       dstRowStride = bpt * dstWidth;
999
1000    /* Compute src and dst pointers */
1001    srcA = srcPtr;
1002    if (srcHeight > 1) 
1003       srcB = srcA + srcRowStride;
1004    else
1005       srcB = srcA;
1006    dst = dstPtr;
1007
1008    for (row = 0; row < dstHeight; row++) {
1009       do_row(datatype, comps,
1010              srcWidth, srcA, srcB,
1011              dstWidth, dst);
1012       srcA += 2 * srcRowStride;
1013       srcB += 2 * srcRowStride;
1014       dst += dstRowStride;
1015    }
1016 }
1017
1018
1019 static void
1020 reduce_3d(enum pipe_format pformat,
1021           int srcWidth, int srcHeight, int srcDepth,
1022           int srcRowStride, int srcImageStride, const ubyte *srcPtr,
1023           int dstWidth, int dstHeight, int dstDepth,
1024           int dstRowStride, int dstImageStride, ubyte *dstPtr)
1025 {
1026    const int bpt = util_format_get_blocksize(pformat);
1027    int img, row;
1028    int srcImageOffset, srcRowOffset;
1029    enum dtype datatype;
1030    uint comps;
1031
1032    format_to_type_comps(pformat, &datatype, &comps);
1033
1034    /* XXX I think we should rather assert those strides */
1035    if (!srcImageStride)
1036       srcImageStride = srcWidth * srcHeight * bpt;
1037    if (!dstImageStride)
1038       dstImageStride = dstWidth * dstHeight * bpt;
1039
1040    if (!srcRowStride)
1041       srcRowStride = srcWidth * bpt;
1042    if (!dstRowStride)
1043       dstRowStride = dstWidth * bpt;
1044
1045    /* Offset between adjacent src images to be averaged together */
1046    srcImageOffset = (srcDepth == dstDepth) ? 0 : srcImageStride;
1047
1048    /* Offset between adjacent src rows to be averaged together */
1049    srcRowOffset = (srcHeight == dstHeight) ? 0 : srcRowStride;
1050
1051    /*
1052     * Need to average together up to 8 src pixels for each dest pixel.
1053     * Break that down into 3 operations:
1054     *   1. take two rows from source image and average them together.
1055     *   2. take two rows from next source image and average them together.
1056     *   3. take the two averaged rows and average them for the final dst row.
1057     */
1058
1059    /*
1060    printf("mip3d %d x %d x %d  ->  %d x %d x %d\n",
1061           srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
1062    */
1063
1064    for (img = 0; img < dstDepth; img++) {
1065       /* first source image pointer */
1066       const ubyte *imgSrcA = srcPtr
1067          + img * (srcImageStride + srcImageOffset);
1068       /* second source image pointer */
1069       const ubyte *imgSrcB = imgSrcA + srcImageOffset;
1070       /* address of the dest image */
1071       ubyte *imgDst = dstPtr + img * dstImageStride;
1072
1073       /* setup the four source row pointers and the dest row pointer */
1074       const ubyte *srcImgARowA = imgSrcA;
1075       const ubyte *srcImgARowB = imgSrcA + srcRowOffset;
1076       const ubyte *srcImgBRowA = imgSrcB;
1077       const ubyte *srcImgBRowB = imgSrcB + srcRowOffset;
1078       ubyte *dstImgRow = imgDst;
1079
1080       for (row = 0; row < dstHeight; row++) {
1081          do_row_3D(datatype, comps, srcWidth, 
1082                    srcImgARowA, srcImgARowB,
1083                    srcImgBRowA, srcImgBRowB,
1084                    dstWidth, dstImgRow);
1085
1086          /* advance to next rows */
1087          srcImgARowA += srcRowStride + srcRowOffset;
1088          srcImgARowB += srcRowStride + srcRowOffset;
1089          srcImgBRowA += srcRowStride + srcRowOffset;
1090          srcImgBRowB += srcRowStride + srcRowOffset;
1091          dstImgRow += dstImageStride;
1092       }
1093    }
1094 }
1095
1096
1097
1098
1099 static void
1100 make_1d_mipmap(struct gen_mipmap_state *ctx,
1101                struct pipe_resource *pt,
1102                uint layer, uint baseLevel, uint lastLevel)
1103 {
1104    struct pipe_context *pipe = ctx->pipe;
1105    uint dstLevel;
1106
1107    for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
1108       const uint srcLevel = dstLevel - 1;
1109       struct pipe_transfer *srcTrans, *dstTrans;
1110       void *srcMap, *dstMap;
1111
1112       srcTrans = pipe_get_transfer(pipe, pt, srcLevel, layer,
1113                                    PIPE_TRANSFER_READ, 0, 0,
1114                                    u_minify(pt->width0, srcLevel),
1115                                    u_minify(pt->height0, srcLevel));
1116       dstTrans = pipe_get_transfer(pipe, pt, dstLevel, layer,
1117                                    PIPE_TRANSFER_WRITE, 0, 0,
1118                                    u_minify(pt->width0, dstLevel),
1119                                    u_minify(pt->height0, dstLevel));
1120
1121       srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans);
1122       dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans);
1123
1124       reduce_1d(pt->format,
1125                 srcTrans->box.width, srcMap,
1126                 dstTrans->box.width, dstMap);
1127
1128       pipe->transfer_unmap(pipe, srcTrans);
1129       pipe->transfer_unmap(pipe, dstTrans);
1130
1131       pipe->transfer_destroy(pipe, srcTrans);
1132       pipe->transfer_destroy(pipe, dstTrans);
1133    }
1134 }
1135
1136
1137 static void
1138 make_2d_mipmap(struct gen_mipmap_state *ctx,
1139                struct pipe_resource *pt,
1140                uint layer, uint baseLevel, uint lastLevel)
1141 {
1142    struct pipe_context *pipe = ctx->pipe;
1143    uint dstLevel;
1144
1145    assert(util_format_get_blockwidth(pt->format) == 1);
1146    assert(util_format_get_blockheight(pt->format) == 1);
1147
1148    for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
1149       const uint srcLevel = dstLevel - 1;
1150       struct pipe_transfer *srcTrans, *dstTrans;
1151       ubyte *srcMap, *dstMap;
1152
1153       srcTrans = pipe_get_transfer(pipe, pt, srcLevel, layer,
1154                                    PIPE_TRANSFER_READ, 0, 0,
1155                                    u_minify(pt->width0, srcLevel),
1156                                    u_minify(pt->height0, srcLevel));
1157       dstTrans = pipe_get_transfer(pipe, pt, dstLevel, layer,
1158                                    PIPE_TRANSFER_WRITE, 0, 0,
1159                                    u_minify(pt->width0, dstLevel),
1160                                    u_minify(pt->height0, dstLevel));
1161
1162       srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans);
1163       dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans);
1164
1165       reduce_2d(pt->format,
1166                 srcTrans->box.width, srcTrans->box.height,
1167                 srcTrans->stride, srcMap,
1168                 dstTrans->box.width, dstTrans->box.height,
1169                 dstTrans->stride, dstMap);
1170
1171       pipe->transfer_unmap(pipe, srcTrans);
1172       pipe->transfer_unmap(pipe, dstTrans);
1173
1174       pipe->transfer_destroy(pipe, srcTrans);
1175       pipe->transfer_destroy(pipe, dstTrans);
1176    }
1177 }
1178
1179
1180 /* XXX looks a bit more like it could work now but need to test */
1181 static void
1182 make_3d_mipmap(struct gen_mipmap_state *ctx,
1183                struct pipe_resource *pt,
1184                uint face, uint baseLevel, uint lastLevel)
1185 {
1186    struct pipe_context *pipe = ctx->pipe;
1187    uint dstLevel;
1188    struct pipe_box src_box, dst_box;
1189
1190    assert(util_format_get_blockwidth(pt->format) == 1);
1191    assert(util_format_get_blockheight(pt->format) == 1);
1192
1193    src_box.x = src_box.y = src_box.z = 0;
1194    dst_box.x = dst_box.y = dst_box.z = 0;
1195
1196    for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
1197       const uint srcLevel = dstLevel - 1;
1198       struct pipe_transfer *srcTrans, *dstTrans;
1199       ubyte *srcMap, *dstMap;
1200       struct pipe_box src_box, dst_box;
1201       src_box.width = u_minify(pt->width0, srcLevel);
1202       src_box.height = u_minify(pt->height0, srcLevel);
1203       src_box.depth = u_minify(pt->depth0, srcLevel);
1204       dst_box.width = u_minify(pt->width0, dstLevel);
1205       dst_box.height = u_minify(pt->height0, dstLevel);
1206       dst_box.depth = u_minify(pt->depth0, dstLevel);
1207
1208       srcTrans = pipe->get_transfer(pipe, pt, srcLevel,
1209                                     PIPE_TRANSFER_READ,
1210                                     &src_box);
1211       dstTrans = pipe->get_transfer(pipe, pt, dstLevel,
1212                                     PIPE_TRANSFER_WRITE,
1213                                     &dst_box);
1214
1215       srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans);
1216       dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans);
1217
1218       reduce_3d(pt->format,
1219                 srcTrans->box.width, srcTrans->box.height, srcTrans->box.depth,
1220                 srcTrans->stride, srcTrans->layer_stride, srcMap,
1221                 dstTrans->box.width, dstTrans->box.height, dstTrans->box.depth,
1222                 dstTrans->stride, dstTrans->layer_stride, dstMap);
1223
1224       pipe->transfer_unmap(pipe, srcTrans);
1225       pipe->transfer_unmap(pipe, dstTrans);
1226
1227       pipe->transfer_destroy(pipe, srcTrans);
1228       pipe->transfer_destroy(pipe, dstTrans);
1229    }
1230 }
1231
1232
1233 static void
1234 fallback_gen_mipmap(struct gen_mipmap_state *ctx,
1235                     struct pipe_resource *pt,
1236                     uint layer, uint baseLevel, uint lastLevel)
1237 {
1238    switch (pt->target) {
1239    case PIPE_TEXTURE_1D:
1240       make_1d_mipmap(ctx, pt, layer, baseLevel, lastLevel);
1241       break;
1242    case PIPE_TEXTURE_2D:
1243    case PIPE_TEXTURE_RECT:
1244    case PIPE_TEXTURE_CUBE:
1245       make_2d_mipmap(ctx, pt, layer, baseLevel, lastLevel);
1246       break;
1247    case PIPE_TEXTURE_3D:
1248       make_3d_mipmap(ctx, pt, layer, baseLevel, lastLevel);
1249       break;
1250    default:
1251       assert(0);
1252    }
1253 }
1254
1255
1256 /**
1257  * Create a mipmap generation context.
1258  * The idea is to create one of these and re-use it each time we need to
1259  * generate a mipmap.
1260  */
1261 struct gen_mipmap_state *
1262 util_create_gen_mipmap(struct pipe_context *pipe,
1263                        struct cso_context *cso)
1264 {
1265    struct gen_mipmap_state *ctx;
1266    uint i;
1267
1268    ctx = CALLOC_STRUCT(gen_mipmap_state);
1269    if (!ctx)
1270       return NULL;
1271
1272    ctx->pipe = pipe;
1273    ctx->cso = cso;
1274
1275    /* disabled blending/masking */
1276    memset(&ctx->blend, 0, sizeof(ctx->blend));
1277    ctx->blend.rt[0].colormask = PIPE_MASK_RGBA;
1278
1279    /* no-op depth/stencil/alpha */
1280    memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil));
1281
1282    /* rasterizer */
1283    memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer));
1284    ctx->rasterizer.cull_face = PIPE_FACE_NONE;
1285    ctx->rasterizer.gl_rasterization_rules = 1;
1286
1287    /* sampler state */
1288    memset(&ctx->sampler, 0, sizeof(ctx->sampler));
1289    ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1290    ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1291    ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1292    ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
1293    ctx->sampler.normalized_coords = 1;
1294
1295    /* vertex elements state */
1296    memset(&ctx->velem[0], 0, sizeof(ctx->velem[0]) * 2);
1297    for (i = 0; i < 2; i++) {
1298       ctx->velem[i].src_offset = i * 4 * sizeof(float);
1299       ctx->velem[i].instance_divisor = 0;
1300       ctx->velem[i].vertex_buffer_index = 0;
1301       ctx->velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
1302    }
1303
1304    /* vertex data that doesn't change */
1305    for (i = 0; i < 4; i++) {
1306       ctx->vertices[i][0][2] = 0.0f; /* z */
1307       ctx->vertices[i][0][3] = 1.0f; /* w */
1308       ctx->vertices[i][1][3] = 1.0f; /* q */
1309    }
1310
1311    /* Note: the actual vertex buffer is allocated as needed below */
1312
1313    return ctx;
1314 }
1315
1316
1317 /**
1318  * Helper function to set the fragment shaders.
1319  */
1320 static INLINE void
1321 set_fragment_shader(struct gen_mipmap_state *ctx, uint type)
1322 {
1323    if (!ctx->fs[type])
1324       ctx->fs[type] =
1325          util_make_fragment_tex_shader(ctx->pipe, type,
1326                                        TGSI_INTERPOLATE_LINEAR);
1327
1328    cso_set_fragment_shader_handle(ctx->cso, ctx->fs[type]);
1329 }
1330
1331
1332 /**
1333  * Helper function to set the vertex shader.
1334  */
1335 static INLINE void
1336 set_vertex_shader(struct gen_mipmap_state *ctx)
1337 {
1338    /* vertex shader - still required to provide the linkage between
1339     * fragment shader input semantics and vertex_element/buffers.
1340     */
1341    if (!ctx->vs)
1342    {
1343       const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
1344                                       TGSI_SEMANTIC_GENERIC };
1345       const uint semantic_indexes[] = { 0, 0 };
1346       ctx->vs = util_make_vertex_passthrough_shader(ctx->pipe, 2,
1347                                                     semantic_names,
1348                                                     semantic_indexes);
1349    }
1350
1351    cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
1352 }
1353
1354
1355 /**
1356  * Get next "slot" of vertex space in the vertex buffer.
1357  * We're allocating one large vertex buffer and using it piece by piece.
1358  */
1359 static unsigned
1360 get_next_slot(struct gen_mipmap_state *ctx)
1361 {
1362    const unsigned max_slots = 4096 / sizeof ctx->vertices;
1363
1364    if (ctx->vbuf_slot >= max_slots) 
1365       util_gen_mipmap_flush( ctx );
1366
1367    if (!ctx->vbuf) {
1368       ctx->vbuf = pipe_buffer_create(ctx->pipe->screen,
1369                                      PIPE_BIND_VERTEX_BUFFER,
1370                                      PIPE_USAGE_STREAM,
1371                                      max_slots * sizeof ctx->vertices);
1372    }
1373    
1374    return ctx->vbuf_slot++ * sizeof ctx->vertices;
1375 }
1376
1377
1378 static unsigned
1379 set_vertex_data(struct gen_mipmap_state *ctx,
1380                 enum pipe_texture_target tex_target,
1381                 uint layer, float r)
1382 {
1383    unsigned offset;
1384
1385    /* vert[0].position */
1386    ctx->vertices[0][0][0] = -1.0f; /*x*/
1387    ctx->vertices[0][0][1] = -1.0f; /*y*/
1388
1389    /* vert[1].position */
1390    ctx->vertices[1][0][0] = 1.0f;
1391    ctx->vertices[1][0][1] = -1.0f;
1392
1393    /* vert[2].position */
1394    ctx->vertices[2][0][0] = 1.0f;
1395    ctx->vertices[2][0][1] = 1.0f;
1396
1397    /* vert[3].position */
1398    ctx->vertices[3][0][0] = -1.0f;
1399    ctx->vertices[3][0][1] = 1.0f;
1400
1401    /* Setup vertex texcoords.  This is a little tricky for cube maps. */
1402    if (tex_target == PIPE_TEXTURE_CUBE) {
1403       static const float st[4][2] = {
1404          {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}
1405       };
1406
1407       util_map_texcoords2d_onto_cubemap(layer, &st[0][0], 2,
1408                                         &ctx->vertices[0][1][0], 8);
1409    }
1410    else if (tex_target == PIPE_TEXTURE_1D_ARRAY) {
1411       /* 1D texture array  */
1412       ctx->vertices[0][1][0] = 0.0f; /*s*/
1413       ctx->vertices[0][1][1] = r; /*t*/
1414       ctx->vertices[0][1][2] = 0.0f;    /*r*/
1415
1416       ctx->vertices[1][1][0] = 1.0f;
1417       ctx->vertices[1][1][1] = r;
1418       ctx->vertices[1][1][2] = 0.0f;
1419
1420       ctx->vertices[2][1][0] = 1.0f;
1421       ctx->vertices[2][1][1] = r;
1422       ctx->vertices[2][1][2] = 0.0f;
1423
1424       ctx->vertices[3][1][0] = 0.0f;
1425       ctx->vertices[3][1][1] = r;
1426       ctx->vertices[3][1][2] = 0.0f;
1427    } else {
1428       /* 1D/2D/3D/2D array */
1429       ctx->vertices[0][1][0] = 0.0f; /*s*/
1430       ctx->vertices[0][1][1] = 0.0f; /*t*/
1431       ctx->vertices[0][1][2] = r;    /*r*/
1432
1433       ctx->vertices[1][1][0] = 1.0f;
1434       ctx->vertices[1][1][1] = 0.0f;
1435       ctx->vertices[1][1][2] = r;
1436
1437       ctx->vertices[2][1][0] = 1.0f;
1438       ctx->vertices[2][1][1] = 1.0f;
1439       ctx->vertices[2][1][2] = r;
1440
1441       ctx->vertices[3][1][0] = 0.0f;
1442       ctx->vertices[3][1][1] = 1.0f;
1443       ctx->vertices[3][1][2] = r;
1444    }
1445
1446    offset = get_next_slot( ctx );
1447
1448    pipe_buffer_write_nooverlap(ctx->pipe, ctx->vbuf,
1449                                offset, sizeof(ctx->vertices), ctx->vertices);
1450
1451    return offset;
1452 }
1453
1454
1455
1456 /**
1457  * Destroy a mipmap generation context
1458  */
1459 void
1460 util_destroy_gen_mipmap(struct gen_mipmap_state *ctx)
1461 {
1462    struct pipe_context *pipe = ctx->pipe;
1463    unsigned i;
1464
1465    for (i = 0; i < Elements(ctx->fs); i++)
1466       if (ctx->fs[i])
1467          pipe->delete_fs_state(pipe, ctx->fs[i]);
1468
1469    if (ctx->vs)
1470       pipe->delete_vs_state(pipe, ctx->vs);
1471
1472    pipe_resource_reference(&ctx->vbuf, NULL);
1473
1474    FREE(ctx);
1475 }
1476
1477
1478
1479 /* Release vertex buffer at end of frame to avoid synchronous
1480  * rendering.
1481  */
1482 void util_gen_mipmap_flush( struct gen_mipmap_state *ctx )
1483 {
1484    pipe_resource_reference(&ctx->vbuf, NULL);
1485    ctx->vbuf_slot = 0;
1486
1487
1488
1489 /**
1490  * Generate mipmap images.  It's assumed all needed texture memory is
1491  * already allocated.
1492  *
1493  * \param psv  the sampler view to the texture to generate mipmap levels for
1494  * \param face  which cube face to generate mipmaps for (0 for non-cube maps)
1495  * \param baseLevel  the first mipmap level to use as a src
1496  * \param lastLevel  the last mipmap level to generate
1497  * \param filter  the minification filter used to generate mipmap levels with
1498  * \param filter  one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST
1499  */
1500 void
1501 util_gen_mipmap(struct gen_mipmap_state *ctx,
1502                 struct pipe_sampler_view *psv,
1503                 uint face, uint baseLevel, uint lastLevel, uint filter)
1504 {
1505    struct pipe_context *pipe = ctx->pipe;
1506    struct pipe_screen *screen = pipe->screen;
1507    struct pipe_framebuffer_state fb;
1508    struct pipe_resource *pt = psv->texture;
1509    uint dstLevel;
1510    uint offset;
1511    uint type;
1512
1513    /* The texture object should have room for the levels which we're
1514     * about to generate.
1515     */
1516    assert(lastLevel <= pt->last_level);
1517
1518    /* If this fails, why are we here? */
1519    assert(lastLevel > baseLevel);
1520
1521    assert(filter == PIPE_TEX_FILTER_LINEAR ||
1522           filter == PIPE_TEX_FILTER_NEAREST);
1523
1524    switch (pt->target) {
1525    case PIPE_TEXTURE_1D:
1526       type = TGSI_TEXTURE_1D;
1527       break;
1528    case PIPE_TEXTURE_2D:
1529       type = TGSI_TEXTURE_2D;
1530       break;
1531    case PIPE_TEXTURE_3D:
1532       type = TGSI_TEXTURE_3D;
1533       break;
1534    case PIPE_TEXTURE_CUBE:
1535       type = TGSI_TEXTURE_CUBE;
1536       break;
1537    case PIPE_TEXTURE_1D_ARRAY:
1538       type = TGSI_TEXTURE_1D_ARRAY;
1539       break;
1540    case PIPE_TEXTURE_2D_ARRAY:
1541       type = TGSI_TEXTURE_2D_ARRAY;
1542       break;
1543    default:
1544       assert(0);
1545       type = TGSI_TEXTURE_2D;
1546    }
1547
1548    /* check if we can render in the texture's format */
1549    if (!screen->is_format_supported(screen, psv->format, pt->target,
1550                                     pt->nr_samples, PIPE_BIND_RENDER_TARGET)) {
1551       fallback_gen_mipmap(ctx, pt, face, baseLevel, lastLevel);
1552       return;
1553    }
1554
1555    /* save state (restored below) */
1556    cso_save_blend(ctx->cso);
1557    cso_save_depth_stencil_alpha(ctx->cso);
1558    cso_save_rasterizer(ctx->cso);
1559    cso_save_samplers(ctx->cso);
1560    cso_save_fragment_sampler_views(ctx->cso);
1561    cso_save_framebuffer(ctx->cso);
1562    cso_save_fragment_shader(ctx->cso);
1563    cso_save_vertex_shader(ctx->cso);
1564    cso_save_viewport(ctx->cso);
1565    cso_save_clip(ctx->cso);
1566    cso_save_vertex_elements(ctx->cso);
1567
1568    /* bind our state */
1569    cso_set_blend(ctx->cso, &ctx->blend);
1570    cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
1571    cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
1572    cso_set_clip(ctx->cso, &ctx->clip);
1573    cso_set_vertex_elements(ctx->cso, 2, ctx->velem);
1574
1575    set_fragment_shader(ctx, type);
1576    set_vertex_shader(ctx);
1577
1578    /* init framebuffer state */
1579    memset(&fb, 0, sizeof(fb));
1580    fb.nr_cbufs = 1;
1581
1582    /* set min/mag to same filter for faster sw speed */
1583    ctx->sampler.mag_img_filter = filter;
1584    ctx->sampler.min_img_filter = filter;
1585
1586    /*
1587     * XXX for small mipmap levels, it may be faster to use the software
1588     * fallback path...
1589     */
1590    for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
1591       const uint srcLevel = dstLevel - 1;
1592       struct pipe_viewport_state vp;
1593       unsigned nr_layers, layer, i;
1594       float rcoord = 0.0f;
1595
1596       if (pt->target == PIPE_TEXTURE_3D)
1597          nr_layers = u_minify(pt->depth0, dstLevel);
1598       else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY)
1599          nr_layers = pt->array_size;
1600       else
1601          nr_layers = 1;
1602
1603       for (i = 0; i < nr_layers; i++) {
1604          struct pipe_surface *surf, surf_templ;
1605          if (pt->target == PIPE_TEXTURE_3D) {
1606             /* in theory with geom shaders and driver with full layer support
1607                could do that in one go. */
1608             layer = i;
1609             /* XXX hmm really? */
1610             rcoord = (float)layer / (float)nr_layers + 1.0f / (float)(nr_layers * 2);
1611          } else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY) {
1612             layer = i;
1613             rcoord = (float)layer;
1614          } else
1615             layer = face;
1616
1617          memset(&surf_templ, 0, sizeof(surf_templ));
1618          u_surface_default_template(&surf_templ, pt, PIPE_BIND_RENDER_TARGET);
1619          surf_templ.u.tex.level = dstLevel;
1620          surf_templ.u.tex.first_layer = layer;
1621          surf_templ.u.tex.last_layer = layer;
1622          surf = pipe->create_surface(pipe, pt, &surf_templ);
1623
1624          /*
1625           * Setup framebuffer / dest surface
1626           */
1627          fb.cbufs[0] = surf;
1628          fb.width = u_minify(pt->width0, dstLevel);
1629          fb.height = u_minify(pt->height0, dstLevel);
1630          cso_set_framebuffer(ctx->cso, &fb);
1631
1632          /* viewport */
1633          vp.scale[0] = 0.5f * fb.width;
1634          vp.scale[1] = 0.5f * fb.height;
1635          vp.scale[2] = 1.0f;
1636          vp.scale[3] = 1.0f;
1637          vp.translate[0] = 0.5f * fb.width;
1638          vp.translate[1] = 0.5f * fb.height;
1639          vp.translate[2] = 0.0f;
1640          vp.translate[3] = 0.0f;
1641          cso_set_viewport(ctx->cso, &vp);
1642
1643          /*
1644           * Setup sampler state
1645           * Note: we should only have to set the min/max LOD clamps to ensure
1646           * we grab texels from the right mipmap level.  But some hardware
1647           * has trouble with min clamping so we also set the lod_bias to
1648           * try to work around that.
1649           */
1650          ctx->sampler.min_lod = ctx->sampler.max_lod = (float) srcLevel;
1651          ctx->sampler.lod_bias = (float) srcLevel;
1652          cso_single_sampler(ctx->cso, 0, &ctx->sampler);
1653          cso_single_sampler_done(ctx->cso);
1654
1655          cso_set_fragment_sampler_views(ctx->cso, 1, &psv);
1656
1657          /* quad coords in clip coords */
1658          offset = set_vertex_data(ctx,
1659                                   pt->target,
1660                                   face,
1661                                   rcoord);
1662
1663          util_draw_vertex_buffer(ctx->pipe,
1664                                  ctx->cso,
1665                                  ctx->vbuf,
1666                                  offset,
1667                                  PIPE_PRIM_TRIANGLE_FAN,
1668                                  4,  /* verts */
1669                                  2); /* attribs/vert */
1670
1671          /* need to signal that the texture has changed _after_ rendering to it */
1672          pipe_surface_reference( &surf, NULL );
1673       }
1674    }
1675
1676    /* restore state we changed */
1677    cso_restore_blend(ctx->cso);
1678    cso_restore_depth_stencil_alpha(ctx->cso);
1679    cso_restore_rasterizer(ctx->cso);
1680    cso_restore_samplers(ctx->cso);
1681    cso_restore_fragment_sampler_views(ctx->cso);
1682    cso_restore_framebuffer(ctx->cso);
1683    cso_restore_fragment_shader(ctx->cso);
1684    cso_restore_vertex_shader(ctx->cso);
1685    cso_restore_viewport(ctx->cso);
1686    cso_restore_clip(ctx->cso);
1687    cso_restore_vertex_elements(ctx->cso);
1688 }