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