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