u_format.c revision ba6f1f2c29c148e33acc9d2b411c19c7c9a9d04f
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 /* Find the first non-void channel. */ 56 for (i = 0; i < 4; i++) { 57 if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { 58 break; 59 } 60 } 61 62 if (i == 4) { 63 return FALSE; 64 } 65 66 return desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT ? TRUE : FALSE; 67} 68 69 70/** 71 * Return the number of logical channels in the given format by 72 * examining swizzles. 73 * XXX this could be made into a public function if useful elsewhere. 74 */ 75static unsigned 76nr_logical_channels(const struct util_format_description *desc) 77{ 78 boolean swizzle_used[UTIL_FORMAT_SWIZZLE_MAX]; 79 80 memset(swizzle_used, 0, sizeof(swizzle_used)); 81 82 swizzle_used[desc->swizzle[0]] = TRUE; 83 swizzle_used[desc->swizzle[1]] = TRUE; 84 swizzle_used[desc->swizzle[2]] = TRUE; 85 swizzle_used[desc->swizzle[3]] = TRUE; 86 87 return (swizzle_used[UTIL_FORMAT_SWIZZLE_X] + 88 swizzle_used[UTIL_FORMAT_SWIZZLE_Y] + 89 swizzle_used[UTIL_FORMAT_SWIZZLE_Z] + 90 swizzle_used[UTIL_FORMAT_SWIZZLE_W]); 91} 92 93 94/** Test if the format contains RGB, but not alpha */ 95boolean 96util_format_is_rgb_no_alpha(enum pipe_format format) 97{ 98 const struct util_format_description *desc = 99 util_format_description(format); 100 101 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 102 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 103 nr_logical_channels(desc) == 3) { 104 return TRUE; 105 } 106 return FALSE; 107} 108 109 110boolean 111util_format_is_luminance(enum pipe_format format) 112{ 113 const struct util_format_description *desc = 114 util_format_description(format); 115 116 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 117 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 118 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && 119 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X && 120 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X && 121 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_1) { 122 return TRUE; 123 } 124 return FALSE; 125} 126 127 128boolean 129util_format_is_luminance_alpha(enum pipe_format format) 130{ 131 const struct util_format_description *desc = 132 util_format_description(format); 133 134 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 135 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 136 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && 137 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X && 138 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X && 139 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_Y) { 140 return TRUE; 141 } 142 return FALSE; 143} 144 145 146boolean 147util_format_is_intensity(enum pipe_format format) 148{ 149 const struct util_format_description *desc = 150 util_format_description(format); 151 152 if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB || 153 desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) && 154 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X && 155 desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_X && 156 desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_X && 157 desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_X) { 158 return TRUE; 159 } 160 return FALSE; 161} 162 163 164boolean 165util_format_is_supported(enum pipe_format format, unsigned bind) 166{ 167 if (util_format_is_s3tc(format) && !util_format_s3tc_enabled) { 168 return FALSE; 169 } 170 171#ifndef TEXTURE_FLOAT_ENABLED 172 if ((bind & PIPE_BIND_RENDER_TARGET) && 173 format != PIPE_FORMAT_R9G9B9E5_FLOAT && 174 format != PIPE_FORMAT_R11G11B10_FLOAT && 175 util_format_is_float(format)) { 176 return FALSE; 177 } 178#endif 179 180 return TRUE; 181} 182 183 184void 185util_format_read_4f(enum pipe_format format, 186 float *dst, unsigned dst_stride, 187 const void *src, unsigned src_stride, 188 unsigned x, unsigned y, unsigned w, unsigned h) 189{ 190 const struct util_format_description *format_desc; 191 const uint8_t *src_row; 192 float *dst_row; 193 194 format_desc = util_format_description(format); 195 196 assert(x % format_desc->block.width == 0); 197 assert(y % format_desc->block.height == 0); 198 199 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8); 200 dst_row = dst; 201 202 format_desc->unpack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h); 203} 204 205 206void 207util_format_write_4f(enum pipe_format format, 208 const float *src, unsigned src_stride, 209 void *dst, unsigned dst_stride, 210 unsigned x, unsigned y, unsigned w, unsigned h) 211{ 212 const struct util_format_description *format_desc; 213 uint8_t *dst_row; 214 const float *src_row; 215 216 format_desc = util_format_description(format); 217 218 assert(x % format_desc->block.width == 0); 219 assert(y % format_desc->block.height == 0); 220 221 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8); 222 src_row = src; 223 224 format_desc->pack_rgba_float(dst_row, dst_stride, src_row, src_stride, w, h); 225} 226 227 228void 229util_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) 230{ 231 const struct util_format_description *format_desc; 232 const uint8_t *src_row; 233 uint8_t *dst_row; 234 235 format_desc = util_format_description(format); 236 237 assert(x % format_desc->block.width == 0); 238 assert(y % format_desc->block.height == 0); 239 240 src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8); 241 dst_row = dst; 242 243 format_desc->unpack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h); 244} 245 246 247void 248util_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) 249{ 250 const struct util_format_description *format_desc; 251 uint8_t *dst_row; 252 const uint8_t *src_row; 253 254 format_desc = util_format_description(format); 255 256 assert(x % format_desc->block.width == 0); 257 assert(y % format_desc->block.height == 0); 258 259 dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8); 260 src_row = src; 261 262 format_desc->pack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h); 263} 264 265 266boolean 267util_is_format_compatible(const struct util_format_description *src_desc, 268 const struct util_format_description *dst_desc) 269{ 270 unsigned chan; 271 272 if (src_desc->format == dst_desc->format) { 273 return TRUE; 274 } 275 276 if (src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN || 277 dst_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) { 278 return FALSE; 279 } 280 281 if (src_desc->block.bits != dst_desc->block.bits || 282 src_desc->nr_channels != dst_desc->nr_channels || 283 src_desc->colorspace != dst_desc->colorspace) { 284 return FALSE; 285 } 286 287 for (chan = 0; chan < 4; ++chan) { 288 if (src_desc->channel[chan].size != 289 dst_desc->channel[chan].size) { 290 return FALSE; 291 } 292 } 293 294 for (chan = 0; chan < 4; ++chan) { 295 enum util_format_swizzle swizzle = dst_desc->swizzle[chan]; 296 297 if (swizzle < 4) { 298 if (src_desc->swizzle[chan] != swizzle) { 299 return FALSE; 300 } 301 if ((src_desc->channel[swizzle].type != 302 dst_desc->channel[swizzle].type) || 303 (src_desc->channel[swizzle].normalized != 304 dst_desc->channel[swizzle].normalized)) { 305 return FALSE; 306 } 307 } 308 } 309 310 return TRUE; 311} 312 313 314boolean 315util_format_fits_8unorm(const struct util_format_description *format_desc) 316{ 317 unsigned chan; 318 319 /* 320 * After linearized sRGB values require more than 8bits. 321 */ 322 323 if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) { 324 return FALSE; 325 } 326 327 switch (format_desc->layout) { 328 329 case UTIL_FORMAT_LAYOUT_S3TC: 330 case UTIL_FORMAT_LAYOUT_RGTC: 331 /* 332 * These are straight forward. 333 */ 334 335 return TRUE; 336 337 case UTIL_FORMAT_LAYOUT_PLAIN: 338 /* 339 * For these we can find a generic rule. 340 */ 341 342 for (chan = 0; chan < format_desc->nr_channels; ++chan) { 343 switch (format_desc->channel[chan].type) { 344 case UTIL_FORMAT_TYPE_VOID: 345 break; 346 case UTIL_FORMAT_TYPE_UNSIGNED: 347 if (!format_desc->channel[chan].normalized || 348 format_desc->channel[chan].size > 8) { 349 return FALSE; 350 } 351 break; 352 default: 353 return FALSE; 354 } 355 } 356 return TRUE; 357 358 default: 359 /* 360 * Handle all others on a case by case basis. 361 */ 362 363 switch (format_desc->format) { 364 case PIPE_FORMAT_R1_UNORM: 365 case PIPE_FORMAT_UYVY: 366 case PIPE_FORMAT_YUYV: 367 case PIPE_FORMAT_R8G8_B8G8_UNORM: 368 case PIPE_FORMAT_G8R8_G8B8_UNORM: 369 return TRUE; 370 371 default: 372 return FALSE; 373 } 374 } 375} 376 377 378void 379util_format_translate(enum pipe_format dst_format, 380 void *dst, unsigned dst_stride, 381 unsigned dst_x, unsigned dst_y, 382 enum pipe_format src_format, 383 const void *src, unsigned src_stride, 384 unsigned src_x, unsigned src_y, 385 unsigned width, unsigned height) 386{ 387 const struct util_format_description *dst_format_desc; 388 const struct util_format_description *src_format_desc; 389 uint8_t *dst_row; 390 const uint8_t *src_row; 391 unsigned x_step, y_step; 392 unsigned dst_step; 393 unsigned src_step; 394 395 dst_format_desc = util_format_description(dst_format); 396 src_format_desc = util_format_description(src_format); 397 398 if (util_is_format_compatible(src_format_desc, dst_format_desc)) { 399 /* 400 * Trivial case. 401 */ 402 403 util_copy_rect(dst, dst_format, dst_stride, dst_x, dst_y, 404 width, height, src, (int)src_stride, 405 src_x, src_y); 406 return; 407 } 408 409 assert(dst_x % dst_format_desc->block.width == 0); 410 assert(dst_y % dst_format_desc->block.height == 0); 411 assert(src_x % src_format_desc->block.width == 0); 412 assert(src_y % src_format_desc->block.height == 0); 413 414 dst_row = (uint8_t *)dst + dst_y*dst_stride + dst_x*(dst_format_desc->block.bits/8); 415 src_row = (const uint8_t *)src + src_y*src_stride + src_x*(src_format_desc->block.bits/8); 416 417 /* 418 * This works because all pixel formats have pixel blocks with power of two 419 * sizes. 420 */ 421 422 y_step = MAX2(dst_format_desc->block.height, src_format_desc->block.height); 423 x_step = MAX2(dst_format_desc->block.width, src_format_desc->block.width); 424 assert(y_step % dst_format_desc->block.height == 0); 425 assert(y_step % src_format_desc->block.height == 0); 426 427 dst_step = y_step / dst_format_desc->block.height * dst_stride; 428 src_step = y_step / src_format_desc->block.height * src_stride; 429 430 /* 431 * TODO: double formats will loose precision 432 * TODO: Add a special case for formats that are mere swizzles of each other 433 */ 434 435 if (util_format_fits_8unorm(src_format_desc) || 436 util_format_fits_8unorm(dst_format_desc)) { 437 unsigned tmp_stride; 438 uint8_t *tmp_row; 439 440 tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row; 441 tmp_row = MALLOC(y_step * tmp_stride); 442 if (!tmp_row) 443 return; 444 445 while (height >= y_step) { 446 src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, y_step); 447 dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step); 448 449 dst_row += dst_step; 450 src_row += src_step; 451 height -= y_step; 452 } 453 454 if (height) { 455 src_format_desc->unpack_rgba_8unorm(tmp_row, tmp_stride, src_row, src_stride, width, height); 456 dst_format_desc->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, height); 457 } 458 459 FREE(tmp_row); 460 } 461 else { 462 unsigned tmp_stride; 463 float *tmp_row; 464 465 tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row; 466 tmp_row = MALLOC(y_step * tmp_stride); 467 if (!tmp_row) 468 return; 469 470 while (height >= y_step) { 471 src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, y_step); 472 dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step); 473 474 dst_row += dst_step; 475 src_row += src_step; 476 height -= y_step; 477 } 478 479 if (height) { 480 src_format_desc->unpack_rgba_float(tmp_row, tmp_stride, src_row, src_stride, width, height); 481 dst_format_desc->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, height); 482 } 483 484 FREE(tmp_row); 485 } 486} 487 488void util_format_compose_swizzles(const unsigned char swz1[4], 489 const unsigned char swz2[4], 490 unsigned char dst[4]) 491{ 492 unsigned i; 493 494 for (i = 0; i < 4; i++) { 495 dst[i] = swz2[i] <= UTIL_FORMAT_SWIZZLE_W ? 496 swz1[swz2[i]] : swz2[i]; 497 } 498} 499 500void util_format_swizzle_4f(float *dst, const float *src, 501 const unsigned char swz[4]) 502{ 503 unsigned i; 504 505 for (i = 0; i < 4; i++) { 506 if (swz[i] <= UTIL_FORMAT_SWIZZLE_W) 507 dst[i] = src[swz[i]]; 508 else if (swz[i] == UTIL_FORMAT_SWIZZLE_0) 509 dst[i] = 0; 510 else if (swz[i] == UTIL_FORMAT_SWIZZLE_1) 511 dst[i] = 1; 512 } 513} 514 515void util_format_unswizzle_4f(float *dst, const float *src, 516 const unsigned char swz[4]) 517{ 518 unsigned i; 519 520 for (i = 0; i < 4; i++) { 521 switch (swz[i]) { 522 case UTIL_FORMAT_SWIZZLE_X: 523 dst[0] = src[i]; 524 break; 525 case UTIL_FORMAT_SWIZZLE_Y: 526 dst[1] = src[i]; 527 break; 528 case UTIL_FORMAT_SWIZZLE_Z: 529 dst[2] = src[i]; 530 break; 531 case UTIL_FORMAT_SWIZZLE_W: 532 dst[3] = src[i]; 533 break; 534 } 535 } 536} 537