u_gen_mipmap.c revision bf8de6d4dc1f956b7e70be285ff0d983b1a8eb5b
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#include "util/u_simple_shaders.h" 47 48#include "tgsi/util/tgsi_build.h" 49#include "tgsi/util/tgsi_dump.h" 50#include "tgsi/util/tgsi_parse.h" 51 52#include "cso_cache/cso_context.h" 53 54 55struct gen_mipmap_state 56{ 57 struct pipe_context *pipe; 58 struct cso_context *cso; 59 60 struct pipe_blend_state blend; 61 struct pipe_depth_stencil_alpha_state depthstencil; 62 struct pipe_rasterizer_state rasterizer; 63 struct pipe_sampler_state sampler; 64 /*struct pipe_viewport_state viewport;*/ 65 struct pipe_sampler_state *vs; 66 struct pipe_sampler_state *fs; 67 68 struct pipe_buffer *vbuf; /**< quad vertices */ 69 float vertices[4][2][4]; /**< vertex/texcoords for quad */ 70}; 71 72 73 74enum dtype 75{ 76 UBYTE, 77 UBYTE_3_3_2, 78 USHORT, 79 USHORT_4_4_4_4, 80 USHORT_5_6_5, 81 USHORT_1_5_5_5_REV, 82 UINT, 83 FLOAT, 84 HALF_FLOAT 85}; 86 87 88typedef ushort half_float; 89 90 91#if 0 92extern half_float 93float_to_half(float f); 94 95extern float 96half_to_float(half_float h); 97#endif 98 99 100/** 101 * Average together two rows of a source image to produce a single new 102 * row in the dest image. It's legal for the two source rows to point 103 * to the same data. The source width must be equal to either the 104 * dest width or two times the dest width. 105 * \param datatype GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc. 106 * \param comps number of components per pixel (1..4) 107 */ 108static void 109do_row(enum dtype datatype, uint comps, int srcWidth, 110 const void *srcRowA, const void *srcRowB, 111 int dstWidth, void *dstRow) 112{ 113 const uint k0 = (srcWidth == dstWidth) ? 0 : 1; 114 const uint colStride = (srcWidth == dstWidth) ? 1 : 2; 115 116 assert(comps >= 1); 117 assert(comps <= 4); 118 119 /* This assertion is no longer valid with non-power-of-2 textures 120 assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth); 121 */ 122 123 if (datatype == UBYTE && comps == 4) { 124 uint i, j, k; 125 const ubyte(*rowA)[4] = (const ubyte(*)[4]) srcRowA; 126 const ubyte(*rowB)[4] = (const ubyte(*)[4]) srcRowB; 127 ubyte(*dst)[4] = (ubyte(*)[4]) dstRow; 128 for (i = j = 0, k = k0; i < (uint) dstWidth; 129 i++, j += colStride, k += colStride) { 130 dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; 131 dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; 132 dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; 133 dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4; 134 } 135 } 136 else if (datatype == UBYTE && comps == 3) { 137 uint i, j, k; 138 const ubyte(*rowA)[3] = (const ubyte(*)[3]) srcRowA; 139 const ubyte(*rowB)[3] = (const ubyte(*)[3]) srcRowB; 140 ubyte(*dst)[3] = (ubyte(*)[3]) dstRow; 141 for (i = j = 0, k = k0; i < (uint) dstWidth; 142 i++, j += colStride, k += colStride) { 143 dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; 144 dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; 145 dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; 146 } 147 } 148 else if (datatype == UBYTE && comps == 2) { 149 uint i, j, k; 150 const ubyte(*rowA)[2] = (const ubyte(*)[2]) srcRowA; 151 const ubyte(*rowB)[2] = (const ubyte(*)[2]) srcRowB; 152 ubyte(*dst)[2] = (ubyte(*)[2]) dstRow; 153 for (i = j = 0, k = k0; i < (uint) dstWidth; 154 i++, j += colStride, k += colStride) { 155 dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) >> 2; 156 dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) >> 2; 157 } 158 } 159 else if (datatype == UBYTE && comps == 1) { 160 uint i, j, k; 161 const ubyte *rowA = (const ubyte *) srcRowA; 162 const ubyte *rowB = (const ubyte *) srcRowB; 163 ubyte *dst = (ubyte *) dstRow; 164 for (i = j = 0, k = k0; i < (uint) dstWidth; 165 i++, j += colStride, k += colStride) { 166 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2; 167 } 168 } 169 170 else if (datatype == USHORT && comps == 4) { 171 uint i, j, k; 172 const ushort(*rowA)[4] = (const ushort(*)[4]) srcRowA; 173 const ushort(*rowB)[4] = (const ushort(*)[4]) srcRowB; 174 ushort(*dst)[4] = (ushort(*)[4]) dstRow; 175 for (i = j = 0, k = k0; i < (uint) dstWidth; 176 i++, j += colStride, k += colStride) { 177 dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; 178 dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; 179 dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; 180 dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4; 181 } 182 } 183 else if (datatype == USHORT && comps == 3) { 184 uint i, j, k; 185 const ushort(*rowA)[3] = (const ushort(*)[3]) srcRowA; 186 const ushort(*rowB)[3] = (const ushort(*)[3]) srcRowB; 187 ushort(*dst)[3] = (ushort(*)[3]) dstRow; 188 for (i = j = 0, k = k0; i < (uint) dstWidth; 189 i++, j += colStride, k += colStride) { 190 dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; 191 dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; 192 dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; 193 } 194 } 195 else if (datatype == USHORT && comps == 2) { 196 uint i, j, k; 197 const ushort(*rowA)[2] = (const ushort(*)[2]) srcRowA; 198 const ushort(*rowB)[2] = (const ushort(*)[2]) srcRowB; 199 ushort(*dst)[2] = (ushort(*)[2]) dstRow; 200 for (i = j = 0, k = k0; i < (uint) dstWidth; 201 i++, j += colStride, k += colStride) { 202 dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; 203 dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; 204 } 205 } 206 else if (datatype == USHORT && comps == 1) { 207 uint i, j, k; 208 const ushort *rowA = (const ushort *) srcRowA; 209 const ushort *rowB = (const ushort *) srcRowB; 210 ushort *dst = (ushort *) dstRow; 211 for (i = j = 0, k = k0; i < (uint) dstWidth; 212 i++, j += colStride, k += colStride) { 213 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4; 214 } 215 } 216 217 else if (datatype == FLOAT && comps == 4) { 218 uint i, j, k; 219 const float(*rowA)[4] = (const float(*)[4]) srcRowA; 220 const float(*rowB)[4] = (const float(*)[4]) srcRowB; 221 float(*dst)[4] = (float(*)[4]) dstRow; 222 for (i = j = 0, k = k0; i < (uint) dstWidth; 223 i++, j += colStride, k += colStride) { 224 dst[i][0] = (rowA[j][0] + rowA[k][0] + 225 rowB[j][0] + rowB[k][0]) * 0.25F; 226 dst[i][1] = (rowA[j][1] + rowA[k][1] + 227 rowB[j][1] + rowB[k][1]) * 0.25F; 228 dst[i][2] = (rowA[j][2] + rowA[k][2] + 229 rowB[j][2] + rowB[k][2]) * 0.25F; 230 dst[i][3] = (rowA[j][3] + rowA[k][3] + 231 rowB[j][3] + rowB[k][3]) * 0.25F; 232 } 233 } 234 else if (datatype == FLOAT && comps == 3) { 235 uint i, j, k; 236 const float(*rowA)[3] = (const float(*)[3]) srcRowA; 237 const float(*rowB)[3] = (const float(*)[3]) srcRowB; 238 float(*dst)[3] = (float(*)[3]) dstRow; 239 for (i = j = 0, k = k0; i < (uint) dstWidth; 240 i++, j += colStride, k += colStride) { 241 dst[i][0] = (rowA[j][0] + rowA[k][0] + 242 rowB[j][0] + rowB[k][0]) * 0.25F; 243 dst[i][1] = (rowA[j][1] + rowA[k][1] + 244 rowB[j][1] + rowB[k][1]) * 0.25F; 245 dst[i][2] = (rowA[j][2] + rowA[k][2] + 246 rowB[j][2] + rowB[k][2]) * 0.25F; 247 } 248 } 249 else if (datatype == FLOAT && comps == 2) { 250 uint i, j, k; 251 const float(*rowA)[2] = (const float(*)[2]) srcRowA; 252 const float(*rowB)[2] = (const float(*)[2]) srcRowB; 253 float(*dst)[2] = (float(*)[2]) dstRow; 254 for (i = j = 0, k = k0; i < (uint) dstWidth; 255 i++, j += colStride, k += colStride) { 256 dst[i][0] = (rowA[j][0] + rowA[k][0] + 257 rowB[j][0] + rowB[k][0]) * 0.25F; 258 dst[i][1] = (rowA[j][1] + rowA[k][1] + 259 rowB[j][1] + rowB[k][1]) * 0.25F; 260 } 261 } 262 else if (datatype == FLOAT && comps == 1) { 263 uint i, j, k; 264 const float *rowA = (const float *) srcRowA; 265 const float *rowB = (const float *) srcRowB; 266 float *dst = (float *) dstRow; 267 for (i = j = 0, k = k0; i < (uint) dstWidth; 268 i++, j += colStride, k += colStride) { 269 dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F; 270 } 271 } 272 273#if 0 274 else if (datatype == HALF_FLOAT && comps == 4) { 275 uint i, j, k, comp; 276 const half_float(*rowA)[4] = (const half_float(*)[4]) srcRowA; 277 const half_float(*rowB)[4] = (const half_float(*)[4]) srcRowB; 278 half_float(*dst)[4] = (half_float(*)[4]) dstRow; 279 for (i = j = 0, k = k0; i < (uint) dstWidth; 280 i++, j += colStride, k += colStride) { 281 for (comp = 0; comp < 4; comp++) { 282 float aj, ak, bj, bk; 283 aj = half_to_float(rowA[j][comp]); 284 ak = half_to_float(rowA[k][comp]); 285 bj = half_to_float(rowB[j][comp]); 286 bk = half_to_float(rowB[k][comp]); 287 dst[i][comp] = float_to_half((aj + ak + bj + bk) * 0.25F); 288 } 289 } 290 } 291 else if (datatype == HALF_FLOAT && comps == 3) { 292 uint i, j, k, comp; 293 const half_float(*rowA)[3] = (const half_float(*)[3]) srcRowA; 294 const half_float(*rowB)[3] = (const half_float(*)[3]) srcRowB; 295 half_float(*dst)[3] = (half_float(*)[3]) dstRow; 296 for (i = j = 0, k = k0; i < (uint) dstWidth; 297 i++, j += colStride, k += colStride) { 298 for (comp = 0; comp < 3; comp++) { 299 float aj, ak, bj, bk; 300 aj = half_to_float(rowA[j][comp]); 301 ak = half_to_float(rowA[k][comp]); 302 bj = half_to_float(rowB[j][comp]); 303 bk = half_to_float(rowB[k][comp]); 304 dst[i][comp] = float_to_half((aj + ak + bj + bk) * 0.25F); 305 } 306 } 307 } 308 else if (datatype == HALF_FLOAT && comps == 2) { 309 uint i, j, k, comp; 310 const half_float(*rowA)[2] = (const half_float(*)[2]) srcRowA; 311 const half_float(*rowB)[2] = (const half_float(*)[2]) srcRowB; 312 half_float(*dst)[2] = (half_float(*)[2]) dstRow; 313 for (i = j = 0, k = k0; i < (uint) dstWidth; 314 i++, j += colStride, k += colStride) { 315 for (comp = 0; comp < 2; comp++) { 316 float aj, ak, bj, bk; 317 aj = half_to_float(rowA[j][comp]); 318 ak = half_to_float(rowA[k][comp]); 319 bj = half_to_float(rowB[j][comp]); 320 bk = half_to_float(rowB[k][comp]); 321 dst[i][comp] = float_to_half((aj + ak + bj + bk) * 0.25F); 322 } 323 } 324 } 325 else if (datatype == HALF_FLOAT && comps == 1) { 326 uint i, j, k; 327 const half_float *rowA = (const half_float *) srcRowA; 328 const half_float *rowB = (const half_float *) srcRowB; 329 half_float *dst = (half_float *) dstRow; 330 for (i = j = 0, k = k0; i < (uint) dstWidth; 331 i++, j += colStride, k += colStride) { 332 float aj, ak, bj, bk; 333 aj = half_to_float(rowA[j]); 334 ak = half_to_float(rowA[k]); 335 bj = half_to_float(rowB[j]); 336 bk = half_to_float(rowB[k]); 337 dst[i] = float_to_half((aj + ak + bj + bk) * 0.25F); 338 } 339 } 340#endif 341 342 else if (datatype == UINT && comps == 1) { 343 uint i, j, k; 344 const uint *rowA = (const uint *) srcRowA; 345 const uint *rowB = (const uint *) srcRowB; 346 uint *dst = (uint *) dstRow; 347 for (i = j = 0, k = k0; i < (uint) dstWidth; 348 i++, j += colStride, k += colStride) { 349 dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4; 350 } 351 } 352 353 else if (datatype == USHORT_5_6_5 && comps == 3) { 354 uint i, j, k; 355 const ushort *rowA = (const ushort *) srcRowA; 356 const ushort *rowB = (const ushort *) srcRowB; 357 ushort *dst = (ushort *) dstRow; 358 for (i = j = 0, k = k0; i < (uint) dstWidth; 359 i++, j += colStride, k += colStride) { 360 const int rowAr0 = rowA[j] & 0x1f; 361 const int rowAr1 = rowA[k] & 0x1f; 362 const int rowBr0 = rowB[j] & 0x1f; 363 const int rowBr1 = rowB[k] & 0x1f; 364 const int rowAg0 = (rowA[j] >> 5) & 0x3f; 365 const int rowAg1 = (rowA[k] >> 5) & 0x3f; 366 const int rowBg0 = (rowB[j] >> 5) & 0x3f; 367 const int rowBg1 = (rowB[k] >> 5) & 0x3f; 368 const int rowAb0 = (rowA[j] >> 11) & 0x1f; 369 const int rowAb1 = (rowA[k] >> 11) & 0x1f; 370 const int rowBb0 = (rowB[j] >> 11) & 0x1f; 371 const int rowBb1 = (rowB[k] >> 11) & 0x1f; 372 const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; 373 const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; 374 const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; 375 dst[i] = (blue << 11) | (green << 5) | red; 376 } 377 } 378 else if (datatype == USHORT_4_4_4_4 && comps == 4) { 379 uint i, j, k; 380 const ushort *rowA = (const ushort *) srcRowA; 381 const ushort *rowB = (const ushort *) srcRowB; 382 ushort *dst = (ushort *) dstRow; 383 for (i = j = 0, k = k0; i < (uint) dstWidth; 384 i++, j += colStride, k += colStride) { 385 const int rowAr0 = rowA[j] & 0xf; 386 const int rowAr1 = rowA[k] & 0xf; 387 const int rowBr0 = rowB[j] & 0xf; 388 const int rowBr1 = rowB[k] & 0xf; 389 const int rowAg0 = (rowA[j] >> 4) & 0xf; 390 const int rowAg1 = (rowA[k] >> 4) & 0xf; 391 const int rowBg0 = (rowB[j] >> 4) & 0xf; 392 const int rowBg1 = (rowB[k] >> 4) & 0xf; 393 const int rowAb0 = (rowA[j] >> 8) & 0xf; 394 const int rowAb1 = (rowA[k] >> 8) & 0xf; 395 const int rowBb0 = (rowB[j] >> 8) & 0xf; 396 const int rowBb1 = (rowB[k] >> 8) & 0xf; 397 const int rowAa0 = (rowA[j] >> 12) & 0xf; 398 const int rowAa1 = (rowA[k] >> 12) & 0xf; 399 const int rowBa0 = (rowB[j] >> 12) & 0xf; 400 const int rowBa1 = (rowB[k] >> 12) & 0xf; 401 const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; 402 const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; 403 const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; 404 const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2; 405 dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red; 406 } 407 } 408 else if (datatype == USHORT_1_5_5_5_REV && comps == 4) { 409 uint i, j, k; 410 const ushort *rowA = (const ushort *) srcRowA; 411 const ushort *rowB = (const ushort *) srcRowB; 412 ushort *dst = (ushort *) dstRow; 413 for (i = j = 0, k = k0; i < (uint) dstWidth; 414 i++, j += colStride, k += colStride) { 415 const int rowAr0 = rowA[j] & 0x1f; 416 const int rowAr1 = rowA[k] & 0x1f; 417 const int rowBr0 = rowB[j] & 0x1f; 418 const int rowBr1 = rowB[k] & 0xf; 419 const int rowAg0 = (rowA[j] >> 5) & 0x1f; 420 const int rowAg1 = (rowA[k] >> 5) & 0x1f; 421 const int rowBg0 = (rowB[j] >> 5) & 0x1f; 422 const int rowBg1 = (rowB[k] >> 5) & 0x1f; 423 const int rowAb0 = (rowA[j] >> 10) & 0x1f; 424 const int rowAb1 = (rowA[k] >> 10) & 0x1f; 425 const int rowBb0 = (rowB[j] >> 10) & 0x1f; 426 const int rowBb1 = (rowB[k] >> 10) & 0x1f; 427 const int rowAa0 = (rowA[j] >> 15) & 0x1; 428 const int rowAa1 = (rowA[k] >> 15) & 0x1; 429 const int rowBa0 = (rowB[j] >> 15) & 0x1; 430 const int rowBa1 = (rowB[k] >> 15) & 0x1; 431 const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; 432 const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; 433 const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; 434 const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2; 435 dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red; 436 } 437 } 438 else if (datatype == UBYTE_3_3_2 && comps == 3) { 439 uint i, j, k; 440 const ubyte *rowA = (const ubyte *) srcRowA; 441 const ubyte *rowB = (const ubyte *) srcRowB; 442 ubyte *dst = (ubyte *) dstRow; 443 for (i = j = 0, k = k0; i < (uint) dstWidth; 444 i++, j += colStride, k += colStride) { 445 const int rowAr0 = rowA[j] & 0x3; 446 const int rowAr1 = rowA[k] & 0x3; 447 const int rowBr0 = rowB[j] & 0x3; 448 const int rowBr1 = rowB[k] & 0x3; 449 const int rowAg0 = (rowA[j] >> 2) & 0x7; 450 const int rowAg1 = (rowA[k] >> 2) & 0x7; 451 const int rowBg0 = (rowB[j] >> 2) & 0x7; 452 const int rowBg1 = (rowB[k] >> 2) & 0x7; 453 const int rowAb0 = (rowA[j] >> 5) & 0x7; 454 const int rowAb1 = (rowA[k] >> 5) & 0x7; 455 const int rowBb0 = (rowB[j] >> 5) & 0x7; 456 const int rowBb1 = (rowB[k] >> 5) & 0x7; 457 const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; 458 const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; 459 const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; 460 dst[i] = (blue << 5) | (green << 2) | red; 461 } 462 } 463 else { 464 debug_printf("bad format in do_row()"); 465 } 466} 467 468 469static void 470format_to_type_comps(enum pipe_format pformat, 471 enum dtype *datatype, uint *comps) 472{ 473 switch (pformat) { 474 case PIPE_FORMAT_A8R8G8B8_UNORM: 475 case PIPE_FORMAT_B8G8R8A8_UNORM: 476 *datatype = UBYTE; 477 *comps = 4; 478 return; 479 case PIPE_FORMAT_A1R5G5B5_UNORM: 480 *datatype = USHORT_1_5_5_5_REV; 481 *comps = 4; 482 return; 483 case PIPE_FORMAT_A4R4G4B4_UNORM: 484 *datatype = USHORT_4_4_4_4; 485 *comps = 4; 486 return; 487 case PIPE_FORMAT_R5G6B5_UNORM: 488 *datatype = USHORT_5_6_5; 489 *comps = 3; 490 return; 491 case PIPE_FORMAT_U_L8: 492 case PIPE_FORMAT_U_A8: 493 case PIPE_FORMAT_U_I8: 494 *datatype = UBYTE; 495 *comps = 1; 496 return; 497 case PIPE_FORMAT_U_A8_L8: 498 *datatype = UBYTE; 499 *comps = 2; 500 return; 501 default: 502 assert(0); 503 } 504} 505 506 507static void 508reduce_1d(enum pipe_format pformat, 509 int srcWidth, const ubyte *srcPtr, 510 int dstWidth, ubyte *dstPtr) 511{ 512 enum dtype datatype; 513 uint comps; 514 515 format_to_type_comps(pformat, &datatype, &comps); 516 517 /* we just duplicate the input row, kind of hack, saves code */ 518 do_row(datatype, comps, 519 srcWidth, srcPtr, srcPtr, 520 dstWidth, dstPtr); 521} 522 523 524/** 525 * Strides are in bytes. If zero, it'll be computed as width * bpp. 526 */ 527static void 528reduce_2d(enum pipe_format pformat, 529 int srcWidth, int srcHeight, 530 int srcRowStride, const ubyte *srcPtr, 531 int dstWidth, int dstHeight, 532 int dstRowStride, ubyte *dstPtr) 533{ 534 enum dtype datatype; 535 uint comps; 536 const int bpt = pf_get_size(pformat); 537 const ubyte *srcA, *srcB; 538 ubyte *dst; 539 int row; 540 541 format_to_type_comps(pformat, &datatype, &comps); 542 543 if (!srcRowStride) 544 srcRowStride = bpt * srcWidth; 545 546 if (!dstRowStride) 547 dstRowStride = bpt * dstWidth; 548 549 /* Compute src and dst pointers */ 550 srcA = srcPtr; 551 if (srcHeight > 1) 552 srcB = srcA + srcRowStride; 553 else 554 srcB = srcA; 555 dst = dstPtr; 556 557 for (row = 0; row < dstHeight; row++) { 558 do_row(datatype, comps, 559 srcWidth, srcA, srcB, 560 dstWidth, dst); 561 srcA += 2 * srcRowStride; 562 srcB += 2 * srcRowStride; 563 dst += dstRowStride; 564 } 565} 566 567 568static void 569make_1d_mipmap(struct gen_mipmap_state *ctx, 570 struct pipe_texture *pt, 571 uint face, uint baseLevel, uint lastLevel) 572{ 573 struct pipe_context *pipe = ctx->pipe; 574 struct pipe_screen *screen = pipe->screen; 575 struct pipe_winsys *winsys = pipe->winsys; 576 const uint zslice = 0; 577 uint dstLevel; 578 579 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { 580 const uint srcLevel = dstLevel - 1; 581 struct pipe_surface *srcSurf, *dstSurf; 582 void *srcMap, *dstMap; 583 584 srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice); 585 dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice); 586 587 srcMap = ((ubyte *) winsys->buffer_map(winsys, srcSurf->buffer, 588 PIPE_BUFFER_USAGE_CPU_READ) 589 + srcSurf->offset); 590 dstMap = ((ubyte *) winsys->buffer_map(winsys, dstSurf->buffer, 591 PIPE_BUFFER_USAGE_CPU_WRITE) 592 + dstSurf->offset); 593 594 reduce_1d(pt->format, 595 srcSurf->width, srcMap, 596 dstSurf->width, dstMap); 597 598 winsys->buffer_unmap(winsys, srcSurf->buffer); 599 winsys->buffer_unmap(winsys, dstSurf->buffer); 600 601 pipe_surface_reference(&srcSurf, NULL); 602 pipe_surface_reference(&dstSurf, NULL); 603 } 604} 605 606 607static void 608make_2d_mipmap(struct gen_mipmap_state *ctx, 609 struct pipe_texture *pt, 610 uint face, uint baseLevel, uint lastLevel) 611{ 612 struct pipe_context *pipe = ctx->pipe; 613 struct pipe_screen *screen = pipe->screen; 614 struct pipe_winsys *winsys = pipe->winsys; 615 const uint zslice = 0; 616 uint dstLevel; 617 const int bpt = pf_get_size(pt->format); 618 619 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { 620 const uint srcLevel = dstLevel - 1; 621 struct pipe_surface *srcSurf, *dstSurf; 622 ubyte *srcMap, *dstMap; 623 624 srcSurf = screen->get_tex_surface(screen, pt, face, srcLevel, zslice); 625 dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice); 626 627 srcMap = ((ubyte *) winsys->buffer_map(winsys, srcSurf->buffer, 628 PIPE_BUFFER_USAGE_CPU_READ) 629 + srcSurf->offset); 630 dstMap = ((ubyte *) winsys->buffer_map(winsys, dstSurf->buffer, 631 PIPE_BUFFER_USAGE_CPU_WRITE) 632 + dstSurf->offset); 633 634 reduce_2d(pt->format, 635 srcSurf->width, srcSurf->height, 636 srcSurf->pitch * bpt, srcMap, 637 dstSurf->width, dstSurf->height, 638 dstSurf->pitch * bpt, dstMap); 639 640 winsys->buffer_unmap(winsys, srcSurf->buffer); 641 winsys->buffer_unmap(winsys, dstSurf->buffer); 642 643 pipe_surface_reference(&srcSurf, NULL); 644 pipe_surface_reference(&dstSurf, NULL); 645 } 646} 647 648 649static void 650make_3d_mipmap(struct gen_mipmap_state *ctx, 651 struct pipe_texture *pt, 652 uint face, uint baseLevel, uint lastLevel) 653{ 654} 655 656 657static void 658fallback_gen_mipmap(struct gen_mipmap_state *ctx, 659 struct pipe_texture *pt, 660 uint face, uint baseLevel, uint lastLevel) 661{ 662 switch (pt->target) { 663 case PIPE_TEXTURE_1D: 664 make_1d_mipmap(ctx, pt, face, baseLevel, lastLevel); 665 break; 666 case PIPE_TEXTURE_2D: 667 case PIPE_TEXTURE_CUBE: 668 make_2d_mipmap(ctx, pt, face, baseLevel, lastLevel); 669 break; 670 case PIPE_TEXTURE_3D: 671 make_3d_mipmap(ctx, pt, face, baseLevel, lastLevel); 672 break; 673 default: 674 assert(0); 675 } 676} 677 678 679/** 680 * Create a mipmap generation context. 681 * The idea is to create one of these and re-use it each time we need to 682 * generate a mipmap. 683 */ 684struct gen_mipmap_state * 685util_create_gen_mipmap(struct pipe_context *pipe, 686 struct cso_context *cso) 687{ 688 struct gen_mipmap_state *ctx; 689 uint i; 690 691 ctx = CALLOC_STRUCT(gen_mipmap_state); 692 if (!ctx) 693 return NULL; 694 695 ctx->pipe = pipe; 696 ctx->cso = cso; 697 698 /* disabled blending/masking */ 699 memset(&ctx->blend, 0, sizeof(ctx->blend)); 700 ctx->blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; 701 ctx->blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; 702 ctx->blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; 703 ctx->blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; 704 ctx->blend.colormask = PIPE_MASK_RGBA; 705 706 /* no-op depth/stencil/alpha */ 707 memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil)); 708 709 /* rasterizer */ 710 memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer)); 711 ctx->rasterizer.front_winding = PIPE_WINDING_CW; 712 ctx->rasterizer.cull_mode = PIPE_WINDING_NONE; 713 ctx->rasterizer.bypass_clipping = 1; /* bypasses viewport too */ 714 /*ctx->rasterizer.bypass_vs = 1;*/ 715 716 /* sampler state */ 717 memset(&ctx->sampler, 0, sizeof(ctx->sampler)); 718 ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 719 ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 720 ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 721 ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; 722 ctx->sampler.normalized_coords = 1; 723 724 725#if 0 726 /* viewport */ 727 ctx->viewport.scale[0] = 1.0; 728 ctx->viewport.scale[1] = 1.0; 729 ctx->viewport.scale[2] = 1.0; 730 ctx->viewport.scale[3] = 1.0; 731 ctx->viewport.translate[0] = 0.0; 732 ctx->viewport.translate[1] = 0.0; 733 ctx->viewport.translate[2] = 0.0; 734 ctx->viewport.translate[3] = 0.0; 735#endif 736 737 /* vertex shader */ 738 { 739 const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, 740 TGSI_SEMANTIC_GENERIC }; 741 const uint semantic_indexes[] = { 0, 0 }; 742 ctx->vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names, 743 semantic_indexes); 744 } 745 746 /* fragment shader */ 747 ctx->fs = util_make_fragment_tex_shader(pipe); 748 749 ctx->vbuf = pipe->winsys->buffer_create(pipe->winsys, 750 32, 751 PIPE_BUFFER_USAGE_VERTEX, 752 sizeof(ctx->vertices)); 753 if (!ctx->vbuf) { 754 FREE(ctx); 755 return NULL; 756 } 757 758 /* vertex data that doesn't change */ 759 for (i = 0; i < 4; i++) { 760 ctx->vertices[i][0][2] = 0.0f; /* z */ 761 ctx->vertices[i][0][3] = 1.0f; /* w */ 762 ctx->vertices[i][1][2] = 0.0f; /* r */ 763 ctx->vertices[i][1][3] = 1.0f; /* q */ 764 } 765 766 return ctx; 767} 768 769 770static void 771set_vertex_data(struct gen_mipmap_state *ctx, float width, float height) 772{ 773 void *buf; 774 775 ctx->vertices[0][0][0] = -0.5f; /*x*/ 776 ctx->vertices[0][0][1] = -0.5f; /*y*/ 777 ctx->vertices[0][1][0] = 0.0f; /*s*/ 778 ctx->vertices[0][1][1] = 0.0f; /*t*/ 779 780 ctx->vertices[1][0][0] = width - 0.5f; /*x*/ 781 ctx->vertices[1][0][1] = -0.5f; /*y*/ 782 ctx->vertices[1][1][0] = 1.0f; /*s*/ 783 ctx->vertices[1][1][1] = 0.0f; /*t*/ 784 785 ctx->vertices[2][0][0] = width - 0.5f; 786 ctx->vertices[2][0][1] = height - 0.5f; 787 ctx->vertices[2][1][0] = 1.0f; 788 ctx->vertices[2][1][1] = 1.0f; 789 790 ctx->vertices[3][0][0] = -0.5f; 791 ctx->vertices[3][0][1] = height - 0.5f; 792 ctx->vertices[3][1][0] = 0.0f; 793 ctx->vertices[3][1][1] = 1.0f; 794 795 buf = ctx->pipe->winsys->buffer_map(ctx->pipe->winsys, ctx->vbuf, 796 PIPE_BUFFER_USAGE_CPU_WRITE); 797 798 memcpy(buf, ctx->vertices, sizeof(ctx->vertices)); 799 800 ctx->pipe->winsys->buffer_unmap(ctx->pipe->winsys, ctx->vbuf); 801} 802 803 804 805/** 806 * Destroy a mipmap generation context 807 */ 808void 809util_destroy_gen_mipmap(struct gen_mipmap_state *ctx) 810{ 811 struct pipe_context *pipe = ctx->pipe; 812 813 pipe->delete_vs_state(pipe, ctx->vs); 814 pipe->delete_fs_state(pipe, ctx->fs); 815 816 pipe->winsys->buffer_destroy(pipe->winsys, ctx->vbuf); 817 818 FREE(ctx); 819} 820 821 822#if 0 823static void 824simple_viewport(struct pipe_context *pipe, uint width, uint height) 825{ 826 struct pipe_viewport_state vp; 827 828 vp.scale[0] = 0.5 * width; 829 vp.scale[1] = -0.5 * height; 830 vp.scale[2] = 1.0; 831 vp.scale[3] = 1.0; 832 vp.translate[0] = 0.5 * width; 833 vp.translate[1] = 0.5 * height; 834 vp.translate[2] = 0.0; 835 vp.translate[3] = 0.0; 836 837 pipe->set_viewport_state(pipe, &vp); 838} 839#endif 840 841 842/** 843 * Generate mipmap images. It's assumed all needed texture memory is 844 * already allocated. 845 * 846 * \param pt the texture to generate mipmap levels for 847 * \param face which cube face to generate mipmaps for (0 for non-cube maps) 848 * \param baseLevel the first mipmap level to use as a src 849 * \param lastLevel the last mipmap level to generate 850 * \param filter the minification filter used to generate mipmap levels with 851 * \param filter one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST 852 */ 853void 854util_gen_mipmap(struct gen_mipmap_state *ctx, 855 struct pipe_texture *pt, 856 uint face, uint baseLevel, uint lastLevel, uint filter) 857{ 858 struct pipe_context *pipe = ctx->pipe; 859 struct pipe_screen *screen = pipe->screen; 860 struct pipe_framebuffer_state fb; 861 uint dstLevel; 862 uint zslice = 0; 863 864 /* check if we can render in the texture's format */ 865 if (!screen->is_format_supported(screen, pt->format, PIPE_SURFACE)) { 866 fallback_gen_mipmap(ctx, pt, face, baseLevel, lastLevel); 867 return; 868 } 869 870 /* save state (restored below) */ 871 cso_save_blend(ctx->cso); 872 cso_save_depth_stencil_alpha(ctx->cso); 873 cso_save_rasterizer(ctx->cso); 874 cso_save_samplers(ctx->cso); 875 cso_save_sampler_textures(ctx->cso); 876 cso_save_framebuffer(ctx->cso); 877 878 /* bind our state */ 879 cso_set_blend(ctx->cso, &ctx->blend); 880 cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil); 881 cso_set_rasterizer(ctx->cso, &ctx->rasterizer); 882 883 pipe->bind_vs_state(pipe, ctx->vs); 884 pipe->bind_fs_state(pipe, ctx->fs); 885#if 0 886 pipe->set_viewport_state(pipe, &ctx->viewport); 887#endif 888 889 /* init framebuffer state */ 890 memset(&fb, 0, sizeof(fb)); 891 fb.num_cbufs = 1; 892 893 /* 894 * XXX for small mipmap levels, it may be faster to use the software 895 * fallback path... 896 */ 897 for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { 898 const uint srcLevel = dstLevel - 1; 899 900 /* 901 * Setup framebuffer / dest surface 902 */ 903 fb.cbufs[0] = screen->get_tex_surface(screen, pt, face, dstLevel, zslice); 904 fb.width = pt->width[dstLevel]; 905 fb.height = pt->height[dstLevel]; 906 cso_set_framebuffer(ctx->cso, &fb); 907 908 /* 909 * Setup sampler state 910 * Note: we should only have to set the min/max LOD clamps to ensure 911 * we grab texels from the right mipmap level. But some hardware 912 * has trouble with min clamping so we also set the lod_bias to 913 * try to work around that. 914 */ 915 ctx->sampler.min_lod = ctx->sampler.max_lod = (float) srcLevel; 916 ctx->sampler.lod_bias = (float) srcLevel; 917 ctx->sampler.mag_img_filter = filter; 918 ctx->sampler.min_img_filter = filter; 919 cso_single_sampler(ctx->cso, 0, &ctx->sampler); 920 cso_single_sampler_done(ctx->cso); 921#if 0 922 simple_viewport(pipe, pt->width[dstLevel], pt->height[dstLevel]); 923#endif 924 925 pipe->set_sampler_textures(pipe, 1, &pt); 926 927 /* quad coords in window coords (bypassing clipping, viewport mapping) */ 928 set_vertex_data(ctx, 929 (float) pt->width[dstLevel], 930 (float) pt->height[dstLevel]); 931 util_draw_vertex_buffer(ctx->pipe, ctx->vbuf, 932 PIPE_PRIM_TRIANGLE_FAN, 933 4, /* verts */ 934 2); /* attribs/vert */ 935 936 pipe->flush(pipe, PIPE_FLUSH_WAIT); 937 938 /* need to signal that the texture has changed _after_ rendering to it */ 939 pipe->texture_update(pipe, pt, face, (1 << dstLevel)); 940 } 941 942 /* restore state we changed */ 943 cso_restore_blend(ctx->cso); 944 cso_restore_depth_stencil_alpha(ctx->cso); 945 cso_restore_rasterizer(ctx->cso); 946 cso_restore_samplers(ctx->cso); 947 cso_restore_sampler_textures(ctx->cso); 948 cso_restore_framebuffer(ctx->cso); 949} 950