1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27/** 28 * @file 29 * Surface utility functions. 30 * 31 * @author Brian Paul 32 */ 33 34 35#include "pipe/p_defines.h" 36#include "pipe/p_screen.h" 37#include "pipe/p_state.h" 38 39#include "util/u_format.h" 40#include "util/u_inlines.h" 41#include "util/u_rect.h" 42#include "util/u_surface.h" 43#include "util/u_pack_color.h" 44 45 46/** 47 * Initialize a pipe_surface object. 'view' is considered to have 48 * uninitialized contents. 49 */ 50void 51u_surface_default_template(struct pipe_surface *surf, 52 const struct pipe_resource *texture) 53{ 54 memset(surf, 0, sizeof(*surf)); 55 56 surf->format = texture->format; 57} 58 59 60/** 61 * Copy 2D rect from one place to another. 62 * Position and sizes are in pixels. 63 * src_stride may be negative to do vertical flip of pixels from source. 64 */ 65void 66util_copy_rect(ubyte * dst, 67 enum pipe_format format, 68 unsigned dst_stride, 69 unsigned dst_x, 70 unsigned dst_y, 71 unsigned width, 72 unsigned height, 73 const ubyte * src, 74 int src_stride, 75 unsigned src_x, 76 unsigned src_y) 77{ 78 unsigned i; 79 int src_stride_pos = src_stride < 0 ? -src_stride : src_stride; 80 int blocksize = util_format_get_blocksize(format); 81 int blockwidth = util_format_get_blockwidth(format); 82 int blockheight = util_format_get_blockheight(format); 83 84 assert(blocksize > 0); 85 assert(blockwidth > 0); 86 assert(blockheight > 0); 87 88 dst_x /= blockwidth; 89 dst_y /= blockheight; 90 width = (width + blockwidth - 1)/blockwidth; 91 height = (height + blockheight - 1)/blockheight; 92 src_x /= blockwidth; 93 src_y /= blockheight; 94 95 dst += dst_x * blocksize; 96 src += src_x * blocksize; 97 dst += dst_y * dst_stride; 98 src += src_y * src_stride_pos; 99 width *= blocksize; 100 101 if (width == dst_stride && width == (unsigned)src_stride) 102 memcpy(dst, src, height * width); 103 else { 104 for (i = 0; i < height; i++) { 105 memcpy(dst, src, width); 106 dst += dst_stride; 107 src += src_stride; 108 } 109 } 110} 111 112 113/** 114 * Copy 3D box from one place to another. 115 * Position and sizes are in pixels. 116 */ 117void 118util_copy_box(ubyte * dst, 119 enum pipe_format format, 120 unsigned dst_stride, unsigned dst_slice_stride, 121 unsigned dst_x, unsigned dst_y, unsigned dst_z, 122 unsigned width, unsigned height, unsigned depth, 123 const ubyte * src, 124 int src_stride, unsigned src_slice_stride, 125 unsigned src_x, unsigned src_y, unsigned src_z) 126{ 127 unsigned z; 128 dst += dst_z * dst_slice_stride; 129 src += src_z * src_slice_stride; 130 for (z = 0; z < depth; ++z) { 131 util_copy_rect(dst, 132 format, 133 dst_stride, 134 dst_x, dst_y, 135 width, height, 136 src, 137 src_stride, 138 src_x, src_y); 139 140 dst += dst_slice_stride; 141 src += src_slice_stride; 142 } 143} 144 145 146void 147util_fill_rect(ubyte * dst, 148 enum pipe_format format, 149 unsigned dst_stride, 150 unsigned dst_x, 151 unsigned dst_y, 152 unsigned width, 153 unsigned height, 154 union util_color *uc) 155{ 156 const struct util_format_description *desc = util_format_description(format); 157 unsigned i, j; 158 unsigned width_size; 159 int blocksize = desc->block.bits / 8; 160 int blockwidth = desc->block.width; 161 int blockheight = desc->block.height; 162 163 assert(blocksize > 0); 164 assert(blockwidth > 0); 165 assert(blockheight > 0); 166 167 dst_x /= blockwidth; 168 dst_y /= blockheight; 169 width = (width + blockwidth - 1)/blockwidth; 170 height = (height + blockheight - 1)/blockheight; 171 172 dst += dst_x * blocksize; 173 dst += dst_y * dst_stride; 174 width_size = width * blocksize; 175 176 switch (blocksize) { 177 case 1: 178 if(dst_stride == width_size) 179 memset(dst, uc->ub, height * width_size); 180 else { 181 for (i = 0; i < height; i++) { 182 memset(dst, uc->ub, width_size); 183 dst += dst_stride; 184 } 185 } 186 break; 187 case 2: 188 for (i = 0; i < height; i++) { 189 uint16_t *row = (uint16_t *)dst; 190 for (j = 0; j < width; j++) 191 *row++ = uc->us; 192 dst += dst_stride; 193 } 194 break; 195 case 4: 196 for (i = 0; i < height; i++) { 197 uint32_t *row = (uint32_t *)dst; 198 for (j = 0; j < width; j++) 199 *row++ = uc->ui[0]; 200 dst += dst_stride; 201 } 202 break; 203 default: 204 for (i = 0; i < height; i++) { 205 ubyte *row = dst; 206 for (j = 0; j < width; j++) { 207 memcpy(row, uc, blocksize); 208 row += blocksize; 209 } 210 dst += dst_stride; 211 } 212 break; 213 } 214} 215 216 217void 218util_fill_box(ubyte * dst, 219 enum pipe_format format, 220 unsigned stride, 221 unsigned layer_stride, 222 unsigned x, 223 unsigned y, 224 unsigned z, 225 unsigned width, 226 unsigned height, 227 unsigned depth, 228 union util_color *uc) 229{ 230 unsigned layer; 231 dst += z * layer_stride; 232 for (layer = z; layer < depth; layer++) { 233 util_fill_rect(dst, format, 234 stride, 235 x, y, width, height, uc); 236 dst += layer_stride; 237 } 238} 239 240 241/** 242 * Fallback function for pipe->resource_copy_region(). 243 * We support copying between different formats (including compressed/ 244 * uncompressed) if the bytes per block or pixel matches. If copying 245 * compressed -> uncompressed, the dst region is reduced by the block 246 * width, height. If copying uncompressed -> compressed, the dest region 247 * is expanded by the block width, height. See GL_ARB_copy_image. 248 * Note: (X,Y)=(0,0) is always the upper-left corner. 249 */ 250void 251util_resource_copy_region(struct pipe_context *pipe, 252 struct pipe_resource *dst, 253 unsigned dst_level, 254 unsigned dst_x, unsigned dst_y, unsigned dst_z, 255 struct pipe_resource *src, 256 unsigned src_level, 257 const struct pipe_box *src_box_in) 258{ 259 struct pipe_transfer *src_trans, *dst_trans; 260 uint8_t *dst_map; 261 const uint8_t *src_map; 262 enum pipe_format src_format; 263 enum pipe_format dst_format; 264 struct pipe_box src_box, dst_box; 265 unsigned src_bs, dst_bs, src_bw, dst_bw, src_bh, dst_bh; 266 267 assert(src && dst); 268 if (!src || !dst) 269 return; 270 271 assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) || 272 (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER)); 273 274 src_format = src->format; 275 dst_format = dst->format; 276 277 /* init src box */ 278 src_box = *src_box_in; 279 280 /* init dst box */ 281 dst_box.x = dst_x; 282 dst_box.y = dst_y; 283 dst_box.z = dst_z; 284 dst_box.width = src_box.width; 285 dst_box.height = src_box.height; 286 dst_box.depth = src_box.depth; 287 288 src_bs = util_format_get_blocksize(src_format); 289 src_bw = util_format_get_blockwidth(src_format); 290 src_bh = util_format_get_blockheight(src_format); 291 dst_bs = util_format_get_blocksize(dst_format); 292 dst_bw = util_format_get_blockwidth(dst_format); 293 dst_bh = util_format_get_blockheight(dst_format); 294 295 /* Note: all box positions and sizes are in pixels */ 296 if (src_bw > 1 && dst_bw == 1) { 297 /* Copy from compressed to uncompressed. 298 * Shrink dest box by the src block size. 299 */ 300 dst_box.width /= src_bw; 301 dst_box.height /= src_bh; 302 } 303 else if (src_bw == 1 && dst_bw > 1) { 304 /* Copy from uncompressed to compressed. 305 * Expand dest box by the dest block size. 306 */ 307 dst_box.width *= dst_bw; 308 dst_box.height *= dst_bh; 309 } 310 else { 311 /* compressed -> compressed or uncompressed -> uncompressed copy */ 312 assert(src_bw == dst_bw); 313 assert(src_bh == dst_bh); 314 } 315 316 assert(src_bs == dst_bs); 317 if (src_bs != dst_bs) { 318 /* This can happen if we fail to do format checking before hand. 319 * Don't crash below. 320 */ 321 return; 322 } 323 324 /* check that region boxes are block aligned */ 325 assert(src_box.x % src_bw == 0); 326 assert(src_box.y % src_bh == 0); 327 assert(dst_box.x % dst_bw == 0); 328 assert(dst_box.y % dst_bh == 0); 329 330 /* check that region boxes are not out of bounds */ 331 assert(src_box.x + src_box.width <= (int)u_minify(src->width0, src_level)); 332 assert(src_box.y + src_box.height <= (int)u_minify(src->height0, src_level)); 333 assert(dst_box.x + dst_box.width <= (int)u_minify(dst->width0, dst_level)); 334 assert(dst_box.y + dst_box.height <= (int)u_minify(dst->height0, dst_level)); 335 336 /* check that total number of src, dest bytes match */ 337 assert((src_box.width / src_bw) * (src_box.height / src_bh) * src_bs == 338 (dst_box.width / dst_bw) * (dst_box.height / dst_bh) * dst_bs); 339 340 src_map = pipe->transfer_map(pipe, 341 src, 342 src_level, 343 PIPE_TRANSFER_READ, 344 &src_box, &src_trans); 345 assert(src_map); 346 if (!src_map) { 347 goto no_src_map; 348 } 349 350 dst_map = pipe->transfer_map(pipe, 351 dst, 352 dst_level, 353 PIPE_TRANSFER_WRITE | 354 PIPE_TRANSFER_DISCARD_RANGE, &dst_box, 355 &dst_trans); 356 assert(dst_map); 357 if (!dst_map) { 358 goto no_dst_map; 359 } 360 361 if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) { 362 assert(src_box.height == 1); 363 assert(src_box.depth == 1); 364 memcpy(dst_map, src_map, src_box.width); 365 } else { 366 util_copy_box(dst_map, 367 src_format, 368 dst_trans->stride, dst_trans->layer_stride, 369 0, 0, 0, 370 src_box.width, src_box.height, src_box.depth, 371 src_map, 372 src_trans->stride, src_trans->layer_stride, 373 0, 0, 0); 374 } 375 376 pipe->transfer_unmap(pipe, dst_trans); 377no_dst_map: 378 pipe->transfer_unmap(pipe, src_trans); 379no_src_map: 380 ; 381} 382 383static void 384util_clear_color_texture_helper(struct pipe_transfer *dst_trans, 385 ubyte *dst_map, 386 enum pipe_format format, 387 const union pipe_color_union *color, 388 unsigned width, unsigned height, unsigned depth) 389{ 390 union util_color uc; 391 392 assert(dst_trans->stride > 0); 393 394 if (util_format_is_pure_integer(format)) { 395 /* 396 * We expect int/uint clear values here, though some APIs 397 * might disagree (but in any case util_pack_color() 398 * couldn't handle it)... 399 */ 400 if (util_format_is_pure_sint(format)) { 401 util_format_write_4i(format, color->i, 0, &uc, 0, 0, 0, 1, 1); 402 } else { 403 assert(util_format_is_pure_uint(format)); 404 util_format_write_4ui(format, color->ui, 0, &uc, 0, 0, 0, 1, 1); 405 } 406 } else { 407 util_pack_color(color->f, format, &uc); 408 } 409 410 util_fill_box(dst_map, format, 411 dst_trans->stride, dst_trans->layer_stride, 412 0, 0, 0, width, height, depth, &uc); 413} 414 415static void 416util_clear_color_texture(struct pipe_context *pipe, 417 struct pipe_resource *texture, 418 enum pipe_format format, 419 const union pipe_color_union *color, 420 unsigned level, 421 unsigned dstx, unsigned dsty, unsigned dstz, 422 unsigned width, unsigned height, unsigned depth) 423{ 424 struct pipe_transfer *dst_trans; 425 ubyte *dst_map; 426 427 dst_map = pipe_transfer_map_3d(pipe, 428 texture, 429 level, 430 PIPE_TRANSFER_WRITE, 431 dstx, dsty, dstz, 432 width, height, depth, 433 &dst_trans); 434 if (!dst_map) 435 return; 436 437 if (dst_trans->stride > 0) { 438 util_clear_color_texture_helper(dst_trans, dst_map, format, color, 439 width, height, depth); 440 } 441 pipe->transfer_unmap(pipe, dst_trans); 442} 443 444 445#define UBYTE_TO_USHORT(B) ((B) | ((B) << 8)) 446 447 448/** 449 * Fallback for pipe->clear_render_target() function. 450 * XXX this looks too hackish to be really useful. 451 * cpp > 4 looks like a gross hack at best... 452 * Plus can't use these transfer fallbacks when clearing 453 * multisampled surfaces for instance. 454 * Clears all bound layers. 455 */ 456void 457util_clear_render_target(struct pipe_context *pipe, 458 struct pipe_surface *dst, 459 const union pipe_color_union *color, 460 unsigned dstx, unsigned dsty, 461 unsigned width, unsigned height) 462{ 463 struct pipe_transfer *dst_trans; 464 ubyte *dst_map; 465 466 assert(dst->texture); 467 if (!dst->texture) 468 return; 469 470 if (dst->texture->target == PIPE_BUFFER) { 471 /* 472 * The fill naturally works on the surface format, however 473 * the transfer uses resource format which is just bytes for buffers. 474 */ 475 unsigned dx, w; 476 unsigned pixstride = util_format_get_blocksize(dst->format); 477 dx = (dst->u.buf.first_element + dstx) * pixstride; 478 w = width * pixstride; 479 dst_map = pipe_transfer_map(pipe, 480 dst->texture, 481 0, 0, 482 PIPE_TRANSFER_WRITE, 483 dx, 0, w, 1, 484 &dst_trans); 485 if (dst_map) { 486 util_clear_color_texture_helper(dst_trans, dst_map, dst->format, 487 color, width, height, 1); 488 pipe->transfer_unmap(pipe, dst_trans); 489 } 490 } 491 else { 492 unsigned depth = dst->u.tex.last_layer - dst->u.tex.first_layer + 1; 493 util_clear_color_texture(pipe, dst->texture, dst->format, color, 494 dst->u.tex.level, dstx, dsty, 495 dst->u.tex.first_layer, width, height, depth); 496 } 497} 498 499static void 500util_clear_depth_stencil_texture(struct pipe_context *pipe, 501 struct pipe_resource *texture, 502 enum pipe_format format, 503 unsigned clear_flags, 504 uint64_t zstencil, unsigned level, 505 unsigned dstx, unsigned dsty, unsigned dstz, 506 unsigned width, unsigned height, unsigned depth) 507{ 508 struct pipe_transfer *dst_trans; 509 ubyte *dst_map; 510 boolean need_rmw = FALSE; 511 unsigned dst_stride; 512 ubyte *dst_layer; 513 unsigned i, j, layer; 514 515 if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) && 516 ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) && 517 util_format_is_depth_and_stencil(format)) 518 need_rmw = TRUE; 519 520 dst_map = pipe_transfer_map_3d(pipe, 521 texture, 522 level, 523 (need_rmw ? PIPE_TRANSFER_READ_WRITE : 524 PIPE_TRANSFER_WRITE), 525 dstx, dsty, dstz, 526 width, height, depth, &dst_trans); 527 assert(dst_map); 528 if (!dst_map) 529 return; 530 531 dst_stride = dst_trans->stride; 532 dst_layer = dst_map; 533 assert(dst_trans->stride > 0); 534 535 for (layer = 0; layer < depth; layer++) { 536 dst_map = dst_layer; 537 538 switch (util_format_get_blocksize(format)) { 539 case 1: 540 assert(format == PIPE_FORMAT_S8_UINT); 541 if(dst_stride == width) 542 memset(dst_map, (uint8_t) zstencil, height * width); 543 else { 544 for (i = 0; i < height; i++) { 545 memset(dst_map, (uint8_t) zstencil, width); 546 dst_map += dst_stride; 547 } 548 } 549 break; 550 case 2: 551 assert(format == PIPE_FORMAT_Z16_UNORM); 552 for (i = 0; i < height; i++) { 553 uint16_t *row = (uint16_t *)dst_map; 554 for (j = 0; j < width; j++) 555 *row++ = (uint16_t) zstencil; 556 dst_map += dst_stride; 557 } 558 break; 559 case 4: 560 if (!need_rmw) { 561 for (i = 0; i < height; i++) { 562 uint32_t *row = (uint32_t *)dst_map; 563 for (j = 0; j < width; j++) 564 *row++ = (uint32_t) zstencil; 565 dst_map += dst_stride; 566 } 567 } 568 else { 569 uint32_t dst_mask; 570 if (format == PIPE_FORMAT_Z24_UNORM_S8_UINT) 571 dst_mask = 0x00ffffff; 572 else { 573 assert(format == PIPE_FORMAT_S8_UINT_Z24_UNORM); 574 dst_mask = 0xffffff00; 575 } 576 if (clear_flags & PIPE_CLEAR_DEPTH) 577 dst_mask = ~dst_mask; 578 for (i = 0; i < height; i++) { 579 uint32_t *row = (uint32_t *)dst_map; 580 for (j = 0; j < width; j++) { 581 uint32_t tmp = *row & dst_mask; 582 *row++ = tmp | ((uint32_t) zstencil & ~dst_mask); 583 } 584 dst_map += dst_stride; 585 } 586 } 587 break; 588 case 8: 589 if (!need_rmw) { 590 for (i = 0; i < height; i++) { 591 uint64_t *row = (uint64_t *)dst_map; 592 for (j = 0; j < width; j++) 593 *row++ = zstencil; 594 dst_map += dst_stride; 595 } 596 } 597 else { 598 uint64_t src_mask; 599 600 if (clear_flags & PIPE_CLEAR_DEPTH) 601 src_mask = 0x00000000ffffffffull; 602 else 603 src_mask = 0x000000ff00000000ull; 604 605 for (i = 0; i < height; i++) { 606 uint64_t *row = (uint64_t *)dst_map; 607 for (j = 0; j < width; j++) { 608 uint64_t tmp = *row & ~src_mask; 609 *row++ = tmp | (zstencil & src_mask); 610 } 611 dst_map += dst_stride; 612 } 613 } 614 break; 615 default: 616 assert(0); 617 break; 618 } 619 dst_layer += dst_trans->layer_stride; 620 } 621 622 pipe->transfer_unmap(pipe, dst_trans); 623} 624 625 626void 627util_clear_texture(struct pipe_context *pipe, 628 struct pipe_resource *tex, 629 unsigned level, 630 const struct pipe_box *box, 631 const void *data) 632{ 633 const struct util_format_description *desc = 634 util_format_description(tex->format); 635 636 if (level > tex->last_level) 637 return; 638 639 if (util_format_is_depth_or_stencil(tex->format)) { 640 unsigned clear = 0; 641 float depth = 0.0f; 642 uint8_t stencil = 0; 643 uint64_t zstencil; 644 645 if (util_format_has_depth(desc)) { 646 clear |= PIPE_CLEAR_DEPTH; 647 desc->unpack_z_float(&depth, 0, data, 0, 1, 1); 648 } 649 650 if (util_format_has_stencil(desc)) { 651 clear |= PIPE_CLEAR_STENCIL; 652 desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1); 653 } 654 655 zstencil = util_pack64_z_stencil(tex->format, depth, stencil); 656 657 util_clear_depth_stencil_texture(pipe, tex, tex->format, clear, zstencil, 658 level, box->x, box->y, box->z, 659 box->width, box->height, box->depth); 660 } else { 661 union pipe_color_union color; 662 if (util_format_is_pure_uint(tex->format)) 663 desc->unpack_rgba_uint(color.ui, 0, data, 0, 1, 1); 664 else if (util_format_is_pure_sint(tex->format)) 665 desc->unpack_rgba_sint(color.i, 0, data, 0, 1, 1); 666 else 667 desc->unpack_rgba_float(color.f, 0, data, 0, 1, 1); 668 669 util_clear_color_texture(pipe, tex, tex->format, &color, level, 670 box->x, box->y, box->z, 671 box->width, box->height, box->depth); 672 } 673} 674 675 676/** 677 * Fallback for pipe->clear_stencil() function. 678 * sw fallback doesn't look terribly useful here. 679 * Plus can't use these transfer fallbacks when clearing 680 * multisampled surfaces for instance. 681 * Clears all bound layers. 682 */ 683void 684util_clear_depth_stencil(struct pipe_context *pipe, 685 struct pipe_surface *dst, 686 unsigned clear_flags, 687 double depth, 688 unsigned stencil, 689 unsigned dstx, unsigned dsty, 690 unsigned width, unsigned height) 691{ 692 uint64_t zstencil; 693 unsigned max_layer; 694 695 assert(dst->texture); 696 if (!dst->texture) 697 return; 698 699 zstencil = util_pack64_z_stencil(dst->format, depth, stencil); 700 max_layer = dst->u.tex.last_layer - dst->u.tex.first_layer; 701 util_clear_depth_stencil_texture(pipe, dst->texture, dst->format, 702 clear_flags, zstencil, dst->u.tex.level, 703 dstx, dsty, dst->u.tex.first_layer, 704 width, height, max_layer + 1); 705} 706 707 708/* Return if the box is totally inside the resource. 709 */ 710static boolean 711is_box_inside_resource(const struct pipe_resource *res, 712 const struct pipe_box *box, 713 unsigned level) 714{ 715 unsigned width = 1, height = 1, depth = 1; 716 717 switch (res->target) { 718 case PIPE_BUFFER: 719 width = res->width0; 720 height = 1; 721 depth = 1; 722 break; 723 case PIPE_TEXTURE_1D: 724 width = u_minify(res->width0, level); 725 height = 1; 726 depth = 1; 727 break; 728 case PIPE_TEXTURE_2D: 729 case PIPE_TEXTURE_RECT: 730 width = u_minify(res->width0, level); 731 height = u_minify(res->height0, level); 732 depth = 1; 733 break; 734 case PIPE_TEXTURE_3D: 735 width = u_minify(res->width0, level); 736 height = u_minify(res->height0, level); 737 depth = u_minify(res->depth0, level); 738 break; 739 case PIPE_TEXTURE_CUBE: 740 width = u_minify(res->width0, level); 741 height = u_minify(res->height0, level); 742 depth = 6; 743 break; 744 case PIPE_TEXTURE_1D_ARRAY: 745 width = u_minify(res->width0, level); 746 height = 1; 747 depth = res->array_size; 748 break; 749 case PIPE_TEXTURE_2D_ARRAY: 750 width = u_minify(res->width0, level); 751 height = u_minify(res->height0, level); 752 depth = res->array_size; 753 break; 754 case PIPE_TEXTURE_CUBE_ARRAY: 755 width = u_minify(res->width0, level); 756 height = u_minify(res->height0, level); 757 depth = res->array_size; 758 assert(res->array_size % 6 == 0); 759 break; 760 case PIPE_MAX_TEXTURE_TYPES: 761 break; 762 } 763 764 return box->x >= 0 && 765 box->x + box->width <= (int) width && 766 box->y >= 0 && 767 box->y + box->height <= (int) height && 768 box->z >= 0 && 769 box->z + box->depth <= (int) depth; 770} 771 772static unsigned 773get_sample_count(const struct pipe_resource *res) 774{ 775 return res->nr_samples ? res->nr_samples : 1; 776} 777 778 779/** 780 * Check if a blit() command can be implemented with a resource_copy_region(). 781 * If tight_format_check is true, only allow the resource_copy_region() if 782 * the blit src/dst formats are identical, ignoring the resource formats. 783 * Otherwise, check for format casting and compatibility. 784 */ 785boolean 786util_can_blit_via_copy_region(const struct pipe_blit_info *blit, 787 boolean tight_format_check) 788{ 789 const struct util_format_description *src_desc, *dst_desc; 790 791 src_desc = util_format_description(blit->src.resource->format); 792 dst_desc = util_format_description(blit->dst.resource->format); 793 794 if (tight_format_check) { 795 /* no format conversions allowed */ 796 if (blit->src.format != blit->dst.format) { 797 return FALSE; 798 } 799 } 800 else { 801 /* do loose format compatibility checking */ 802 if (blit->src.resource->format != blit->src.format || 803 blit->dst.resource->format != blit->dst.format || 804 !util_is_format_compatible(src_desc, dst_desc)) { 805 return FALSE; 806 } 807 } 808 809 unsigned mask = util_format_get_mask(blit->dst.format); 810 811 /* No masks, no filtering, no scissor, no blending */ 812 if ((blit->mask & mask) != mask || 813 blit->filter != PIPE_TEX_FILTER_NEAREST || 814 blit->scissor_enable || 815 blit->num_window_rectangles > 0 || 816 blit->alpha_blend) { 817 return FALSE; 818 } 819 820 /* Only the src box can have negative dims for flipping */ 821 assert(blit->dst.box.width >= 1); 822 assert(blit->dst.box.height >= 1); 823 assert(blit->dst.box.depth >= 1); 824 825 /* No scaling or flipping */ 826 if (blit->src.box.width != blit->dst.box.width || 827 blit->src.box.height != blit->dst.box.height || 828 blit->src.box.depth != blit->dst.box.depth) { 829 return FALSE; 830 } 831 832 /* No out-of-bounds access. */ 833 if (!is_box_inside_resource(blit->src.resource, &blit->src.box, 834 blit->src.level) || 835 !is_box_inside_resource(blit->dst.resource, &blit->dst.box, 836 blit->dst.level)) { 837 return FALSE; 838 } 839 840 /* Sample counts must match. */ 841 if (get_sample_count(blit->src.resource) != 842 get_sample_count(blit->dst.resource)) { 843 return FALSE; 844 } 845 846 return TRUE; 847} 848 849 850/** 851 * Try to do a blit using resource_copy_region. The function calls 852 * resource_copy_region if the blit description is compatible with it. 853 * 854 * It returns TRUE if the blit was done using resource_copy_region. 855 * 856 * It returns FALSE otherwise and the caller must fall back to a more generic 857 * codepath for the blit operation. (e.g. by using u_blitter) 858 */ 859boolean 860util_try_blit_via_copy_region(struct pipe_context *ctx, 861 const struct pipe_blit_info *blit) 862{ 863 if (util_can_blit_via_copy_region(blit, FALSE)) { 864 ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level, 865 blit->dst.box.x, blit->dst.box.y, 866 blit->dst.box.z, 867 blit->src.resource, blit->src.level, 868 &blit->src.box); 869 return TRUE; 870 } 871 else { 872 return FALSE; 873 } 874} 875