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