u_format.c revision 866f9b18c68ede63c00917ec9c3dae3524ca8826
1/************************************************************************** 2 * 3 * Copyright 2010 VMware, Inc. 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 VMWARE 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 * Pixel format accessor functions. 31 * 32 * @author Jose Fonseca <jfonseca@vmware.com> 33 */ 34 35#include "u_math.h" 36#include "u_memory.h" 37#include "u_rect.h" 38#include "u_format.h" 39#include "u_format_s3tc.h" 40 41#include "pipe/p_defines.h" 42 43 44boolean 45util_format_is_float(enum pipe_format format) 46{ 47 const struct util_format_description *desc = util_format_description(format); 48 unsigned i; 49 50 assert(desc); 51 if (!desc) { 52 return FALSE; 53 } 54 55 i = util_format_get_first_non_void_channel(format); 56 if (i == -1) { 57 return FALSE; 58 } 59 60 return desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT ? TRUE : FALSE; 61} 62 63 64/** 65 * Return the number of logical channels in the given format by 66 * examining swizzles. 67 * XXX this could be made into a public function if useful elsewhere. 68 */ 69static unsigned 70nr_logical_channels(const struct util_format_description *desc) 71{ 72 boolean swizzle_used[UTIL_FORMAT_SWIZZLE_MAX]; 73 74 memset(swizzle_used, 0, sizeof(swizzle_used)); 75 76 swizzle_used[desc->swizzle[0]] = TRUE; 77 swizzle_used[desc->swizzle[1]] = TRUE; 78 swizzle_used[desc->swizzle[2]] = TRUE; 79 swizzle_used[desc->swizzle[3]] = TRUE; 80 81 return (swizzle_used[UTIL_FORMAT_SWIZZLE_X] + 82 swizzle_used[UTIL_FORMAT_SWIZZLE_Y] + 83 swizzle_used[UTIL_FORMAT_SWIZZLE_Z] + 84 swizzle_used[UTIL_FORMAT_SWIZZLE_W]); 85} 86 87 88/** Test if the format contains RGB, but not alpha */ 89boolean 90util_format_is_rgb_no_alpha(enum pipe_format format) 91{ 92 const struct util_format_description *desc = 93 util_format_description(format); 94 95 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 96 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 97 nr_logical_channels(desc) == 3) { 98 return TRUE; 99 } 100 return FALSE; 101} 102 103 104boolean 105util_format_is_luminance(enum pipe_format format) 106{ 107 const struct util_format_description *desc = 108 util_format_description(format); 109 110 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 111 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 112 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && 113 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X && 114 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X && 115 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) { 116 return TRUE; 117 } 118 return FALSE; 119} 120 121boolean 122util_format_is_pure_integer(enum pipe_format format) 123{ 124 const struct util_format_description *desc = util_format_description(format); 125 int i; 126 127 /* Find the first non-void channel. */ 128 i = util_format_get_first_non_void_channel(format); 129 if (i == -1) 130 return FALSE; 131 132 return desc->channel[i].pure_integer ? TRUE : FALSE; 133} 134 135boolean 136util_format_is_pure_sint(enum pipe_format format) 137{ 138 const struct util_format_description *desc = util_format_description(format); 139 int i; 140 141 i = util_format_get_first_non_void_channel(format); 142 if (i == -1) 143 return FALSE; 144 145 return (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE; 146} 147 148boolean 149util_format_is_pure_uint(enum pipe_format format) 150{ 151 const struct util_format_description *desc = util_format_description(format); 152 int i; 153 154 i = util_format_get_first_non_void_channel(format); 155 if (i == -1) 156 return FALSE; 157 158 return (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE; 159} 160 161boolean 162util_format_is_luminance_alpha(enum pipe_format format) 163{ 164 const struct util_format_description *desc = 165 util_format_description(format); 166 167 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 168 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 169 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && 170 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X && 171 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X && 172 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_Y) { 173 return TRUE; 174 } 175 return FALSE; 176} 177 178 179boolean 180util_format_is_intensity(enum pipe_format format) 181{ 182 const struct util_format_description *desc = 183 util_format_description(format); 184 185 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 186 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 187 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && 188 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X && 189 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X && 190 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) { 191 return TRUE; 192 } 193 return FALSE; 194} 195 196 197boolean 198util_format_is_supported(enum pipe_format format, unsigned bind) 199{ 200 if (util_format_is_s3tc(format) && !util_format_s3tc_enabled) { 201 return FALSE; 202 } 203 204#ifndef TEXTURE_FLOAT_ENABLED 205 if ((bind & PIPE_BIND_RENDER_TARGET) && 206 format != PIPE_FORMAT_R9G9B9E5_FLOAT && 207 format != PIPE_FORMAT_R11G11B10_FLOAT && 208 util_format_is_float(format)) { 209 return FALSE; 210 } 211#endif 212 213 return TRUE; 214} 215 216 217void 218util_format_read_4f(enum pipe_format format, 219 float *dst, unsigned dst_stride, 220 const void *src, unsigned src_stride, 221 unsigned x, unsigned y, unsigned w, unsigned h) 222{ 223 const struct util_format_description *format_desc; 224 const uint8_t *src_row; 225 float *dst_row; 226 227 format_desc = util_format_description(format); 228 229 assert(x % format_desc->block.width == 0); 230 assert(y % format_desc->block.height == 0); 231 232 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8); 233 dst_row = dst; 234 235 format_desc->unpack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h); 236} 237 238 239void 240util_format_write_4f(enum pipe_format format, 241 const float *src, unsigned src_stride, 242 void *dst, unsigned dst_stride, 243 unsigned x, unsigned y, unsigned w, unsigned h) 244{ 245 const struct util_format_description *format_desc; 246 uint8_t *dst_row; 247 const float *src_row; 248 249 format_desc = util_format_description(format); 250 251 assert(x % format_desc->block.width == 0); 252 assert(y % format_desc->block.height == 0); 253 254 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8); 255 src_row = src; 256 257 format_desc->pack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h); 258} 259 260 261void 262util_format_read_4ub(enum pipe_format format, uint8_t *dst, unsigned dst_stride, const void *src, unsigned src_stride, unsigned x, unsigned y, unsigned w, unsigned h) 263{ 264 const struct util_format_description *format_desc; 265 const uint8_t *src_row; 266 uint8_t *dst_row; 267 268 format_desc = util_format_description(format); 269 270 assert(x % format_desc->block.width == 0); 271 assert(y % format_desc->block.height == 0); 272 273 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8); 274 dst_row = dst; 275 276 format_desc->unpack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h); 277} 278 279 280void 281util_format_write_4ub(enum pipe_format format, const uint8_t *src, unsigned src_stride, void *dst, unsigned dst_stride, unsigned x, unsigned y, unsigned w, unsigned h) 282{ 283 const struct util_format_description *format_desc; 284 uint8_t *dst_row; 285 const uint8_t *src_row; 286 287 format_desc = util_format_description(format); 288 289 assert(x % format_desc->block.width == 0); 290 assert(y % format_desc->block.height == 0); 291 292 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8); 293 src_row = src; 294 295 format_desc->pack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h); 296} 297 298void 299util_format_read_4ui(enum pipe_format format, 300 unsigned *dst, unsigned dst_stride, 301 const void *src, unsigned src_stride, 302 unsigned x, unsigned y, unsigned w, unsigned h) 303{ 304 const struct util_format_description *format_desc; 305 const uint8_t *src_row; 306 unsigned *dst_row; 307 308 format_desc = util_format_description(format); 309 310 assert(x % format_desc->block.width == 0); 311 assert(y % format_desc->block.height == 0); 312 313 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8); 314 dst_row = dst; 315 316 format_desc->unpack_rgba_uint(dst_row, dst_stride, src_row, src_stride, w, h); 317} 318 319void 320util_format_write_4ui(enum pipe_format format, 321 const unsigned int *src, unsigned src_stride, 322 void *dst, unsigned dst_stride, 323 unsigned x, unsigned y, unsigned w, unsigned h) 324{ 325 const struct util_format_description *format_desc; 326 uint8_t *dst_row; 327 const unsigned *src_row; 328 329 format_desc = util_format_description(format); 330 331 assert(x % format_desc->block.width == 0); 332 assert(y % format_desc->block.height == 0); 333 334 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8); 335 src_row = src; 336 337 format_desc->pack_rgba_uint(dst_row, dst_stride, src_row, src_stride, w, h); 338} 339 340void 341util_format_read_4i(enum pipe_format format, 342 int *dst, unsigned dst_stride, 343 const void *src, unsigned src_stride, 344 unsigned x, unsigned y, unsigned w, unsigned h) 345{ 346 const struct util_format_description *format_desc; 347 const uint8_t *src_row; 348 int *dst_row; 349 350 format_desc = util_format_description(format); 351 352 assert(x % format_desc->block.width == 0); 353 assert(y % format_desc->block.height == 0); 354 355 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8); 356 dst_row = dst; 357 358 format_desc->unpack_rgba_sint(dst_row, dst_stride, src_row, src_stride, w, h); 359} 360 361void 362util_format_write_4i(enum pipe_format format, 363 const int *src, unsigned src_stride, 364 void *dst, unsigned dst_stride, 365 unsigned x, unsigned y, unsigned w, unsigned h) 366{ 367 const struct util_format_description *format_desc; 368 uint8_t *dst_row; 369 const int *src_row; 370 371 format_desc = util_format_description(format); 372 373 assert(x % format_desc->block.width == 0); 374 assert(y % format_desc->block.height == 0); 375 376 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8); 377 src_row = src; 378 379 format_desc->pack_rgba_sint(dst_row, dst_stride, src_row, src_stride, w, h); 380} 381 382boolean 383util_is_format_compatible(const struct util_format_description *src_desc, 384 const struct util_format_description *dst_desc) 385{ 386 unsigned chan; 387 388 if (src_desc->format == dst_desc->format) { 389 return TRUE; 390 } 391 392 if (src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || 393 dst_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) { 394 return FALSE; 395 } 396 397 if (src_desc->block.bits != dst_desc->block.bits || 398 src_desc->nr_channels != dst_desc->nr_channels || 399 src_desc->colorspace != dst_desc->colorspace) { 400 return FALSE; 401 } 402 403 for (chan = 0; chan < 4; ++chan) { 404 if (src_desc->channel[chan].size != 405 dst_desc->channel[chan].size) { 406 return FALSE; 407 } 408 } 409 410 for (chan = 0; chan < 4; ++chan) { 411 enum util_format_swizzle swizzle = dst_desc->swizzle[chan]; 412 413 if (swizzle < 4) { 414 if (src_desc->swizzle[chan] != swizzle) { 415 return FALSE; 416 } 417 if ((src_desc->channel[swizzle].type != 418 dst_desc->channel[swizzle].type) || 419 (src_desc->channel[swizzle].normalized != 420 dst_desc->channel[swizzle].normalized)) { 421 return FALSE; 422 } 423 } 424 } 425 426 return TRUE; 427} 428 429 430boolean 431util_format_fits_8unorm(const struct util_format_description *format_desc) 432{ 433 unsigned chan; 434 435 /* 436 * After linearized sRGB values require more than 8bits. 437 */ 438 439 if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) { 440 return FALSE; 441 } 442 443 switch (format_desc->layout) { 444 445 case UTIL_FORMAT_LAYOUT_S3TC: 446 case UTIL_FORMAT_LAYOUT_RGTC: 447 /* 448 * These are straight forward. 449 */ 450 451 return TRUE; 452 453 case UTIL_FORMAT_LAYOUT_PLAIN: 454 /* 455 * For these we can find a generic rule. 456 */ 457 458 for (chan = 0; chan < format_desc->nr_channels; ++chan) { 459 switch (format_desc->channel[chan].type) { 460 case UTIL_FORMAT_TYPE_VOID: 461 break; 462 case UTIL_FORMAT_TYPE_UNSIGNED: 463 if (!format_desc->channel[chan].normalized || 464 format_desc->channel[chan].size > 8) { 465 return FALSE; 466 } 467 break; 468 default: 469 return FALSE; 470 } 471 } 472 return TRUE; 473 474 default: 475 /* 476 * Handle all others on a case by case basis. 477 */ 478 479 switch (format_desc->format) { 480 case PIPE_FORMAT_R1_UNORM: 481 case PIPE_FORMAT_UYVY: 482 case PIPE_FORMAT_YUYV: 483 case PIPE_FORMAT_R8G8_B8G8_UNORM: 484 case PIPE_FORMAT_G8R8_G8B8_UNORM: 485 return TRUE; 486 487 default: 488 return FALSE; 489 } 490 } 491} 492 493 494void 495util_format_translate(enum pipe_format dst_format, 496 void *dst, unsigned dst_stride, 497 unsigned dst_x, unsigned dst_y, 498 enum pipe_format src_format, 499 const void *src, unsigned src_stride, 500 unsigned src_x, unsigned src_y, 501 unsigned width, unsigned height) 502{ 503 const struct util_format_description *dst_format_desc; 504 const struct util_format_description *src_format_desc; 505 uint8_t *dst_row; 506 const uint8_t *src_row; 507 unsigned x_step, y_step; 508 unsigned dst_step; 509 unsigned src_step; 510 511 dst_format_desc = util_format_description(dst_format); 512 src_format_desc = util_format_description(src_format); 513 514 if (util_is_format_compatible(src_format_desc, dst_format_desc)) { 515 /* 516 * Trivial case. 517 */ 518 519 util_copy_rect(dst, dst_format, dst_stride, dst_x, dst_y, 520 width, height, src, (int)src_stride, 521 src_x, src_y); 522 return; 523 } 524 525 assert(dst_x % dst_format_desc->block.width == 0); 526 assert(dst_y % dst_format_desc->block.height == 0); 527 assert(src_x % src_format_desc->block.width == 0); 528 assert(src_y % src_format_desc->block.height == 0); 529 530 dst_row = (uint8_t *)dst + dst_y*dst_stride + dst_x*(dst_format_desc->block.bits/8); 531 src_row = (const uint8_t *)src + src_y*src_stride + src_x*(src_format_desc->block.bits/8); 532 533 /* 534 * This works because all pixel formats have pixel blocks with power of two 535 * sizes. 536 */ 537 538 y_step = MAX2(dst_format_desc->block.height, src_format_desc->block.height); 539 x_step = MAX2(dst_format_desc->block.width, src_format_desc->block.width); 540 assert(y_step % dst_format_desc->block.height == 0); 541 assert(y_step % src_format_desc->block.height == 0); 542 543 dst_step = y_step / dst_format_desc->block.height * dst_stride; 544 src_step = y_step / src_format_desc->block.height * src_stride; 545 546 /* 547 * TODO: double formats will loose precision 548 * TODO: Add a special case for formats that are mere swizzles of each other 549 */ 550 551 if (src_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS || 552 dst_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) { 553 float *tmp_z = NULL; 554 uint8_t *tmp_s = NULL; 555 556 assert(x_step == 1); 557 assert(y_step == 1); 558 559 if (src_format_desc->unpack_z_float && 560 dst_format_desc->pack_z_float) { 561 tmp_z = MALLOC(width * sizeof *tmp_z); 562 } 563 564 if (src_format_desc->unpack_s_8uint && 565 dst_format_desc->pack_s_8uint) { 566 tmp_s = MALLOC(width * sizeof *tmp_s); 567 } 568 569 while (height--) { 570 if (tmp_z) { 571 src_format_desc->unpack_z_float(tmp_z, 0, src_row, src_stride, width, 1); 572 dst_format_desc->pack_z_float(dst_row, dst_stride, tmp_z, 0, width, 1); 573 } 574 575 if (tmp_s) { 576 src_format_desc->unpack_s_8uint(tmp_s, 0, src_row, src_stride, width, 1); 577 dst_format_desc->pack_s_8uint(dst_row, dst_stride, tmp_s, 0, width, 1); 578 } 579 580 dst_row += dst_step; 581 src_row += src_step; 582 } 583 584 if (tmp_s) { 585 FREE(tmp_s); 586 } 587 588 if (tmp_z) { 589 FREE(tmp_z); 590 } 591 592 return; 593 } 594 595 if (util_format_fits_8unorm(src_format_desc) || 596 util_format_fits_8unorm(dst_format_desc)) { 597 unsigned tmp_stride; 598 uint8_t *tmp_row; 599 600 tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row; 601 tmp_row = MALLOC(y_step * tmp_stride); 602 if (!tmp_row) 603 return; 604 605 while (height >= y_step) { 606 src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, y_step); 607 dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step); 608 609 dst_row += dst_step; 610 src_row += src_step; 611 height -= y_step; 612 } 613 614 if (height) { 615 src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, height); 616 dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, height); 617 } 618 619 FREE(tmp_row); 620 } 621 else { 622 unsigned tmp_stride; 623 float *tmp_row; 624 625 tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row; 626 tmp_row = MALLOC(y_step * tmp_stride); 627 if (!tmp_row) 628 return; 629 630 while (height >= y_step) { 631 src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, y_step); 632 dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step); 633 634 dst_row += dst_step; 635 src_row += src_step; 636 height -= y_step; 637 } 638 639 if (height) { 640 src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, height); 641 dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, height); 642 } 643 644 FREE(tmp_row); 645 } 646} 647 648void util_format_compose_swizzles(const unsigned char swz1[4], 649 const unsigned char swz2[4], 650 unsigned char dst[4]) 651{ 652 unsigned i; 653 654 for (i = 0; i < 4; i++) { 655 dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ? 656 swz1[swz2[i]] : swz2[i]; 657 } 658} 659 660void util_format_swizzle_4f(float *dst, const float *src, 661 const unsigned char swz[4]) 662{ 663 unsigned i; 664 665 for (i = 0; i < 4; i++) { 666 if (swz[i] <= UTIL_FORMAT_SWIZZLE_W) 667 dst[i] = src[swz[i]]; 668 else if (swz[i] == UTIL_FORMAT_SWIZZLE_0) 669 dst[i] = 0; 670 else if (swz[i] == UTIL_FORMAT_SWIZZLE_1) 671 dst[i] = 1; 672 } 673} 674 675void util_format_unswizzle_4f(float *dst, const float *src, 676 const unsigned char swz[4]) 677{ 678 unsigned i; 679 680 for (i = 0; i < 4; i++) { 681 switch (swz[i]) { 682 case UTIL_FORMAT_SWIZZLE_X: 683 dst[0] = src[i]; 684 break; 685 case UTIL_FORMAT_SWIZZLE_Y: 686 dst[1] = src[i]; 687 break; 688 case UTIL_FORMAT_SWIZZLE_Z: 689 dst[2] = src[i]; 690 break; 691 case UTIL_FORMAT_SWIZZLE_W: 692 dst[3] = src[i]; 693 break; 694 } 695 } 696} 697