u_gen_mipmap.c revision b2b905b04c09dd5e701a43b0fecb73921b8f2866
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_util.h"
41#include "pipe/p_winsys.h"
42#include "pipe/p_shader_tokens.h"
43
44#include "util/u_draw_quad.h"
45#include "util/u_gen_mipmap.h"
46
47#include "tgsi/util/tgsi_build.h"
48#include "tgsi/util/tgsi_dump.h"
49#include "tgsi/util/tgsi_parse.h"
50
51
52
53enum dtype
54{
55   UBYTE,
56   UBYTE_3_3_2,
57   USHORT,
58   USHORT_4_4_4_4,
59   USHORT_5_6_5,
60   USHORT_1_5_5_5_REV,
61   UINT,
62   FLOAT,
63   HALF_FLOAT
64};
65
66
67typedef ushort half_float;
68
69
70#if 0
71extern half_float
72float_to_half(float f);
73
74extern float
75half_to_float(half_float h);
76#endif
77
78
79/**
80 * Average together two rows of a source image to produce a single new
81 * row in the dest image.  It's legal for the two source rows to point
82 * to the same data.  The source width must be equal to either the
83 * dest width or two times the dest width.
84 * \param datatype  GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
85 * \param comps  number of components per pixel (1..4)
86 */
87static void
88do_row(enum dtype datatype, uint comps, int srcWidth,
89       const void *srcRowA, const void *srcRowB,
90       int dstWidth, void *dstRow)
91{
92   const uint k0 = (srcWidth == dstWidth) ? 0 : 1;
93   const uint colStride = (srcWidth == dstWidth) ? 1 : 2;
94
95   assert(comps >= 1);
96   assert(comps <= 4);
97
98   /* This assertion is no longer valid with non-power-of-2 textures
99   assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
100   */
101
102   if (datatype == UBYTE && comps == 4) {
103      uint i, j, k;
104      const ubyte(*rowA)[4] = (const ubyte(*)[4]) srcRowA;
105      const ubyte(*rowB)[4] = (const ubyte(*)[4]) srcRowB;
106      ubyte(*dst)[4] = (ubyte(*)[4]) dstRow;
107      for (i = j = 0, k = k0; i < (uint) dstWidth;
108           i++, j += colStride, k += colStride) {
109         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
110         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
111         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
112         dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
113      }
114   }
115   else if (datatype == UBYTE && comps == 3) {
116      uint i, j, k;
117      const ubyte(*rowA)[3] = (const ubyte(*)[3]) srcRowA;
118      const ubyte(*rowB)[3] = (const ubyte(*)[3]) srcRowB;
119      ubyte(*dst)[3] = (ubyte(*)[3]) dstRow;
120      for (i = j = 0, k = k0; i < (uint) dstWidth;
121           i++, j += colStride, k += colStride) {
122         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
123         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
124         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
125      }
126   }
127   else if (datatype == UBYTE && comps == 2) {
128      uint i, j, k;
129      const ubyte(*rowA)[2] = (const ubyte(*)[2]) srcRowA;
130      const ubyte(*rowB)[2] = (const ubyte(*)[2]) srcRowB;
131      ubyte(*dst)[2] = (ubyte(*)[2]) dstRow;
132      for (i = j = 0, k = k0; i < (uint) dstWidth;
133           i++, j += colStride, k += colStride) {
134         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) >> 2;
135         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) >> 2;
136      }
137   }
138   else if (datatype == UBYTE && comps == 1) {
139      uint i, j, k;
140      const ubyte *rowA = (const ubyte *) srcRowA;
141      const ubyte *rowB = (const ubyte *) srcRowB;
142      ubyte *dst = (ubyte *) dstRow;
143      for (i = j = 0, k = k0; i < (uint) dstWidth;
144           i++, j += colStride, k += colStride) {
145         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
146      }
147   }
148
149   else if (datatype == USHORT && comps == 4) {
150      uint i, j, k;
151      const ushort(*rowA)[4] = (const ushort(*)[4]) srcRowA;
152      const ushort(*rowB)[4] = (const ushort(*)[4]) srcRowB;
153      ushort(*dst)[4] = (ushort(*)[4]) dstRow;
154      for (i = j = 0, k = k0; i < (uint) dstWidth;
155           i++, j += colStride, k += colStride) {
156         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
157         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
158         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
159         dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
160      }
161   }
162   else if (datatype == USHORT && comps == 3) {
163      uint i, j, k;
164      const ushort(*rowA)[3] = (const ushort(*)[3]) srcRowA;
165      const ushort(*rowB)[3] = (const ushort(*)[3]) srcRowB;
166      ushort(*dst)[3] = (ushort(*)[3]) dstRow;
167      for (i = j = 0, k = k0; i < (uint) dstWidth;
168           i++, j += colStride, k += colStride) {
169         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
170         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
171         dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
172      }
173   }
174   else if (datatype == USHORT && comps == 2) {
175      uint i, j, k;
176      const ushort(*rowA)[2] = (const ushort(*)[2]) srcRowA;
177      const ushort(*rowB)[2] = (const ushort(*)[2]) srcRowB;
178      ushort(*dst)[2] = (ushort(*)[2]) dstRow;
179      for (i = j = 0, k = k0; i < (uint) dstWidth;
180           i++, j += colStride, k += colStride) {
181         dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
182         dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
183      }
184   }
185   else if (datatype == USHORT && comps == 1) {
186      uint i, j, k;
187      const ushort *rowA = (const ushort *) srcRowA;
188      const ushort *rowB = (const ushort *) srcRowB;
189      ushort *dst = (ushort *) dstRow;
190      for (i = j = 0, k = k0; i < (uint) dstWidth;
191           i++, j += colStride, k += colStride) {
192         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
193      }
194   }
195
196   else if (datatype == FLOAT && comps == 4) {
197      uint i, j, k;
198      const float(*rowA)[4] = (const float(*)[4]) srcRowA;
199      const float(*rowB)[4] = (const float(*)[4]) srcRowB;
200      float(*dst)[4] = (float(*)[4]) dstRow;
201      for (i = j = 0, k = k0; i < (uint) dstWidth;
202           i++, j += colStride, k += colStride) {
203         dst[i][0] = (rowA[j][0] + rowA[k][0] +
204                      rowB[j][0] + rowB[k][0]) * 0.25F;
205         dst[i][1] = (rowA[j][1] + rowA[k][1] +
206                      rowB[j][1] + rowB[k][1]) * 0.25F;
207         dst[i][2] = (rowA[j][2] + rowA[k][2] +
208                      rowB[j][2] + rowB[k][2]) * 0.25F;
209         dst[i][3] = (rowA[j][3] + rowA[k][3] +
210                      rowB[j][3] + rowB[k][3]) * 0.25F;
211      }
212   }
213   else if (datatype == FLOAT && comps == 3) {
214      uint i, j, k;
215      const float(*rowA)[3] = (const float(*)[3]) srcRowA;
216      const float(*rowB)[3] = (const float(*)[3]) srcRowB;
217      float(*dst)[3] = (float(*)[3]) dstRow;
218      for (i = j = 0, k = k0; i < (uint) dstWidth;
219           i++, j += colStride, k += colStride) {
220         dst[i][0] = (rowA[j][0] + rowA[k][0] +
221                      rowB[j][0] + rowB[k][0]) * 0.25F;
222         dst[i][1] = (rowA[j][1] + rowA[k][1] +
223                      rowB[j][1] + rowB[k][1]) * 0.25F;
224         dst[i][2] = (rowA[j][2] + rowA[k][2] +
225                      rowB[j][2] + rowB[k][2]) * 0.25F;
226      }
227   }
228   else if (datatype == FLOAT && comps == 2) {
229      uint i, j, k;
230      const float(*rowA)[2] = (const float(*)[2]) srcRowA;
231      const float(*rowB)[2] = (const float(*)[2]) srcRowB;
232      float(*dst)[2] = (float(*)[2]) 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] +
236                      rowB[j][0] + rowB[k][0]) * 0.25F;
237         dst[i][1] = (rowA[j][1] + rowA[k][1] +
238                      rowB[j][1] + rowB[k][1]) * 0.25F;
239      }
240   }
241   else if (datatype == FLOAT && comps == 1) {
242      uint i, j, k;
243      const float *rowA = (const float *) srcRowA;
244      const float *rowB = (const float *) srcRowB;
245      float *dst = (float *) dstRow;
246      for (i = j = 0, k = k0; i < (uint) dstWidth;
247           i++, j += colStride, k += colStride) {
248         dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
249      }
250   }
251
252#if 0
253   else if (datatype == HALF_FLOAT && comps == 4) {
254      uint i, j, k, comp;
255      const half_float(*rowA)[4] = (const half_float(*)[4]) srcRowA;
256      const half_float(*rowB)[4] = (const half_float(*)[4]) srcRowB;
257      half_float(*dst)[4] = (half_float(*)[4]) dstRow;
258      for (i = j = 0, k = k0; i < (uint) dstWidth;
259           i++, j += colStride, k += colStride) {
260         for (comp = 0; comp < 4; comp++) {
261            float aj, ak, bj, bk;
262            aj = half_to_float(rowA[j][comp]);
263            ak = half_to_float(rowA[k][comp]);
264            bj = half_to_float(rowB[j][comp]);
265            bk = half_to_float(rowB[k][comp]);
266            dst[i][comp] = float_to_half((aj + ak + bj + bk) * 0.25F);
267         }
268      }
269   }
270   else if (datatype == HALF_FLOAT && comps == 3) {
271      uint i, j, k, comp;
272      const half_float(*rowA)[3] = (const half_float(*)[3]) srcRowA;
273      const half_float(*rowB)[3] = (const half_float(*)[3]) srcRowB;
274      half_float(*dst)[3] = (half_float(*)[3]) dstRow;
275      for (i = j = 0, k = k0; i < (uint) dstWidth;
276           i++, j += colStride, k += colStride) {
277         for (comp = 0; comp < 3; comp++) {
278            float aj, ak, bj, bk;
279            aj = half_to_float(rowA[j][comp]);
280            ak = half_to_float(rowA[k][comp]);
281            bj = half_to_float(rowB[j][comp]);
282            bk = half_to_float(rowB[k][comp]);
283            dst[i][comp] = float_to_half((aj + ak + bj + bk) * 0.25F);
284         }
285      }
286   }
287   else if (datatype == HALF_FLOAT && comps == 2) {
288      uint i, j, k, comp;
289      const half_float(*rowA)[2] = (const half_float(*)[2]) srcRowA;
290      const half_float(*rowB)[2] = (const half_float(*)[2]) srcRowB;
291      half_float(*dst)[2] = (half_float(*)[2]) dstRow;
292      for (i = j = 0, k = k0; i < (uint) dstWidth;
293           i++, j += colStride, k += colStride) {
294         for (comp = 0; comp < 2; comp++) {
295            float aj, ak, bj, bk;
296            aj = half_to_float(rowA[j][comp]);
297            ak = half_to_float(rowA[k][comp]);
298            bj = half_to_float(rowB[j][comp]);
299            bk = half_to_float(rowB[k][comp]);
300            dst[i][comp] = float_to_half((aj + ak + bj + bk) * 0.25F);
301         }
302      }
303   }
304   else if (datatype == HALF_FLOAT && comps == 1) {
305      uint i, j, k;
306      const half_float *rowA = (const half_float *) srcRowA;
307      const half_float *rowB = (const half_float *) srcRowB;
308      half_float *dst = (half_float *) dstRow;
309      for (i = j = 0, k = k0; i < (uint) dstWidth;
310           i++, j += colStride, k += colStride) {
311         float aj, ak, bj, bk;
312         aj = half_to_float(rowA[j]);
313         ak = half_to_float(rowA[k]);
314         bj = half_to_float(rowB[j]);
315         bk = half_to_float(rowB[k]);
316         dst[i] = float_to_half((aj + ak + bj + bk) * 0.25F);
317      }
318   }
319#endif
320
321   else if (datatype == UINT && comps == 1) {
322      uint i, j, k;
323      const uint *rowA = (const uint *) srcRowA;
324      const uint *rowB = (const uint *) srcRowB;
325      float *dst = (float *) dstRow;
326      for (i = j = 0, k = k0; i < (uint) dstWidth;
327           i++, j += colStride, k += colStride) {
328         dst[i] = (float) rowA[j] / 4 + (float) rowA[k] / 4 + (float) rowB[j] / 4 + (float) rowB[k] / 4;
329      }
330   }
331
332   else if (datatype == USHORT_5_6_5 && comps == 3) {
333      uint i, j, k;
334      const ushort *rowA = (const ushort *) srcRowA;
335      const ushort *rowB = (const ushort *) srcRowB;
336      ushort *dst = (ushort *) dstRow;
337      for (i = j = 0, k = k0; i < (uint) dstWidth;
338           i++, j += colStride, k += colStride) {
339         const int rowAr0 = rowA[j] & 0x1f;
340         const int rowAr1 = rowA[k] & 0x1f;
341         const int rowBr0 = rowB[j] & 0x1f;
342         const int rowBr1 = rowB[k] & 0x1f;
343         const int rowAg0 = (rowA[j] >> 5) & 0x3f;
344         const int rowAg1 = (rowA[k] >> 5) & 0x3f;
345         const int rowBg0 = (rowB[j] >> 5) & 0x3f;
346         const int rowBg1 = (rowB[k] >> 5) & 0x3f;
347         const int rowAb0 = (rowA[j] >> 11) & 0x1f;
348         const int rowAb1 = (rowA[k] >> 11) & 0x1f;
349         const int rowBb0 = (rowB[j] >> 11) & 0x1f;
350         const int rowBb1 = (rowB[k] >> 11) & 0x1f;
351         const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
352         const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
353         const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
354         dst[i] = (blue << 11) | (green << 5) | red;
355      }
356   }
357   else if (datatype == USHORT_4_4_4_4 && comps == 4) {
358      uint i, j, k;
359      const ushort *rowA = (const ushort *) srcRowA;
360      const ushort *rowB = (const ushort *) srcRowB;
361      ushort *dst = (ushort *) dstRow;
362      for (i = j = 0, k = k0; i < (uint) dstWidth;
363           i++, j += colStride, k += colStride) {
364         const int rowAr0 = rowA[j] & 0xf;
365         const int rowAr1 = rowA[k] & 0xf;
366         const int rowBr0 = rowB[j] & 0xf;
367         const int rowBr1 = rowB[k] & 0xf;
368         const int rowAg0 = (rowA[j] >> 4) & 0xf;
369         const int rowAg1 = (rowA[k] >> 4) & 0xf;
370         const int rowBg0 = (rowB[j] >> 4) & 0xf;
371         const int rowBg1 = (rowB[k] >> 4) & 0xf;
372         const int rowAb0 = (rowA[j] >> 8) & 0xf;
373         const int rowAb1 = (rowA[k] >> 8) & 0xf;
374         const int rowBb0 = (rowB[j] >> 8) & 0xf;
375         const int rowBb1 = (rowB[k] >> 8) & 0xf;
376         const int rowAa0 = (rowA[j] >> 12) & 0xf;
377         const int rowAa1 = (rowA[k] >> 12) & 0xf;
378         const int rowBa0 = (rowB[j] >> 12) & 0xf;
379         const int rowBa1 = (rowB[k] >> 12) & 0xf;
380         const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
381         const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
382         const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
383         const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
384         dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
385      }
386   }
387   else if (datatype == USHORT_1_5_5_5_REV && comps == 4) {
388      uint i, j, k;
389      const ushort *rowA = (const ushort *) srcRowA;
390      const ushort *rowB = (const ushort *) srcRowB;
391      ushort *dst = (ushort *) dstRow;
392      for (i = j = 0, k = k0; i < (uint) dstWidth;
393           i++, j += colStride, k += colStride) {
394         const int rowAr0 = rowA[j] & 0x1f;
395         const int rowAr1 = rowA[k] & 0x1f;
396         const int rowBr0 = rowB[j] & 0x1f;
397         const int rowBr1 = rowB[k] & 0xf;
398         const int rowAg0 = (rowA[j] >> 5) & 0x1f;
399         const int rowAg1 = (rowA[k] >> 5) & 0x1f;
400         const int rowBg0 = (rowB[j] >> 5) & 0x1f;
401         const int rowBg1 = (rowB[k] >> 5) & 0x1f;
402         const int rowAb0 = (rowA[j] >> 10) & 0x1f;
403         const int rowAb1 = (rowA[k] >> 10) & 0x1f;
404         const int rowBb0 = (rowB[j] >> 10) & 0x1f;
405         const int rowBb1 = (rowB[k] >> 10) & 0x1f;
406         const int rowAa0 = (rowA[j] >> 15) & 0x1;
407         const int rowAa1 = (rowA[k] >> 15) & 0x1;
408         const int rowBa0 = (rowB[j] >> 15) & 0x1;
409         const int rowBa1 = (rowB[k] >> 15) & 0x1;
410         const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
411         const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
412         const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
413         const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
414         dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
415      }
416   }
417   else if (datatype == UBYTE_3_3_2 && comps == 3) {
418      uint i, j, k;
419      const ubyte *rowA = (const ubyte *) srcRowA;
420      const ubyte *rowB = (const ubyte *) srcRowB;
421      ubyte *dst = (ubyte *) dstRow;
422      for (i = j = 0, k = k0; i < (uint) dstWidth;
423           i++, j += colStride, k += colStride) {
424         const int rowAr0 = rowA[j] & 0x3;
425         const int rowAr1 = rowA[k] & 0x3;
426         const int rowBr0 = rowB[j] & 0x3;
427         const int rowBr1 = rowB[k] & 0x3;
428         const int rowAg0 = (rowA[j] >> 2) & 0x7;
429         const int rowAg1 = (rowA[k] >> 2) & 0x7;
430         const int rowBg0 = (rowB[j] >> 2) & 0x7;
431         const int rowBg1 = (rowB[k] >> 2) & 0x7;
432         const int rowAb0 = (rowA[j] >> 5) & 0x7;
433         const int rowAb1 = (rowA[k] >> 5) & 0x7;
434         const int rowBb0 = (rowB[j] >> 5) & 0x7;
435         const int rowBb1 = (rowB[k] >> 5) & 0x7;
436         const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
437         const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
438         const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
439         dst[i] = (blue << 5) | (green << 2) | red;
440      }
441   }
442   else {
443      debug_printf("bad format in do_row()");
444   }
445}
446
447
448static void
449format_to_type_comps(enum pipe_format pformat,
450                     enum dtype *datatype, uint *comps)
451{
452   switch (pformat) {
453   case PIPE_FORMAT_A8R8G8B8_UNORM:
454   case PIPE_FORMAT_B8G8R8A8_UNORM:
455      *datatype = UBYTE;
456      *comps = 4;
457      return;
458   case PIPE_FORMAT_A1R5G5B5_UNORM:
459      *datatype = USHORT_1_5_5_5_REV;
460      *comps = 4;
461      return;
462   case PIPE_FORMAT_A4R4G4B4_UNORM:
463      *datatype = USHORT_4_4_4_4;
464      *comps = 4;
465      return;
466   case PIPE_FORMAT_R5G6B5_UNORM:
467      *datatype = USHORT_5_6_5;
468      *comps = 3;
469      return;
470   case PIPE_FORMAT_U_L8:
471   case PIPE_FORMAT_U_A8:
472   case PIPE_FORMAT_U_I8:
473      *datatype = UBYTE;
474      *comps = 1;
475      return;
476   case PIPE_FORMAT_U_A8_L8:
477      *datatype = UBYTE;
478      *comps = 2;
479      return;
480   default:
481      assert(0);
482   }
483}
484
485
486static void
487reduce_1d(enum pipe_format pformat,
488          int srcWidth, const ubyte *srcPtr,
489          int dstWidth, ubyte *dstPtr)
490{
491   enum dtype datatype;
492   uint comps;
493
494   format_to_type_comps(pformat, &datatype, &comps);
495
496   /* we just duplicate the input row, kind of hack, saves code */
497   do_row(datatype, comps,
498          srcWidth, srcPtr, srcPtr,
499          dstWidth, dstPtr);
500}
501
502
503/**
504 * Strides are in bytes.  If zero, it'll be computed as width * bpp.
505 */
506static void
507reduce_2d(enum pipe_format pformat,
508          int srcWidth, int srcHeight,
509          int srcRowStride, const ubyte *srcPtr,
510          int dstWidth, int dstHeight,
511          int dstRowStride, ubyte *dstPtr)
512{
513   enum dtype datatype;
514   uint comps;
515   const int bpt = pf_get_size(pformat);
516   const ubyte *srcA, *srcB;
517   ubyte *dst;
518   int row;
519
520   format_to_type_comps(pformat, &datatype, &comps);
521
522   if (!srcRowStride)
523      srcRowStride = bpt * srcWidth;
524
525   if (!dstRowStride)
526      dstRowStride = bpt * dstWidth;
527
528   /* Compute src and dst pointers */
529   srcA = srcPtr;
530   if (srcHeight > 1)
531      srcB = srcA + srcRowStride;
532   else
533      srcB = srcA;
534   dst = dstPtr;
535
536   for (row = 0; row < dstHeight; row++) {
537      do_row(datatype, comps,
538             srcWidth, srcA, srcB,
539             dstWidth, dst);
540      srcA += 2 * srcRowStride;
541      srcB += 2 * srcRowStride;
542      dst += dstRowStride;
543   }
544}
545
546
547static void
548make_1d_mipmap(struct gen_mipmap_state *ctx,
549               struct pipe_texture *pt,
550               uint face, uint baseLevel, uint lastLevel)
551{
552   struct pipe_context *pipe = ctx->pipe;
553   struct pipe_screen *screen = pipe->screen;
554   struct pipe_winsys *winsys = pipe->winsys;
555   const uint zslice = 0;
556   uint dstLevel;
557
558   for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
559      const uint srcLevel = dstLevel - 1;
560      struct pipe_surface *srcSurf, *dstSurf;
561      void *srcMap, *dstMap;
562
563      srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice);
564      dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice);
565
566      srcMap = ((ubyte *) winsys->buffer_map(winsys, srcSurf->buffer,
567                                            PIPE_BUFFER_USAGE_CPU_READ)
568                + srcSurf->offset);
569      dstMap = ((ubyte *) winsys->buffer_map(winsys, dstSurf->buffer,
570                                            PIPE_BUFFER_USAGE_CPU_WRITE)
571                + dstSurf->offset);
572
573      reduce_1d(pt->format,
574                srcSurf->width, srcMap,
575                dstSurf->width, dstMap);
576
577      winsys->buffer_unmap(winsys, srcSurf->buffer);
578      winsys->buffer_unmap(winsys, dstSurf->buffer);
579
580      pipe_surface_reference(&srcSurf, NULL);
581      pipe_surface_reference(&dstSurf, NULL);
582   }
583}
584
585
586static void
587make_2d_mipmap(struct gen_mipmap_state *ctx,
588               struct pipe_texture *pt,
589               uint face, uint baseLevel, uint lastLevel)
590{
591   struct pipe_context *pipe = ctx->pipe;
592   struct pipe_screen *screen = pipe->screen;
593   struct pipe_winsys *winsys = pipe->winsys;
594   const uint zslice = 0;
595   uint dstLevel;
596   const int bpt = pf_get_size(pt->format);
597
598   for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
599      const uint srcLevel = dstLevel - 1;
600      struct pipe_surface *srcSurf, *dstSurf;
601      ubyte *srcMap, *dstMap;
602
603      srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice);
604      dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice);
605
606      srcMap = ((ubyte *) winsys->buffer_map(winsys, srcSurf->buffer,
607                                            PIPE_BUFFER_USAGE_CPU_READ)
608                + srcSurf->offset);
609      dstMap = ((ubyte *) winsys->buffer_map(winsys, dstSurf->buffer,
610                                            PIPE_BUFFER_USAGE_CPU_WRITE)
611                + dstSurf->offset);
612
613      reduce_2d(pt->format,
614                srcSurf->width, srcSurf->height,
615                srcSurf->pitch * bpt, srcMap,
616                dstSurf->width, dstSurf->height,
617                dstSurf->pitch * bpt, dstMap);
618
619      winsys->buffer_unmap(winsys, srcSurf->buffer);
620      winsys->buffer_unmap(winsys, dstSurf->buffer);
621
622      pipe_surface_reference(&srcSurf, NULL);
623      pipe_surface_reference(&dstSurf, NULL);
624   }
625}
626
627
628static void
629make_3d_mipmap(struct gen_mipmap_state *ctx,
630               struct pipe_texture *pt,
631               uint face, uint baseLevel, uint lastLevel)
632{
633}
634
635
636static void
637fallback_gen_mipmap(struct gen_mipmap_state *ctx,
638                    struct pipe_texture *pt,
639                    uint face, uint baseLevel, uint lastLevel)
640{
641   switch (pt->target) {
642   case PIPE_TEXTURE_1D:
643      make_1d_mipmap(ctx, pt, face, baseLevel, lastLevel);
644      break;
645   case PIPE_TEXTURE_2D:
646   case PIPE_TEXTURE_CUBE:
647      make_2d_mipmap(ctx, pt, face, baseLevel, lastLevel);
648      break;
649   case PIPE_TEXTURE_3D:
650      make_3d_mipmap(ctx, pt, face, baseLevel, lastLevel);
651      break;
652   default:
653      assert(0);
654   }
655}
656
657
658/**
659 * Make simple fragment shader:
660 *  TEX OUT[0], IN[0], SAMP[0], 2D;
661 *  END;
662 */
663static void
664make_fragment_shader(struct gen_mipmap_state *ctx)
665{
666   struct pipe_context *pipe = ctx->pipe;
667   uint maxTokens = 100;
668   struct tgsi_token *tokens;
669   struct tgsi_header *header;
670   struct tgsi_processor *processor;
671   struct tgsi_full_declaration decl;
672   struct tgsi_full_instruction inst;
673   const uint procType = TGSI_PROCESSOR_FRAGMENT;
674   uint ti = 0;
675   struct pipe_shader_state shader;
676
677   tokens = (struct tgsi_token *) malloc(maxTokens * sizeof(tokens[0]));
678
679   /* shader header
680    */
681   *(struct tgsi_version *) &tokens[0] = tgsi_build_version();
682
683   header = (struct tgsi_header *) &tokens[1];
684   *header = tgsi_build_header();
685
686   processor = (struct tgsi_processor *) &tokens[2];
687   *processor = tgsi_build_processor( procType, header );
688
689   ti = 3;
690
691   /* declare TEX[0] input */
692   decl = tgsi_default_full_declaration();
693   decl.Declaration.File = TGSI_FILE_INPUT;
694   decl.Declaration.Semantic = 1;
695   decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC;
696   decl.Semantic.SemanticIndex = 0;
697   /* XXX this could be linear... */
698   decl.Declaration.Interpolate = 1;
699   decl.Interpolation.Interpolate = TGSI_INTERPOLATE_PERSPECTIVE;
700   decl.u.DeclarationRange.First =
701   decl.u.DeclarationRange.Last = 0;
702   ti += tgsi_build_full_declaration(&decl,
703                                     &tokens[ti],
704                                     header,
705                                     maxTokens - ti);
706
707   /* declare color[0] output */
708   decl = tgsi_default_full_declaration();
709   decl.Declaration.File = TGSI_FILE_OUTPUT;
710   decl.Declaration.Semantic = 1;
711   decl.Semantic.SemanticName = TGSI_SEMANTIC_COLOR;
712   decl.Semantic.SemanticIndex = 0;
713   decl.u.DeclarationRange.First =
714   decl.u.DeclarationRange.Last = 0;
715   ti += tgsi_build_full_declaration(&decl,
716                                     &tokens[ti],
717                                     header,
718                                     maxTokens - ti);
719
720   /* declare sampler */
721   decl = tgsi_default_full_declaration();
722   decl.Declaration.File = TGSI_FILE_SAMPLER;
723   decl.u.DeclarationRange.First =
724   decl.u.DeclarationRange.Last = 0;
725   ti += tgsi_build_full_declaration(&decl,
726                                     &tokens[ti],
727                                     header,
728                                     maxTokens - ti);
729
730   /* TEX instruction */
731   inst = tgsi_default_full_instruction();
732   inst.Instruction.Opcode = TGSI_OPCODE_TEX;
733   inst.Instruction.NumDstRegs = 1;
734   inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT;
735   inst.FullDstRegisters[0].DstRegister.Index = 0;
736   inst.Instruction.NumSrcRegs = 2;
737   inst.InstructionExtTexture.Texture = TGSI_TEXTURE_2D;
738   inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT;
739   inst.FullSrcRegisters[0].SrcRegister.Index = 0;
740   inst.FullSrcRegisters[1].SrcRegister.File = TGSI_FILE_SAMPLER;
741   inst.FullSrcRegisters[1].SrcRegister.Index = 0;
742   ti += tgsi_build_full_instruction(&inst,
743                                     &tokens[ti],
744                                     header,
745                                     maxTokens - ti );
746
747   /* END instruction */
748   inst = tgsi_default_full_instruction();
749   inst.Instruction.Opcode = TGSI_OPCODE_END;
750   inst.Instruction.NumDstRegs = 0;
751   inst.Instruction.NumSrcRegs = 0;
752   ti += tgsi_build_full_instruction(&inst,
753                                     &tokens[ti],
754                                     header,
755                                     maxTokens - ti );
756
757#if 0 /*debug*/
758   tgsi_dump(tokens, 0);
759#endif
760
761   shader.tokens = tokens;
762   ctx->fs = pipe->create_fs_state(pipe, &shader);
763}
764
765
766/**
767 * Make simple fragment shader:
768 *  MOV OUT[0], IN[0];
769 *  MOV OUT[1], IN[1];
770 *  END;
771 *
772 * XXX eliminate this when vertex passthrough-mode is more solid.
773 */
774static void
775make_vertex_shader(struct gen_mipmap_state *ctx)
776{
777   struct pipe_context *pipe = ctx->pipe;
778   uint maxTokens = 100;
779   struct tgsi_token *tokens;
780   struct tgsi_header *header;
781   struct tgsi_processor *processor;
782   struct tgsi_full_declaration decl;
783   struct tgsi_full_instruction inst;
784   const uint procType = TGSI_PROCESSOR_VERTEX;
785   uint ti = 0;
786   struct pipe_shader_state shader;
787
788   tokens = (struct tgsi_token *) malloc(maxTokens * sizeof(tokens[0]));
789
790   /* shader header
791    */
792   *(struct tgsi_version *) &tokens[0] = tgsi_build_version();
793
794   header = (struct tgsi_header *) &tokens[1];
795   *header = tgsi_build_header();
796
797   processor = (struct tgsi_processor *) &tokens[2];
798   *processor = tgsi_build_processor( procType, header );
799
800   ti = 3;
801
802   /* declare POS input */
803   decl = tgsi_default_full_declaration();
804   decl.Declaration.File = TGSI_FILE_INPUT;
805   /*
806   decl.Declaration.Semantic = 1;
807   decl.Semantic.SemanticName = TGSI_SEMANTIC_POSITION;
808   decl.Semantic.SemanticIndex = 0;
809   */
810   decl.u.DeclarationRange.First =
811   decl.u.DeclarationRange.Last = 0;
812   ti += tgsi_build_full_declaration(&decl,
813                                     &tokens[ti],
814                                     header,
815                                     maxTokens - ti);
816   /* declare TEX[0] input */
817   decl = tgsi_default_full_declaration();
818   decl.Declaration.File = TGSI_FILE_INPUT;
819   /*
820   decl.Declaration.Semantic = 1;
821   decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC;
822   decl.Semantic.SemanticIndex = 0;
823   */
824   decl.u.DeclarationRange.First =
825   decl.u.DeclarationRange.Last = 1;
826   ti += tgsi_build_full_declaration(&decl,
827                                     &tokens[ti],
828                                     header,
829                                     maxTokens - ti);
830
831   /* declare POS output */
832   decl = tgsi_default_full_declaration();
833   decl.Declaration.File = TGSI_FILE_OUTPUT;
834   decl.Declaration.Semantic = 1;
835   decl.Semantic.SemanticName = TGSI_SEMANTIC_POSITION;
836   decl.Semantic.SemanticIndex = 0;
837   decl.u.DeclarationRange.First =
838   decl.u.DeclarationRange.Last = 0;
839   ti += tgsi_build_full_declaration(&decl,
840                                     &tokens[ti],
841                                     header,
842                                     maxTokens - ti);
843
844   /* declare TEX[0] output */
845   decl = tgsi_default_full_declaration();
846   decl.Declaration.File = TGSI_FILE_OUTPUT;
847   decl.Declaration.Semantic = 1;
848   decl.Semantic.SemanticName = TGSI_SEMANTIC_GENERIC;
849   decl.Semantic.SemanticIndex = 0;
850   decl.u.DeclarationRange.First =
851   decl.u.DeclarationRange.Last = 1;
852   ti += tgsi_build_full_declaration(&decl,
853                                     &tokens[ti],
854                                     header,
855                                     maxTokens - ti);
856
857   /* MOVE out[0], in[0];  # POS */
858   inst = tgsi_default_full_instruction();
859   inst.Instruction.Opcode = TGSI_OPCODE_MOV;
860   inst.Instruction.NumDstRegs = 1;
861   inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT;
862   inst.FullDstRegisters[0].DstRegister.Index = 0;
863   inst.Instruction.NumSrcRegs = 1;
864   inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT;
865   inst.FullSrcRegisters[0].SrcRegister.Index = 0;
866   ti += tgsi_build_full_instruction(&inst,
867                                     &tokens[ti],
868                                     header,
869                                     maxTokens - ti );
870
871   /* MOVE out[1], in[1];  # TEX */
872   inst = tgsi_default_full_instruction();
873   inst.Instruction.Opcode = TGSI_OPCODE_MOV;
874   inst.Instruction.NumDstRegs = 1;
875   inst.FullDstRegisters[0].DstRegister.File = TGSI_FILE_OUTPUT;
876   inst.FullDstRegisters[0].DstRegister.Index = 1;
877   inst.Instruction.NumSrcRegs = 1;
878   inst.FullSrcRegisters[0].SrcRegister.File = TGSI_FILE_INPUT;
879   inst.FullSrcRegisters[0].SrcRegister.Index = 1;
880   ti += tgsi_build_full_instruction(&inst,
881                                     &tokens[ti],
882                                     header,
883                                     maxTokens - ti );
884
885   /* END instruction */
886   inst = tgsi_default_full_instruction();
887   inst.Instruction.Opcode = TGSI_OPCODE_END;
888   inst.Instruction.NumDstRegs = 0;
889   inst.Instruction.NumSrcRegs = 0;
890   ti += tgsi_build_full_instruction(&inst,
891                                     &tokens[ti],
892                                     header,
893                                     maxTokens - ti );
894
895#if 0 /*debug*/
896   tgsi_dump(tokens, 0);
897#endif
898
899   shader.tokens = tokens;
900   ctx->vs = pipe->create_vs_state(pipe, &shader);
901}
902
903
904/**
905 * Create a mipmap generation context.
906 * The idea is to create one of these and re-use it each time we need to
907 * generate a mipmap.
908 */
909struct gen_mipmap_state *
910util_create_gen_mipmap(struct pipe_context *pipe)
911{
912   struct pipe_blend_state blend;
913   struct pipe_depth_stencil_alpha_state depthstencil;
914   struct pipe_rasterizer_state rasterizer;
915   struct gen_mipmap_state *ctx;
916
917   ctx = CALLOC_STRUCT(gen_mipmap_state);
918   if (!ctx)
919      return NULL;
920
921   ctx->pipe = pipe;
922
923   /* we don't use blending, but need to set valid values */
924   memset(&blend, 0, sizeof(blend));
925   blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE;
926   blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE;
927   blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
928   blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
929   blend.colormask = PIPE_MASK_RGBA;
930   ctx->blend = pipe->create_blend_state(pipe, &blend);
931
932   /* depth/stencil/alpha */
933   memset(&depthstencil, 0, sizeof(depthstencil));
934   ctx->depthstencil = pipe->create_depth_stencil_alpha_state(pipe, &depthstencil);
935
936   /* rasterizer */
937   memset(&rasterizer, 0, sizeof(rasterizer));
938   rasterizer.front_winding = PIPE_WINDING_CW;
939   rasterizer.cull_mode = PIPE_WINDING_NONE;
940   rasterizer.bypass_clipping = 1;  /* bypasses viewport too */
941   //rasterizer.bypass_vs = 1;
942   ctx->rasterizer = pipe->create_rasterizer_state(pipe, &rasterizer);
943
944#if 0
945   /* viewport */
946   ctx->viewport.scale[0] = 1.0;
947   ctx->viewport.scale[1] = 1.0;
948   ctx->viewport.scale[2] = 1.0;
949   ctx->viewport.scale[3] = 1.0;
950   ctx->viewport.translate[0] = 0.0;
951   ctx->viewport.translate[1] = 0.0;
952   ctx->viewport.translate[2] = 0.0;
953   ctx->viewport.translate[3] = 0.0;
954#endif
955
956   make_vertex_shader(ctx);
957   make_fragment_shader(ctx);
958
959   return ctx;
960}
961
962
963/**
964 * Destroy a mipmap generation context
965 */
966void
967util_destroy_gen_mipmap(struct gen_mipmap_state *ctx)
968{
969   struct pipe_context *pipe = ctx->pipe;
970
971   pipe->delete_blend_state(pipe, ctx->blend);
972   pipe->delete_depth_stencil_alpha_state(pipe, ctx->depthstencil);
973   pipe->delete_rasterizer_state(pipe, ctx->rasterizer);
974   pipe->delete_vs_state(pipe, ctx->vs);
975   pipe->delete_fs_state(pipe, ctx->fs);
976
977   FREE(ctx);
978}
979
980
981#if 0
982static void
983simple_viewport(struct pipe_context *pipe, uint width, uint height)
984{
985   struct pipe_viewport_state vp;
986
987   vp.scale[0] =  0.5 * width;
988   vp.scale[1] = -0.5 * height;
989   vp.scale[2] = 1.0;
990   vp.scale[3] = 1.0;
991   vp.translate[0] = 0.5 * width;
992   vp.translate[1] = 0.5 * height;
993   vp.translate[2] = 0.0;
994   vp.translate[3] = 0.0;
995
996   pipe->set_viewport_state(pipe, &vp);
997}
998#endif
999
1000
1001/**
1002 * Generate mipmap images.  It's assumed all needed texture memory is
1003 * already allocated.
1004 *
1005 * \param pt  the texture to generate mipmap levels for
1006 * \param face  which cube face to generate mipmaps for (0 for non-cube maps)
1007 * \param baseLevel  the first mipmap level to use as a src
1008 * \param lastLevel  the last mipmap level to generate
1009 */
1010void
1011util_gen_mipmap(struct gen_mipmap_state *ctx,
1012                struct pipe_texture *pt,
1013                uint face, uint baseLevel, uint lastLevel)
1014{
1015   struct pipe_context *pipe = ctx->pipe;
1016   struct pipe_screen *screen = pipe->screen;
1017   struct pipe_framebuffer_state fb;
1018   struct pipe_sampler_state sampler;
1019   void *sampler_cso;
1020   uint dstLevel;
1021   uint zslice = 0;
1022
1023   /* check if we can render in the texture's format */
1024   if (!screen->is_format_supported(screen, pt->format, PIPE_SURFACE)) {
1025      fallback_gen_mipmap(ctx, pt, face, baseLevel, lastLevel);
1026      return;
1027   }
1028
1029   /* init framebuffer state */
1030   memset(&fb, 0, sizeof(fb));
1031   fb.num_cbufs = 1;
1032
1033   /* sampler state */
1034   memset(&sampler, 0, sizeof(sampler));
1035   sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1036   sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1037   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
1038   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
1039   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
1040   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
1041   sampler.normalized_coords = 1;
1042
1043   /* bind our state */
1044   pipe->bind_blend_state(pipe, ctx->blend);
1045   pipe->bind_depth_stencil_alpha_state(pipe, ctx->depthstencil);
1046   pipe->bind_rasterizer_state(pipe, ctx->rasterizer);
1047   pipe->bind_vs_state(pipe, ctx->vs);
1048   pipe->bind_fs_state(pipe, ctx->fs);
1049#if 0
1050   pipe->set_viewport_state(pipe, &ctx->viewport);
1051#endif
1052
1053   /*
1054    * XXX for small mipmap levels, it may be faster to use the software
1055    * fallback path...
1056    */
1057   for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
1058      const uint srcLevel = dstLevel - 1;
1059
1060      /*
1061       * Setup framebuffer / dest surface
1062       */
1063      fb.cbufs[0] = screen->get_tex_surface(screen, pt, face, dstLevel, zslice);
1064      pipe->set_framebuffer_state(pipe, &fb);
1065
1066      /*
1067       * Setup sampler state
1068       * Note: we should only have to set the min/max LOD clamps to ensure
1069       * we grab texels from the right mipmap level.  But some hardware
1070       * has trouble with min clamping so we also set the lod_bias to
1071       * try to work around that.
1072       */
1073      sampler.min_lod = sampler.max_lod = (float) srcLevel;
1074      sampler.lod_bias = (float) srcLevel;
1075      sampler_cso = pipe->create_sampler_state(pipe, &sampler);
1076      pipe->bind_sampler_states(pipe, 1, &sampler_cso);
1077
1078#if 0
1079      simple_viewport(pipe, pt->width[dstLevel], pt->height[dstLevel]);
1080#endif
1081
1082      pipe->set_sampler_textures(pipe, 1, &pt);
1083
1084      /* quad coords in window coords (bypassing clipping, viewport mapping) */
1085      util_draw_texquad(pipe,
1086                        0.0F, 0.0F, /* x0, y0 */
1087                        (float) pt->width[dstLevel], /* x1 */
1088                        (float) pt->height[dstLevel], /* y1 */
1089                        0.0F);  /* z */
1090
1091
1092      pipe->flush(pipe, PIPE_FLUSH_WAIT);
1093
1094      /*pipe->texture_update(pipe, pt);  not really needed */
1095
1096      pipe->delete_sampler_state(pipe, sampler_cso);
1097   }
1098
1099   /* Note: caller must restore pipe/gallium state at this time */
1100}
1101