1 /************************************************************************** 2 * 3 * Copyright 2006 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 * Authors: 29 * Keith Whitwell <keithw (at) vmware.com> 30 * Michel Dnzer <daenzer (at) vmware.com> 31 */ 32 33 #include <stdio.h> 34 35 #include "pipe/p_context.h" 36 #include "pipe/p_defines.h" 37 38 #include "util/u_inlines.h" 39 #include "util/u_cpu_detect.h" 40 #include "util/u_format.h" 41 #include "util/u_math.h" 42 #include "util/u_memory.h" 43 #include "util/simple_list.h" 44 #include "util/u_transfer.h" 45 46 #include "lp_context.h" 47 #include "lp_flush.h" 48 #include "lp_screen.h" 49 #include "lp_texture.h" 50 #include "lp_setup.h" 51 #include "lp_state.h" 52 #include "lp_rast.h" 53 54 #include "state_tracker/sw_winsys.h" 55 56 57 #ifdef DEBUG 58 static struct llvmpipe_resource resource_list; 59 #endif 60 static unsigned id_counter = 0; 61 62 63 /** 64 * Conventional allocation path for non-display textures: 65 * Compute strides and allocate data (unless asked not to). 66 */ 67 static boolean 68 llvmpipe_texture_layout(struct llvmpipe_screen *screen, 69 struct llvmpipe_resource *lpr, 70 boolean allocate) 71 { 72 struct pipe_resource *pt = &lpr->base; 73 unsigned level; 74 unsigned width = pt->width0; 75 unsigned height = pt->height0; 76 unsigned depth = pt->depth0; 77 uint64_t total_size = 0; 78 unsigned layers = pt->array_size; 79 /* XXX: 80 * This alignment here (same for displaytarget) was added for the purpose of 81 * ARB_map_buffer_alignment. I am not convinced it's needed for non-buffer 82 * resources. Otherwise we'd want the max of cacheline size and 16 (max size 83 * of a block for all formats) though this should not be strictly necessary 84 * neither. In any case it can only affect compressed or 1d textures. 85 */ 86 unsigned mip_align = MAX2(64, util_cpu_caps.cacheline); 87 88 assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS); 89 assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS); 90 91 for (level = 0; level <= pt->last_level; level++) { 92 uint64_t mipsize; 93 unsigned align_x, align_y, nblocksx, nblocksy, block_size, num_slices; 94 95 /* Row stride and image stride */ 96 97 /* For non-compressed formats we need 4x4 pixel alignment 98 * so we can read/write LP_RASTER_BLOCK_SIZE when rendering to them. 99 * We also want cache line size in x direction, 100 * otherwise same cache line could end up in multiple threads. 101 * For explicit 1d resources however we reduce this to 4x1 and 102 * handle specially in render output code (as we need to do special 103 * handling there for buffers in any case). 104 */ 105 if (util_format_is_compressed(pt->format)) 106 align_x = align_y = 1; 107 else { 108 align_x = LP_RASTER_BLOCK_SIZE; 109 if (llvmpipe_resource_is_1d(&lpr->base)) 110 align_y = 1; 111 else 112 align_y = LP_RASTER_BLOCK_SIZE; 113 } 114 115 nblocksx = util_format_get_nblocksx(pt->format, 116 align(width, align_x)); 117 nblocksy = util_format_get_nblocksy(pt->format, 118 align(height, align_y)); 119 block_size = util_format_get_blocksize(pt->format); 120 121 if (util_format_is_compressed(pt->format)) 122 lpr->row_stride[level] = nblocksx * block_size; 123 else 124 lpr->row_stride[level] = align(nblocksx * block_size, util_cpu_caps.cacheline); 125 126 /* if row_stride * height > LP_MAX_TEXTURE_SIZE */ 127 if ((uint64_t)lpr->row_stride[level] * nblocksy > LP_MAX_TEXTURE_SIZE) { 128 /* image too large */ 129 goto fail; 130 } 131 132 lpr->img_stride[level] = lpr->row_stride[level] * nblocksy; 133 134 /* Number of 3D image slices, cube faces or texture array layers */ 135 if (lpr->base.target == PIPE_TEXTURE_CUBE) { 136 assert(layers == 6); 137 } 138 139 if (lpr->base.target == PIPE_TEXTURE_3D) 140 num_slices = depth; 141 else if (lpr->base.target == PIPE_TEXTURE_1D_ARRAY || 142 lpr->base.target == PIPE_TEXTURE_2D_ARRAY || 143 lpr->base.target == PIPE_TEXTURE_CUBE || 144 lpr->base.target == PIPE_TEXTURE_CUBE_ARRAY) 145 num_slices = layers; 146 else 147 num_slices = 1; 148 149 /* if img_stride * num_slices_faces > LP_MAX_TEXTURE_SIZE */ 150 mipsize = (uint64_t)lpr->img_stride[level] * num_slices; 151 if (mipsize > LP_MAX_TEXTURE_SIZE) { 152 /* volume too large */ 153 goto fail; 154 } 155 156 lpr->mip_offsets[level] = total_size; 157 158 total_size += align((unsigned)mipsize, mip_align); 159 if (total_size > LP_MAX_TEXTURE_SIZE) { 160 goto fail; 161 } 162 163 /* Compute size of next mipmap level */ 164 width = u_minify(width, 1); 165 height = u_minify(height, 1); 166 depth = u_minify(depth, 1); 167 } 168 169 if (allocate) { 170 lpr->tex_data = align_malloc(total_size, mip_align); 171 if (!lpr->tex_data) { 172 return FALSE; 173 } 174 else { 175 memset(lpr->tex_data, 0, total_size); 176 } 177 } 178 179 return TRUE; 180 181 fail: 182 return FALSE; 183 } 184 185 186 /** 187 * Check the size of the texture specified by 'res'. 188 * \return TRUE if OK, FALSE if too large. 189 */ 190 static boolean 191 llvmpipe_can_create_resource(struct pipe_screen *screen, 192 const struct pipe_resource *res) 193 { 194 struct llvmpipe_resource lpr; 195 memset(&lpr, 0, sizeof(lpr)); 196 lpr.base = *res; 197 return llvmpipe_texture_layout(llvmpipe_screen(screen), &lpr, false); 198 } 199 200 201 static boolean 202 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen, 203 struct llvmpipe_resource *lpr, 204 const void *map_front_private) 205 { 206 struct sw_winsys *winsys = screen->winsys; 207 208 /* Round up the surface size to a multiple of the tile size to 209 * avoid tile clipping. 210 */ 211 const unsigned width = MAX2(1, align(lpr->base.width0, TILE_SIZE)); 212 const unsigned height = MAX2(1, align(lpr->base.height0, TILE_SIZE)); 213 214 lpr->dt = winsys->displaytarget_create(winsys, 215 lpr->base.bind, 216 lpr->base.format, 217 width, height, 218 64, 219 map_front_private, 220 &lpr->row_stride[0] ); 221 222 if (lpr->dt == NULL) 223 return FALSE; 224 225 if (!map_front_private) { 226 void *map = winsys->displaytarget_map(winsys, lpr->dt, 227 PIPE_TRANSFER_WRITE); 228 229 if (map) 230 memset(map, 0, height * lpr->row_stride[0]); 231 232 winsys->displaytarget_unmap(winsys, lpr->dt); 233 } 234 235 return TRUE; 236 } 237 238 239 static struct pipe_resource * 240 llvmpipe_resource_create_front(struct pipe_screen *_screen, 241 const struct pipe_resource *templat, 242 const void *map_front_private) 243 { 244 struct llvmpipe_screen *screen = llvmpipe_screen(_screen); 245 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource); 246 if (!lpr) 247 return NULL; 248 249 lpr->base = *templat; 250 pipe_reference_init(&lpr->base.reference, 1); 251 lpr->base.screen = &screen->base; 252 253 /* assert(lpr->base.bind); */ 254 255 if (llvmpipe_resource_is_texture(&lpr->base)) { 256 if (lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET | 257 PIPE_BIND_SCANOUT | 258 PIPE_BIND_SHARED)) { 259 /* displayable surface */ 260 if (!llvmpipe_displaytarget_layout(screen, lpr, map_front_private)) 261 goto fail; 262 } 263 else { 264 /* texture map */ 265 if (!llvmpipe_texture_layout(screen, lpr, true)) 266 goto fail; 267 } 268 } 269 else { 270 /* other data (vertex buffer, const buffer, etc) */ 271 const uint bytes = templat->width0; 272 assert(util_format_get_blocksize(templat->format) == 1); 273 assert(templat->height0 == 1); 274 assert(templat->depth0 == 1); 275 assert(templat->last_level == 0); 276 /* 277 * Reserve some extra storage since if we'd render to a buffer we 278 * read/write always LP_RASTER_BLOCK_SIZE pixels, but the element 279 * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE. 280 */ 281 lpr->data = align_malloc(bytes + (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float), 64); 282 283 /* 284 * buffers don't really have stride but it's probably safer 285 * (for code doing same calculations for buffers and textures) 286 * to put something sane in there. 287 */ 288 lpr->row_stride[0] = bytes; 289 if (!lpr->data) 290 goto fail; 291 memset(lpr->data, 0, bytes); 292 } 293 294 lpr->id = id_counter++; 295 296 #ifdef DEBUG 297 insert_at_tail(&resource_list, lpr); 298 #endif 299 300 return &lpr->base; 301 302 fail: 303 FREE(lpr); 304 return NULL; 305 } 306 307 308 static struct pipe_resource * 309 llvmpipe_resource_create(struct pipe_screen *_screen, 310 const struct pipe_resource *templat) 311 { 312 return llvmpipe_resource_create_front(_screen, templat, NULL); 313 } 314 315 316 static void 317 llvmpipe_resource_destroy(struct pipe_screen *pscreen, 318 struct pipe_resource *pt) 319 { 320 struct llvmpipe_screen *screen = llvmpipe_screen(pscreen); 321 struct llvmpipe_resource *lpr = llvmpipe_resource(pt); 322 323 if (lpr->dt) { 324 /* display target */ 325 struct sw_winsys *winsys = screen->winsys; 326 winsys->displaytarget_destroy(winsys, lpr->dt); 327 } 328 else if (llvmpipe_resource_is_texture(pt)) { 329 /* free linear image data */ 330 if (lpr->tex_data) { 331 align_free(lpr->tex_data); 332 lpr->tex_data = NULL; 333 } 334 } 335 else if (!lpr->userBuffer) { 336 assert(lpr->data); 337 align_free(lpr->data); 338 } 339 340 #ifdef DEBUG 341 if (lpr->next) 342 remove_from_list(lpr); 343 #endif 344 345 FREE(lpr); 346 } 347 348 349 /** 350 * Map a resource for read/write. 351 */ 352 void * 353 llvmpipe_resource_map(struct pipe_resource *resource, 354 unsigned level, 355 unsigned layer, 356 enum lp_texture_usage tex_usage) 357 { 358 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 359 uint8_t *map; 360 361 assert(level < LP_MAX_TEXTURE_LEVELS); 362 assert(layer < (u_minify(resource->depth0, level) + resource->array_size - 1)); 363 364 assert(tex_usage == LP_TEX_USAGE_READ || 365 tex_usage == LP_TEX_USAGE_READ_WRITE || 366 tex_usage == LP_TEX_USAGE_WRITE_ALL); 367 368 if (lpr->dt) { 369 /* display target */ 370 struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen); 371 struct sw_winsys *winsys = screen->winsys; 372 unsigned dt_usage; 373 374 if (tex_usage == LP_TEX_USAGE_READ) { 375 dt_usage = PIPE_TRANSFER_READ; 376 } 377 else { 378 dt_usage = PIPE_TRANSFER_READ_WRITE; 379 } 380 381 assert(level == 0); 382 assert(layer == 0); 383 384 /* FIXME: keep map count? */ 385 map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage); 386 387 /* install this linear image in texture data structure */ 388 lpr->tex_data = map; 389 390 return map; 391 } 392 else if (llvmpipe_resource_is_texture(resource)) { 393 394 map = llvmpipe_get_texture_image_address(lpr, layer, level); 395 return map; 396 } 397 else { 398 return lpr->data; 399 } 400 } 401 402 403 /** 404 * Unmap a resource. 405 */ 406 void 407 llvmpipe_resource_unmap(struct pipe_resource *resource, 408 unsigned level, 409 unsigned layer) 410 { 411 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 412 413 if (lpr->dt) { 414 /* display target */ 415 struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen); 416 struct sw_winsys *winsys = lp_screen->winsys; 417 418 assert(level == 0); 419 assert(layer == 0); 420 421 winsys->displaytarget_unmap(winsys, lpr->dt); 422 } 423 } 424 425 426 void * 427 llvmpipe_resource_data(struct pipe_resource *resource) 428 { 429 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 430 431 assert(!llvmpipe_resource_is_texture(resource)); 432 433 return lpr->data; 434 } 435 436 437 static struct pipe_resource * 438 llvmpipe_resource_from_handle(struct pipe_screen *screen, 439 const struct pipe_resource *template, 440 struct winsys_handle *whandle, 441 unsigned usage) 442 { 443 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys; 444 struct llvmpipe_resource *lpr; 445 446 /* XXX Seems like from_handled depth textures doesn't work that well */ 447 448 lpr = CALLOC_STRUCT(llvmpipe_resource); 449 if (!lpr) { 450 goto no_lpr; 451 } 452 453 lpr->base = *template; 454 pipe_reference_init(&lpr->base.reference, 1); 455 lpr->base.screen = screen; 456 457 /* 458 * Looks like unaligned displaytargets work just fine, 459 * at least sampler/render ones. 460 */ 461 #if 0 462 assert(lpr->base.width0 == width); 463 assert(lpr->base.height0 == height); 464 #endif 465 466 lpr->dt = winsys->displaytarget_from_handle(winsys, 467 template, 468 whandle, 469 &lpr->row_stride[0]); 470 if (!lpr->dt) { 471 goto no_dt; 472 } 473 474 lpr->id = id_counter++; 475 476 #ifdef DEBUG 477 insert_at_tail(&resource_list, lpr); 478 #endif 479 480 return &lpr->base; 481 482 no_dt: 483 FREE(lpr); 484 no_lpr: 485 return NULL; 486 } 487 488 489 static boolean 490 llvmpipe_resource_get_handle(struct pipe_screen *screen, 491 struct pipe_context *ctx, 492 struct pipe_resource *pt, 493 struct winsys_handle *whandle, 494 unsigned usage) 495 { 496 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys; 497 struct llvmpipe_resource *lpr = llvmpipe_resource(pt); 498 499 assert(lpr->dt); 500 if (!lpr->dt) 501 return FALSE; 502 503 return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle); 504 } 505 506 507 static void * 508 llvmpipe_transfer_map( struct pipe_context *pipe, 509 struct pipe_resource *resource, 510 unsigned level, 511 unsigned usage, 512 const struct pipe_box *box, 513 struct pipe_transfer **transfer ) 514 { 515 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); 516 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); 517 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 518 struct llvmpipe_transfer *lpt; 519 struct pipe_transfer *pt; 520 ubyte *map; 521 enum pipe_format format; 522 enum lp_texture_usage tex_usage; 523 const char *mode; 524 525 assert(resource); 526 assert(level <= resource->last_level); 527 528 /* 529 * Transfers, like other pipe operations, must happen in order, so flush the 530 * context if necessary. 531 */ 532 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 533 boolean read_only = !(usage & PIPE_TRANSFER_WRITE); 534 boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK); 535 if (!llvmpipe_flush_resource(pipe, resource, 536 level, 537 read_only, 538 TRUE, /* cpu_access */ 539 do_not_block, 540 __FUNCTION__)) { 541 /* 542 * It would have blocked, but state tracker requested no to. 543 */ 544 assert(do_not_block); 545 return NULL; 546 } 547 } 548 549 /* Check if we're mapping a current constant buffer */ 550 if ((usage & PIPE_TRANSFER_WRITE) && 551 (resource->bind & PIPE_BIND_CONSTANT_BUFFER)) { 552 unsigned i; 553 for (i = 0; i < ARRAY_SIZE(llvmpipe->constants[PIPE_SHADER_FRAGMENT]); ++i) { 554 if (resource == llvmpipe->constants[PIPE_SHADER_FRAGMENT][i].buffer) { 555 /* constants may have changed */ 556 llvmpipe->dirty |= LP_NEW_FS_CONSTANTS; 557 break; 558 } 559 } 560 } 561 562 lpt = CALLOC_STRUCT(llvmpipe_transfer); 563 if (!lpt) 564 return NULL; 565 pt = &lpt->base; 566 pipe_resource_reference(&pt->resource, resource); 567 pt->box = *box; 568 pt->level = level; 569 pt->stride = lpr->row_stride[level]; 570 pt->layer_stride = lpr->img_stride[level]; 571 pt->usage = usage; 572 *transfer = pt; 573 574 assert(level < LP_MAX_TEXTURE_LEVELS); 575 576 /* 577 printf("tex_transfer_map(%d, %d %d x %d of %d x %d, usage %d )\n", 578 transfer->x, transfer->y, transfer->width, transfer->height, 579 transfer->texture->width0, 580 transfer->texture->height0, 581 transfer->usage); 582 */ 583 584 if (usage == PIPE_TRANSFER_READ) { 585 tex_usage = LP_TEX_USAGE_READ; 586 mode = "read"; 587 } 588 else { 589 tex_usage = LP_TEX_USAGE_READ_WRITE; 590 mode = "read/write"; 591 } 592 593 if (0) { 594 printf("transfer map tex %u mode %s\n", lpr->id, mode); 595 } 596 597 format = lpr->base.format; 598 599 map = llvmpipe_resource_map(resource, 600 level, 601 box->z, 602 tex_usage); 603 604 605 /* May want to do different things here depending on read/write nature 606 * of the map: 607 */ 608 if (usage & PIPE_TRANSFER_WRITE) { 609 /* Do something to notify sharing contexts of a texture change. 610 */ 611 screen->timestamp++; 612 } 613 614 map += 615 box->y / util_format_get_blockheight(format) * pt->stride + 616 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 617 618 return map; 619 } 620 621 622 static void 623 llvmpipe_transfer_unmap(struct pipe_context *pipe, 624 struct pipe_transfer *transfer) 625 { 626 assert(transfer->resource); 627 628 llvmpipe_resource_unmap(transfer->resource, 629 transfer->level, 630 transfer->box.z); 631 632 /* Effectively do the texture_update work here - if texture images 633 * needed post-processing to put them into hardware layout, this is 634 * where it would happen. For llvmpipe, nothing to do. 635 */ 636 assert (transfer->resource); 637 pipe_resource_reference(&transfer->resource, NULL); 638 FREE(transfer); 639 } 640 641 unsigned int 642 llvmpipe_is_resource_referenced( struct pipe_context *pipe, 643 struct pipe_resource *presource, 644 unsigned level) 645 { 646 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 647 if (!(presource->bind & (PIPE_BIND_DEPTH_STENCIL | 648 PIPE_BIND_RENDER_TARGET | 649 PIPE_BIND_SAMPLER_VIEW))) 650 return LP_UNREFERENCED; 651 652 return lp_setup_is_resource_referenced(llvmpipe->setup, presource); 653 } 654 655 656 /** 657 * Returns the largest possible alignment for a format in llvmpipe 658 */ 659 unsigned 660 llvmpipe_get_format_alignment( enum pipe_format format ) 661 { 662 const struct util_format_description *desc = util_format_description(format); 663 unsigned size = 0; 664 unsigned bytes; 665 unsigned i; 666 667 for (i = 0; i < desc->nr_channels; ++i) { 668 size += desc->channel[i].size; 669 } 670 671 bytes = size / 8; 672 673 if (!util_is_power_of_two(bytes)) { 674 bytes /= desc->nr_channels; 675 } 676 677 if (bytes % 2 || bytes < 1) { 678 return 1; 679 } else { 680 return bytes; 681 } 682 } 683 684 685 /** 686 * Create buffer which wraps user-space data. 687 * XXX unreachable. 688 */ 689 struct pipe_resource * 690 llvmpipe_user_buffer_create(struct pipe_screen *screen, 691 void *ptr, 692 unsigned bytes, 693 unsigned bind_flags) 694 { 695 struct llvmpipe_resource *buffer; 696 697 buffer = CALLOC_STRUCT(llvmpipe_resource); 698 if (!buffer) 699 return NULL; 700 701 pipe_reference_init(&buffer->base.reference, 1); 702 buffer->base.screen = screen; 703 buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */ 704 buffer->base.bind = bind_flags; 705 buffer->base.usage = PIPE_USAGE_IMMUTABLE; 706 buffer->base.flags = 0; 707 buffer->base.width0 = bytes; 708 buffer->base.height0 = 1; 709 buffer->base.depth0 = 1; 710 buffer->base.array_size = 1; 711 buffer->userBuffer = TRUE; 712 buffer->data = ptr; 713 714 return &buffer->base; 715 } 716 717 718 /** 719 * Compute size (in bytes) need to store a texture image / mipmap level, 720 * for just one cube face, one array layer or one 3D texture slice 721 */ 722 static unsigned 723 tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level) 724 { 725 return lpr->img_stride[level]; 726 } 727 728 729 /** 730 * Return pointer to a 2D texture image/face/slice. 731 * No tiled/linear conversion is done. 732 */ 733 ubyte * 734 llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr, 735 unsigned face_slice, unsigned level) 736 { 737 unsigned offset; 738 739 assert(llvmpipe_resource_is_texture(&lpr->base)); 740 741 offset = lpr->mip_offsets[level]; 742 743 if (face_slice > 0) 744 offset += face_slice * tex_image_face_size(lpr, level); 745 746 return (ubyte *) lpr->tex_data + offset; 747 } 748 749 750 /** 751 * Return size of resource in bytes 752 */ 753 unsigned 754 llvmpipe_resource_size(const struct pipe_resource *resource) 755 { 756 const struct llvmpipe_resource *lpr = llvmpipe_resource_const(resource); 757 unsigned size = 0; 758 759 if (llvmpipe_resource_is_texture(resource)) { 760 /* Note this will always return 0 for displaytarget resources */ 761 size = lpr->total_alloc_size; 762 } 763 else { 764 size = resource->width0; 765 } 766 return size; 767 } 768 769 770 #ifdef DEBUG 771 void 772 llvmpipe_print_resources(void) 773 { 774 struct llvmpipe_resource *lpr; 775 unsigned n = 0, total = 0; 776 777 debug_printf("LLVMPIPE: current resources:\n"); 778 foreach(lpr, &resource_list) { 779 unsigned size = llvmpipe_resource_size(&lpr->base); 780 debug_printf("resource %u at %p, size %ux%ux%u: %u bytes, refcount %u\n", 781 lpr->id, (void *) lpr, 782 lpr->base.width0, lpr->base.height0, lpr->base.depth0, 783 size, lpr->base.reference.count); 784 total += size; 785 n++; 786 } 787 debug_printf("LLVMPIPE: total size of %u resources: %u\n", n, total); 788 } 789 #endif 790 791 792 void 793 llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen) 794 { 795 #ifdef DEBUG 796 /* init linked list for tracking resources */ 797 { 798 static boolean first_call = TRUE; 799 if (first_call) { 800 memset(&resource_list, 0, sizeof(resource_list)); 801 make_empty_list(&resource_list); 802 first_call = FALSE; 803 } 804 } 805 #endif 806 807 screen->resource_create = llvmpipe_resource_create; 808 /* screen->resource_create_front = llvmpipe_resource_create_front; */ 809 screen->resource_destroy = llvmpipe_resource_destroy; 810 screen->resource_from_handle = llvmpipe_resource_from_handle; 811 screen->resource_get_handle = llvmpipe_resource_get_handle; 812 screen->can_create_resource = llvmpipe_can_create_resource; 813 } 814 815 816 void 817 llvmpipe_init_context_resource_funcs(struct pipe_context *pipe) 818 { 819 pipe->transfer_map = llvmpipe_transfer_map; 820 pipe->transfer_unmap = llvmpipe_transfer_unmap; 821 822 pipe->transfer_flush_region = u_default_transfer_flush_region; 823 pipe->buffer_subdata = u_default_buffer_subdata; 824 pipe->texture_subdata = u_default_texture_subdata; 825 } 826