lp_texture.c revision 08e443a1c8218e43dcd953859843d95d9020a892
1/************************************************************************** 2 * 3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. 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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.com> 30 * Michel Dänzer <michel@tungstengraphics.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_format.h" 40#include "util/u_math.h" 41#include "util/u_memory.h" 42#include "util/u_simple_list.h" 43#include "util/u_transfer.h" 44 45#include "lp_context.h" 46#include "lp_flush.h" 47#include "lp_screen.h" 48#include "lp_tile_image.h" 49#include "lp_texture.h" 50#include "lp_setup.h" 51 52#include "state_tracker/sw_winsys.h" 53 54 55#ifdef DEBUG 56static struct llvmpipe_resource resource_list; 57#endif 58 59 60static INLINE boolean 61resource_is_texture(const struct pipe_resource *resource) 62{ 63 switch (resource->target) { 64 case PIPE_BUFFER: 65 return FALSE; 66 case PIPE_TEXTURE_1D: 67 case PIPE_TEXTURE_2D: 68 case PIPE_TEXTURE_3D: 69 case PIPE_TEXTURE_CUBE: 70 return TRUE; 71 default: 72 assert(0); 73 return FALSE; 74 } 75} 76 77 78 79/** 80 * Allocate storage for llvmpipe_texture::layout array. 81 * The number of elements is width_in_tiles * height_in_tiles. 82 */ 83static enum lp_texture_layout * 84alloc_layout_array(unsigned num_slices, unsigned width, unsigned height) 85{ 86 const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE; 87 const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE; 88 89 assert(num_slices * tx * ty > 0); 90 assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */ 91 92 return (enum lp_texture_layout *) 93 CALLOC(num_slices * tx * ty, sizeof(enum lp_texture_layout)); 94} 95 96 97 98/** 99 * Conventional allocation path for non-display textures: 100 * Just compute row strides here. Storage is allocated on demand later. 101 */ 102static boolean 103llvmpipe_texture_layout(struct llvmpipe_screen *screen, 104 struct llvmpipe_resource *lpr) 105{ 106 struct pipe_resource *pt = &lpr->base; 107 unsigned level; 108 unsigned width = pt->width0; 109 unsigned height = pt->height0; 110 unsigned depth = pt->depth0; 111 112 assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS); 113 assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS); 114 115 for (level = 0; level <= pt->last_level; level++) { 116 117 /* Row stride and image stride (for linear layout) */ 118 { 119 unsigned alignment, nblocksx, nblocksy, block_size; 120 121 /* For non-compressed formats we need to align the texture size 122 * to the tile size to facilitate render-to-texture. 123 */ 124 if (util_format_is_compressed(pt->format)) 125 alignment = 1; 126 else 127 alignment = TILE_SIZE; 128 129 nblocksx = util_format_get_nblocksx(pt->format, 130 align(width, alignment)); 131 nblocksy = util_format_get_nblocksy(pt->format, 132 align(height, alignment)); 133 block_size = util_format_get_blocksize(pt->format); 134 135 lpr->row_stride[level] = align(nblocksx * block_size, 16); 136 137 lpr->img_stride[level] = lpr->row_stride[level] * nblocksy; 138 } 139 140 /* Size of the image in tiles (for tiled layout) */ 141 { 142 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE; 143 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE; 144 lpr->tiles_per_row[level] = width_t; 145 lpr->tiles_per_image[level] = width_t * height_t; 146 } 147 148 /* Number of 3D image slices or cube faces */ 149 { 150 unsigned num_slices; 151 152 if (lpr->base.target == PIPE_TEXTURE_CUBE) 153 num_slices = 6; 154 else if (lpr->base.target == PIPE_TEXTURE_3D) 155 num_slices = depth; 156 else 157 num_slices = 1; 158 159 lpr->num_slices_faces[level] = num_slices; 160 161 lpr->layout[level] = alloc_layout_array(num_slices, width, height); 162 } 163 164 /* Compute size of next mipmap level */ 165 width = u_minify(width, 1); 166 height = u_minify(height, 1); 167 depth = u_minify(depth, 1); 168 } 169 170 return TRUE; 171} 172 173 174 175static boolean 176llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen, 177 struct llvmpipe_resource *lpr) 178{ 179 struct sw_winsys *winsys = screen->winsys; 180 181 /* Round up the surface size to a multiple of the tile size to 182 * avoid tile clipping. 183 */ 184 const unsigned width = align(lpr->base.width0, TILE_SIZE); 185 const unsigned height = align(lpr->base.height0, TILE_SIZE); 186 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE; 187 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE; 188 189 lpr->tiles_per_row[0] = width_t; 190 lpr->tiles_per_image[0] = width_t * height_t; 191 lpr->num_slices_faces[0] = 1; 192 lpr->img_stride[0] = 0; 193 194 lpr->layout[0] = alloc_layout_array(1, width, height); 195 //lpr->layout[0][0] = LP_TEX_LAYOUT_LINEAR; 196 197 lpr->dt = winsys->displaytarget_create(winsys, 198 lpr->base.bind, 199 lpr->base.format, 200 width, height, 201 16, 202 &lpr->row_stride[0] ); 203 204 return lpr->dt != NULL; 205} 206 207 208static struct pipe_resource * 209llvmpipe_resource_create(struct pipe_screen *_screen, 210 const struct pipe_resource *templat) 211{ 212 static unsigned id_counter = 0; 213 struct llvmpipe_screen *screen = llvmpipe_screen(_screen); 214 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource); 215 if (!lpr) 216 return NULL; 217 218 lpr->base = *templat; 219 pipe_reference_init(&lpr->base.reference, 1); 220 lpr->base.screen = &screen->base; 221 222 assert(lpr->base.bind); 223 224 if (resource_is_texture(&lpr->base)) { 225 if (lpr->base.bind & PIPE_BIND_DISPLAY_TARGET) { 226 /* displayable surface */ 227 if (!llvmpipe_displaytarget_layout(screen, lpr)) 228 goto fail; 229 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE); 230 } 231 else { 232 /* texture map */ 233 if (!llvmpipe_texture_layout(screen, lpr)) 234 goto fail; 235 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE); 236 } 237 assert(lpr->layout[0]); 238 } 239 else { 240 /* other data (vertex buffer, const buffer, etc) */ 241 const enum pipe_format format = templat->format; 242 const uint w = templat->width0 / util_format_get_blockheight(format); 243 const uint h = templat->height0 / util_format_get_blockwidth(format); 244 const uint d = templat->depth0; 245 const uint bpp = util_format_get_blocksize(format); 246 const uint bytes = w * h * d * bpp; 247 lpr->data = align_malloc(bytes, 16); 248 if (!lpr->data) 249 goto fail; 250 } 251 252 lpr->id = id_counter++; 253 254#ifdef DEBUG 255 insert_at_tail(&resource_list, lpr); 256#endif 257 258 return &lpr->base; 259 260 fail: 261 FREE(lpr); 262 return NULL; 263} 264 265 266static void 267llvmpipe_resource_destroy(struct pipe_screen *pscreen, 268 struct pipe_resource *pt) 269{ 270 struct llvmpipe_screen *screen = llvmpipe_screen(pscreen); 271 struct llvmpipe_resource *lpr = llvmpipe_resource(pt); 272 273 if (lpr->dt) { 274 /* display target */ 275 struct sw_winsys *winsys = screen->winsys; 276 winsys->displaytarget_destroy(winsys, lpr->dt); 277 278 if (lpr->tiled[0].data) { 279 align_free(lpr->tiled[0].data); 280 lpr->tiled[0].data = NULL; 281 } 282 283 FREE(lpr->layout[0]); 284 } 285 else if (resource_is_texture(pt)) { 286 /* regular texture */ 287 uint level; 288 289 /* free linear image data */ 290 for (level = 0; level < Elements(lpr->linear); level++) { 291 if (lpr->linear[level].data) { 292 align_free(lpr->linear[level].data); 293 lpr->linear[level].data = NULL; 294 } 295 } 296 297 /* free tiled image data */ 298 for (level = 0; level < Elements(lpr->tiled); level++) { 299 if (lpr->tiled[level].data) { 300 align_free(lpr->tiled[level].data); 301 lpr->tiled[level].data = NULL; 302 } 303 } 304 305 /* free layout flag arrays */ 306 for (level = 0; level < Elements(lpr->tiled); level++) { 307 FREE(lpr->layout[level]); 308 lpr->layout[level] = NULL; 309 } 310 } 311 else if (!lpr->userBuffer) { 312 assert(lpr->data); 313 align_free(lpr->data); 314 } 315 316#ifdef DEBUG 317 if (lpr->next) 318 remove_from_list(lpr); 319#endif 320 321 FREE(lpr); 322} 323 324 325/** 326 * Map a resource for read/write. 327 */ 328void * 329llvmpipe_resource_map(struct pipe_resource *resource, 330 unsigned face, 331 unsigned level, 332 unsigned zslice, 333 enum lp_texture_usage tex_usage, 334 enum lp_texture_layout layout) 335{ 336 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 337 uint8_t *map; 338 339 assert(face < 6); 340 assert(level < LP_MAX_TEXTURE_LEVELS); 341 342 assert(tex_usage == LP_TEX_USAGE_READ || 343 tex_usage == LP_TEX_USAGE_READ_WRITE || 344 tex_usage == LP_TEX_USAGE_WRITE_ALL); 345 346 assert(layout == LP_TEX_LAYOUT_NONE || 347 layout == LP_TEX_LAYOUT_TILED || 348 layout == LP_TEX_LAYOUT_LINEAR); 349 350 if (lpr->dt) { 351 /* display target */ 352 struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen); 353 struct sw_winsys *winsys = screen->winsys; 354 unsigned dt_usage; 355 uint8_t *map2; 356 357 if (tex_usage == LP_TEX_USAGE_READ) { 358 dt_usage = PIPE_TRANSFER_READ; 359 } 360 else { 361 dt_usage = PIPE_TRANSFER_READ_WRITE; 362 } 363 364 assert(face == 0); 365 assert(level == 0); 366 assert(zslice == 0); 367 368 /* FIXME: keep map count? */ 369 map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage); 370 371 /* install this linear image in texture data structure */ 372 lpr->linear[level].data = map; 373 374 /* make sure tiled data gets converted to linear data */ 375 map2 = llvmpipe_get_texture_image(lpr, 0, 0, tex_usage, layout); 376 if (layout == LP_TEX_LAYOUT_LINEAR) 377 assert(map == map2); 378 379 return map2; 380 } 381 else if (resource_is_texture(resource)) { 382 /* regular texture */ 383 if (resource->target != PIPE_TEXTURE_CUBE) { 384 assert(face == 0); 385 } 386 if (resource->target != PIPE_TEXTURE_3D) { 387 assert(zslice == 0); 388 } 389 390 map = llvmpipe_get_texture_image(lpr, face + zslice, level, 391 tex_usage, layout); 392 assert(map); 393 return map; 394 } 395 else { 396 return lpr->data; 397 } 398} 399 400 401/** 402 * Unmap a resource. 403 */ 404void 405llvmpipe_resource_unmap(struct pipe_resource *resource, 406 unsigned face, 407 unsigned level, 408 unsigned zslice) 409{ 410 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 411 412 if (lpr->dt) { 413 /* display target */ 414 struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen); 415 struct sw_winsys *winsys = lp_screen->winsys; 416 417 assert(face == 0); 418 assert(level == 0); 419 assert(zslice == 0); 420 421 /* make sure linear image is up to date */ 422 (void) llvmpipe_get_texture_image(lpr, face + zslice, level, 423 LP_TEX_USAGE_READ, 424 LP_TEX_LAYOUT_LINEAR); 425 426 winsys->displaytarget_unmap(winsys, lpr->dt); 427 } 428} 429 430 431void * 432llvmpipe_resource_data(struct pipe_resource *resource) 433{ 434 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 435 436 assert(!resource_is_texture(resource)); 437 438 return lpr->data; 439} 440 441 442static struct pipe_resource * 443llvmpipe_resource_from_handle(struct pipe_screen *screen, 444 const struct pipe_resource *template, 445 struct winsys_handle *whandle) 446{ 447 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys; 448 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource); 449 if (!lpr) 450 return NULL; 451 452 lpr->base = *template; 453 pipe_reference_init(&lpr->base.reference, 1); 454 lpr->base.screen = screen; 455 456 lpr->dt = winsys->displaytarget_from_handle(winsys, 457 template, 458 whandle, 459 &lpr->row_stride[0]); 460 if (!lpr->dt) 461 goto fail; 462 463 return &lpr->base; 464 465 fail: 466 FREE(lpr); 467 return NULL; 468} 469 470 471static boolean 472llvmpipe_resource_get_handle(struct pipe_screen *screen, 473 struct pipe_resource *pt, 474 struct winsys_handle *whandle) 475{ 476 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys; 477 struct llvmpipe_resource *lpr = llvmpipe_resource(pt); 478 479 assert(lpr->dt); 480 if (!lpr->dt) 481 return FALSE; 482 483 return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle); 484} 485 486 487static struct pipe_surface * 488llvmpipe_get_tex_surface(struct pipe_screen *screen, 489 struct pipe_resource *pt, 490 unsigned face, unsigned level, unsigned zslice, 491 unsigned usage) 492{ 493 struct pipe_surface *ps; 494 495 assert(level <= pt->last_level); 496 497 ps = CALLOC_STRUCT(pipe_surface); 498 if (ps) { 499 pipe_reference_init(&ps->reference, 1); 500 pipe_resource_reference(&ps->texture, pt); 501 ps->format = pt->format; 502 ps->width = u_minify(pt->width0, level); 503 ps->height = u_minify(pt->height0, level); 504 ps->usage = usage; 505 506 ps->face = face; 507 ps->level = level; 508 ps->zslice = zslice; 509 } 510 return ps; 511} 512 513 514static void 515llvmpipe_tex_surface_destroy(struct pipe_surface *surf) 516{ 517 /* Effectively do the texture_update work here - if texture images 518 * needed post-processing to put them into hardware layout, this is 519 * where it would happen. For llvmpipe, nothing to do. 520 */ 521 assert(surf->texture); 522 pipe_resource_reference(&surf->texture, NULL); 523 FREE(surf); 524} 525 526 527static struct pipe_transfer * 528llvmpipe_get_transfer(struct pipe_context *pipe, 529 struct pipe_resource *resource, 530 struct pipe_subresource sr, 531 unsigned usage, 532 const struct pipe_box *box) 533{ 534 struct llvmpipe_resource *lprex = llvmpipe_resource(resource); 535 struct llvmpipe_transfer *lpr; 536 537 assert(resource); 538 assert(sr.level <= resource->last_level); 539 540 /* 541 * Transfers, like other pipe operations, must happen in order, so flush the 542 * context if necessary. 543 */ 544 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 545 boolean read_only = !(usage & PIPE_TRANSFER_WRITE); 546 boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK); 547 if (!llvmpipe_flush_resource(pipe, resource, 548 sr.face, sr.level, 549 0, /* flush_flags */ 550 read_only, 551 TRUE, /* cpu_access */ 552 do_not_block)) { 553 /* 554 * It would have blocked, but state tracker requested no to. 555 */ 556 assert(do_not_block); 557 return NULL; 558 } 559 } 560 561 lpr = CALLOC_STRUCT(llvmpipe_transfer); 562 if (lpr) { 563 struct pipe_transfer *pt = &lpr->base; 564 pipe_resource_reference(&pt->resource, resource); 565 pt->box = *box; 566 pt->sr = sr; 567 pt->stride = lprex->row_stride[sr.level]; 568 pt->usage = usage; 569 570 return pt; 571 } 572 return NULL; 573} 574 575 576static void 577llvmpipe_transfer_destroy(struct pipe_context *pipe, 578 struct pipe_transfer *transfer) 579{ 580 /* Effectively do the texture_update work here - if texture images 581 * needed post-processing to put them into hardware layout, this is 582 * where it would happen. For llvmpipe, nothing to do. 583 */ 584 assert (transfer->resource); 585 pipe_resource_reference(&transfer->resource, NULL); 586 FREE(transfer); 587} 588 589 590static void * 591llvmpipe_transfer_map( struct pipe_context *pipe, 592 struct pipe_transfer *transfer ) 593{ 594 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); 595 ubyte *map; 596 struct llvmpipe_resource *lpr; 597 enum pipe_format format; 598 enum lp_texture_usage tex_usage; 599 const char *mode; 600 601 assert(transfer->sr.face < 6); 602 assert(transfer->sr.level < LP_MAX_TEXTURE_LEVELS); 603 604 /* 605 printf("tex_transfer_map(%d, %d %d x %d of %d x %d, usage %d )\n", 606 transfer->x, transfer->y, transfer->width, transfer->height, 607 transfer->texture->width0, 608 transfer->texture->height0, 609 transfer->usage); 610 */ 611 612 if (transfer->usage == PIPE_TRANSFER_READ) { 613 tex_usage = LP_TEX_USAGE_READ; 614 mode = "read"; 615 } 616 else { 617 tex_usage = LP_TEX_USAGE_READ_WRITE; 618 mode = "read/write"; 619 } 620 621 if (0) { 622 struct llvmpipe_resource *lpr = llvmpipe_resource(transfer->resource); 623 printf("transfer map tex %u mode %s\n", lpr->id, mode); 624 } 625 626 627 assert(transfer->resource); 628 lpr = llvmpipe_resource(transfer->resource); 629 format = lpr->base.format; 630 631 map = llvmpipe_resource_map(transfer->resource, 632 transfer->sr.face, 633 transfer->sr.level, 634 transfer->box.z, 635 tex_usage, LP_TEX_LAYOUT_LINEAR); 636 637 638 /* May want to do different things here depending on read/write nature 639 * of the map: 640 */ 641 if (transfer->usage & PIPE_TRANSFER_WRITE) { 642 /* Do something to notify sharing contexts of a texture change. 643 */ 644 screen->timestamp++; 645 } 646 647 map += 648 transfer->box.y / util_format_get_blockheight(format) * transfer->stride + 649 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 650 651 return map; 652} 653 654 655static void 656llvmpipe_transfer_unmap(struct pipe_context *pipe, 657 struct pipe_transfer *transfer) 658{ 659 assert(transfer->resource); 660 661 llvmpipe_resource_unmap(transfer->resource, 662 transfer->sr.face, 663 transfer->sr.level, 664 transfer->box.z); 665} 666 667static unsigned int 668llvmpipe_is_resource_referenced( struct pipe_context *pipe, 669 struct pipe_resource *presource, 670 unsigned face, unsigned level) 671{ 672 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 673 674 if (presource->target == PIPE_BUFFER) 675 return PIPE_UNREFERENCED; 676 677 return lp_setup_is_resource_referenced(llvmpipe->setup, presource); 678} 679 680 681 682/** 683 * Create buffer which wraps user-space data. 684 */ 685static struct pipe_resource * 686llvmpipe_user_buffer_create(struct pipe_screen *screen, 687 void *ptr, 688 unsigned bytes, 689 unsigned bind_flags) 690{ 691 struct llvmpipe_resource *buffer; 692 693 buffer = CALLOC_STRUCT(llvmpipe_resource); 694 if(!buffer) 695 return NULL; 696 697 pipe_reference_init(&buffer->base.reference, 1); 698 buffer->base.screen = screen; 699 buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */ 700 buffer->base.bind = bind_flags; 701 buffer->base.usage = PIPE_USAGE_IMMUTABLE; 702 buffer->base.flags = 0; 703 buffer->base.width0 = bytes; 704 buffer->base.height0 = 1; 705 buffer->base.depth0 = 1; 706 buffer->userBuffer = TRUE; 707 buffer->data = ptr; 708 709 return &buffer->base; 710} 711 712 713/** 714 * Compute size (in bytes) need to store a texture image / mipmap level, 715 * for just one cube face or one 3D texture slice 716 */ 717static unsigned 718tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level, 719 enum lp_texture_layout layout) 720{ 721 const unsigned width = u_minify(lpr->base.width0, level); 722 const unsigned height = u_minify(lpr->base.height0, level); 723 724 assert(layout == LP_TEX_LAYOUT_TILED || 725 layout == LP_TEX_LAYOUT_LINEAR); 726 727 if (layout == LP_TEX_LAYOUT_TILED) { 728 /* for tiled layout, force a 32bpp format */ 729 const enum pipe_format format = PIPE_FORMAT_B8G8R8A8_UNORM; 730 const unsigned block_size = util_format_get_blocksize(format); 731 const unsigned nblocksy = 732 util_format_get_nblocksy(format, align(height, TILE_SIZE)); 733 const unsigned nblocksx = 734 util_format_get_nblocksx(format, align(width, TILE_SIZE)); 735 const unsigned buffer_size = block_size * nblocksy * nblocksx; 736 return buffer_size; 737 } 738 else { 739 /* we already computed this */ 740 return lpr->img_stride[level]; 741 } 742} 743 744 745/** 746 * Compute size (in bytes) need to store a texture image / mipmap level, 747 * including all cube faces or 3D image slices 748 */ 749static unsigned 750tex_image_size(const struct llvmpipe_resource *lpr, unsigned level, 751 enum lp_texture_layout layout) 752{ 753 const unsigned buf_size = tex_image_face_size(lpr, level, layout); 754 return buf_size * lpr->num_slices_faces[level]; 755} 756 757 758/** 759 * This function encapsulates some complicated logic for determining 760 * how to convert a tile of image data from linear layout to tiled 761 * layout, or vice versa. 762 * \param cur_layout the current tile layout 763 * \param target_layout the desired tile layout 764 * \param usage how the tile will be accessed (R/W vs. read-only, etc) 765 * \param new_layout_return returns the new layout mode 766 * \param convert_return returns TRUE if image conversion is needed 767 */ 768static void 769layout_logic(enum lp_texture_layout cur_layout, 770 enum lp_texture_layout target_layout, 771 enum lp_texture_usage usage, 772 enum lp_texture_layout *new_layout_return, 773 boolean *convert) 774{ 775 enum lp_texture_layout other_layout, new_layout; 776 777 *convert = FALSE; 778 779 new_layout = 99; /* debug check */ 780 781 if (target_layout == LP_TEX_LAYOUT_LINEAR) { 782 other_layout = LP_TEX_LAYOUT_TILED; 783 } 784 else { 785 assert(target_layout == LP_TEX_LAYOUT_TILED); 786 other_layout = LP_TEX_LAYOUT_LINEAR; 787 } 788 789 new_layout = target_layout; /* may get changed below */ 790 791 if (cur_layout == LP_TEX_LAYOUT_BOTH) { 792 if (usage == LP_TEX_USAGE_READ) { 793 new_layout = LP_TEX_LAYOUT_BOTH; 794 } 795 } 796 else if (cur_layout == other_layout) { 797 if (usage != LP_TEX_USAGE_WRITE_ALL) { 798 /* need to convert tiled data to linear or vice versa */ 799 *convert = TRUE; 800 801 if (usage == LP_TEX_USAGE_READ) 802 new_layout = LP_TEX_LAYOUT_BOTH; 803 } 804 } 805 else { 806 assert(cur_layout == LP_TEX_LAYOUT_NONE || 807 cur_layout == target_layout); 808 } 809 810 assert(new_layout == LP_TEX_LAYOUT_BOTH || 811 new_layout == target_layout); 812 813 *new_layout_return = new_layout; 814} 815 816 817/** 818 * Return pointer to a 2D texture image/face/slice. 819 * No tiled/linear conversion is done. 820 */ 821ubyte * 822llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr, 823 unsigned face_slice, unsigned level, 824 enum lp_texture_layout layout) 825{ 826 struct llvmpipe_texture_image *img; 827 unsigned offset; 828 829 if (layout == LP_TEX_LAYOUT_LINEAR) { 830 img = &lpr->linear[level]; 831 } 832 else { 833 assert (layout == LP_TEX_LAYOUT_TILED); 834 img = &lpr->tiled[level]; 835 } 836 837 if (face_slice > 0) 838 offset = face_slice * tex_image_face_size(lpr, level, layout); 839 else 840 offset = 0; 841 842 return (ubyte *) img->data + offset; 843} 844 845 846static INLINE enum lp_texture_layout 847llvmpipe_get_texture_tile_layout(const struct llvmpipe_resource *lpr, 848 unsigned face_slice, unsigned level, 849 unsigned x, unsigned y) 850{ 851 uint i; 852 assert(resource_is_texture(&lpr->base)); 853 assert(x < lpr->tiles_per_row[level]); 854 i = face_slice * lpr->tiles_per_image[level] 855 + y * lpr->tiles_per_row[level] + x; 856 return lpr->layout[level][i]; 857} 858 859 860static INLINE void 861llvmpipe_set_texture_tile_layout(struct llvmpipe_resource *lpr, 862 unsigned face_slice, unsigned level, 863 unsigned x, unsigned y, 864 enum lp_texture_layout layout) 865{ 866 uint i; 867 assert(resource_is_texture(&lpr->base)); 868 assert(x < lpr->tiles_per_row[level]); 869 i = face_slice * lpr->tiles_per_image[level] 870 + y * lpr->tiles_per_row[level] + x; 871 lpr->layout[level][i] = layout; 872} 873 874 875/** 876 * Set the layout mode for all tiles in a particular image. 877 */ 878static INLINE void 879llvmpipe_set_texture_image_layout(struct llvmpipe_resource *lpr, 880 unsigned face_slice, unsigned level, 881 unsigned width_t, unsigned height_t, 882 enum lp_texture_layout layout) 883{ 884 const unsigned start = face_slice * lpr->tiles_per_image[level]; 885 unsigned i; 886 887 for (i = 0; i < width_t * height_t; i++) { 888 lpr->layout[level][start + i] = layout; 889 } 890} 891 892 893/** 894 * Allocate storage for a linear or tile texture image (all cube 895 * faces and all 3D slices. 896 */ 897static void 898alloc_image_data(struct llvmpipe_resource *lpr, unsigned level, 899 enum lp_texture_layout layout) 900{ 901 if (lpr->dt) 902 assert(level == 0); 903 904 if (layout == LP_TEX_LAYOUT_TILED) { 905 /* tiled data is stored in regular memory */ 906 uint buffer_size = tex_image_size(lpr, level, layout); 907 lpr->tiled[level].data = align_malloc(buffer_size, 16); 908 } 909 else { 910 assert(layout == LP_TEX_LAYOUT_LINEAR); 911 if (lpr->dt) { 912 /* we get the linear memory from the winsys */ 913 struct llvmpipe_screen *screen = llvmpipe_screen(lpr->base.screen); 914 struct sw_winsys *winsys = screen->winsys; 915 916 lpr->linear[0].data = 917 winsys->displaytarget_map(winsys, lpr->dt, 918 PIPE_TRANSFER_READ_WRITE); 919 } 920 else { 921 /* not a display target - allocate regular memory */ 922 uint buffer_size = tex_image_size(lpr, level, LP_TEX_LAYOUT_LINEAR); 923 lpr->linear[level].data = align_malloc(buffer_size, 16); 924 } 925 } 926} 927 928 929 930/** 931 * Return pointer to texture image data (either linear or tiled layout) 932 * for a particular cube face or 3D texture slice. 933 * 934 * \param face_slice the cube face or 3D slice of interest 935 * \param usage one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE 936 * \param layout either LP_TEX_LAYOUT_LINEAR or _TILED or _NONE 937 */ 938void * 939llvmpipe_get_texture_image(struct llvmpipe_resource *lpr, 940 unsigned face_slice, unsigned level, 941 enum lp_texture_usage usage, 942 enum lp_texture_layout layout) 943{ 944 /* 945 * 'target' refers to the image which we're retrieving (either in 946 * tiled or linear layout). 947 * 'other' refers to the same image but in the other layout. (it may 948 * or may not exist. 949 */ 950 struct llvmpipe_texture_image *target_img; 951 struct llvmpipe_texture_image *other_img; 952 void *target_data; 953 void *other_data; 954 const unsigned width = u_minify(lpr->base.width0, level); 955 const unsigned height = u_minify(lpr->base.height0, level); 956 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE; 957 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE; 958 enum lp_texture_layout other_layout; 959 boolean only_allocate; 960 961 assert(layout == LP_TEX_LAYOUT_NONE || 962 layout == LP_TEX_LAYOUT_TILED || 963 layout == LP_TEX_LAYOUT_LINEAR); 964 965 assert(usage == LP_TEX_USAGE_READ || 966 usage == LP_TEX_USAGE_READ_WRITE || 967 usage == LP_TEX_USAGE_WRITE_ALL); 968 969 /* check for the special case of layout == LP_TEX_LAYOUT_NONE */ 970 if (layout == LP_TEX_LAYOUT_NONE) { 971 only_allocate = TRUE; 972 layout = LP_TEX_LAYOUT_TILED; 973 } 974 else { 975 only_allocate = FALSE; 976 } 977 978 if (lpr->dt) { 979 assert(lpr->linear[level].data); 980 } 981 982 /* which is target? which is other? */ 983 if (layout == LP_TEX_LAYOUT_LINEAR) { 984 target_img = &lpr->linear[level]; 985 other_img = &lpr->tiled[level]; 986 other_layout = LP_TEX_LAYOUT_TILED; 987 } 988 else { 989 target_img = &lpr->tiled[level]; 990 other_img = &lpr->linear[level]; 991 other_layout = LP_TEX_LAYOUT_LINEAR; 992 } 993 994 target_data = target_img->data; 995 other_data = other_img->data; 996 997 if (!target_data) { 998 /* allocate memory for the target image now */ 999 alloc_image_data(lpr, level, layout); 1000 target_data = target_img->data; 1001 } 1002 1003 if (face_slice > 0) { 1004 unsigned target_offset, other_offset; 1005 1006 target_offset = face_slice * tex_image_face_size(lpr, level, layout); 1007 other_offset = face_slice * tex_image_face_size(lpr, level, other_layout); 1008 if (target_data) { 1009 target_data = (uint8_t *) target_data + target_offset; 1010 } 1011 if (other_data) { 1012 other_data = (uint8_t *) other_data + other_offset; 1013 } 1014 } 1015 1016 if (only_allocate) { 1017 /* Just allocating tiled memory. Don't initialize it from the 1018 * linear data if it exists. 1019 */ 1020 return target_data; 1021 } 1022 1023 if (other_data) { 1024 /* may need to convert other data to the requested layout */ 1025 enum lp_texture_layout new_layout; 1026 unsigned x, y; 1027 1028 /* loop over all image tiles, doing layout conversion where needed */ 1029 for (y = 0; y < height_t; y++) { 1030 for (x = 0; x < width_t; x++) { 1031 enum lp_texture_layout cur_layout = 1032 llvmpipe_get_texture_tile_layout(lpr, face_slice, level, x, y); 1033 boolean convert; 1034 1035 layout_logic(cur_layout, layout, usage, &new_layout, &convert); 1036 1037 if (convert) { 1038 if (layout == LP_TEX_LAYOUT_TILED) { 1039 lp_linear_to_tiled(other_data, target_data, 1040 x * TILE_SIZE, y * TILE_SIZE, 1041 TILE_SIZE, TILE_SIZE, 1042 lpr->base.format, 1043 lpr->row_stride[level], 1044 lpr->tiles_per_row[level]); 1045 } 1046 else { 1047 lp_tiled_to_linear(other_data, target_data, 1048 x * TILE_SIZE, y * TILE_SIZE, 1049 TILE_SIZE, TILE_SIZE, 1050 lpr->base.format, 1051 lpr->row_stride[level], 1052 lpr->tiles_per_row[level]); 1053 } 1054 } 1055 1056 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, x, y, 1057 new_layout); 1058 } 1059 } 1060 } 1061 else { 1062 /* no other data */ 1063 llvmpipe_set_texture_image_layout(lpr, face_slice, level, 1064 width_t, height_t, layout); 1065 } 1066 1067 assert(target_data); 1068 1069 return target_data; 1070} 1071 1072 1073/** 1074 * Return pointer to start of a texture image (1D, 2D, 3D, CUBE). 1075 * All cube faces and 3D slices will be converted to the requested 1076 * layout if needed. 1077 * This is typically used when we're about to sample from a texture. 1078 */ 1079void * 1080llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr, 1081 unsigned level, 1082 enum lp_texture_usage usage, 1083 enum lp_texture_layout layout) 1084{ 1085 const int slices = lpr->num_slices_faces[level]; 1086 int slice; 1087 void *map = NULL; 1088 1089 assert(slices > 0); 1090 1091 for (slice = slices - 1; slice >= 0; slice--) { 1092 map = llvmpipe_get_texture_image(lpr, slice, level, usage, layout); 1093 } 1094 1095 return map; 1096} 1097 1098 1099/** 1100 * Get pointer to a linear image (not the tile!) where the tile at (x,y) 1101 * is known to be in linear layout. 1102 * Conversion from tiled to linear will be done if necessary. 1103 * \return pointer to start of image/face (not the tile) 1104 */ 1105ubyte * 1106llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr, 1107 unsigned face_slice, unsigned level, 1108 enum lp_texture_usage usage, 1109 unsigned x, unsigned y) 1110{ 1111 struct llvmpipe_texture_image *linear_img = &lpr->linear[level]; 1112 enum lp_texture_layout cur_layout, new_layout; 1113 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE; 1114 boolean convert; 1115 uint8_t *tiled_image, *linear_image; 1116 1117 assert(resource_is_texture(&lpr->base)); 1118 assert(x % TILE_SIZE == 0); 1119 assert(y % TILE_SIZE == 0); 1120 1121 if (!linear_img->data) { 1122 /* allocate memory for the linear image now */ 1123 alloc_image_data(lpr, level, LP_TEX_LAYOUT_LINEAR); 1124 } 1125 1126 /* compute address of the slice/face of the image that contains the tile */ 1127 tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level, 1128 LP_TEX_LAYOUT_TILED); 1129 linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level, 1130 LP_TEX_LAYOUT_LINEAR); 1131 1132 /* get current tile layout and determine if data conversion is needed */ 1133 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty); 1134 1135 layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage, 1136 &new_layout, &convert); 1137 1138 if (convert) { 1139 lp_tiled_to_linear(tiled_image, linear_image, 1140 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format, 1141 lpr->row_stride[level], 1142 lpr->tiles_per_row[level]); 1143 } 1144 1145 if (new_layout != cur_layout) 1146 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout); 1147 1148 return linear_image; 1149} 1150 1151 1152/** 1153 * Get pointer to tiled data for rendering. 1154 * \return pointer to the tiled data at the given tile position 1155 */ 1156ubyte * 1157llvmpipe_get_texture_tile(struct llvmpipe_resource *lpr, 1158 unsigned face_slice, unsigned level, 1159 enum lp_texture_usage usage, 1160 unsigned x, unsigned y) 1161{ 1162 struct llvmpipe_texture_image *tiled_img = &lpr->tiled[level]; 1163 enum lp_texture_layout cur_layout, new_layout; 1164 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE; 1165 boolean convert; 1166 uint8_t *tiled_image, *linear_image; 1167 unsigned tile_offset; 1168 1169 assert(x % TILE_SIZE == 0); 1170 assert(y % TILE_SIZE == 0); 1171 1172 if (!tiled_img->data) { 1173 /* allocate memory for the tiled image now */ 1174 alloc_image_data(lpr, level, LP_TEX_LAYOUT_TILED); 1175 } 1176 1177 /* compute address of the slice/face of the image that contains the tile */ 1178 tiled_image = llvmpipe_get_texture_image_address(lpr, face_slice, level, 1179 LP_TEX_LAYOUT_TILED); 1180 linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level, 1181 LP_TEX_LAYOUT_LINEAR); 1182 1183 /* get current tile layout and see if we need to convert the data */ 1184 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty); 1185 1186 layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert); 1187 if (convert) { 1188 lp_linear_to_tiled(linear_image, tiled_image, 1189 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format, 1190 lpr->row_stride[level], 1191 lpr->tiles_per_row[level]); 1192 } 1193 1194 if (new_layout != cur_layout) 1195 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout); 1196 1197 /* compute, return address of the 64x64 tile */ 1198 tile_offset = (ty * lpr->tiles_per_row[level] + tx) 1199 * TILE_SIZE * TILE_SIZE * 4; 1200 1201 return (ubyte *) tiled_image + tile_offset; 1202} 1203 1204 1205/** 1206 * Return size of resource in bytes 1207 */ 1208unsigned 1209llvmpipe_resource_size(const struct pipe_resource *resource) 1210{ 1211 const struct llvmpipe_resource *lpr = llvmpipe_resource_const(resource); 1212 unsigned lvl, size = 0; 1213 1214 for (lvl = 0; lvl <= lpr->base.last_level; lvl++) { 1215 if (lpr->linear[lvl].data) 1216 size += tex_image_size(lpr, lvl, LP_TEX_LAYOUT_LINEAR); 1217 1218 if (lpr->tiled[lvl].data) 1219 size += tex_image_size(lpr, lvl, LP_TEX_LAYOUT_TILED); 1220 } 1221 1222 return size; 1223} 1224 1225 1226#ifdef DEBUG 1227void 1228llvmpipe_print_resources(void) 1229{ 1230 struct llvmpipe_resource *lpr; 1231 unsigned n = 0, total = 0; 1232 1233 debug_printf("LLVMPIPE: current resources:\n"); 1234 foreach(lpr, &resource_list) { 1235 unsigned size = llvmpipe_resource_size(&lpr->base); 1236 debug_printf("resource %u at %p, size %ux%ux%u: %u bytes, refcount %u\n", 1237 lpr->id, (void *) lpr, 1238 lpr->base.width0, lpr->base.height0, lpr->base.depth0, 1239 size, lpr->base.reference.count); 1240 total += size; 1241 n++; 1242 } 1243 debug_printf("LLVMPIPE: total size of %u resources: %u\n", n, total); 1244} 1245#endif 1246 1247 1248void 1249llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen) 1250{ 1251#ifdef DEBUG 1252 /* init linked list for tracking resources */ 1253 { 1254 static boolean first_call = TRUE; 1255 if (first_call) { 1256 memset(&resource_list, 0, sizeof(resource_list)); 1257 make_empty_list(&resource_list); 1258 first_call = FALSE; 1259 } 1260 } 1261#endif 1262 1263 screen->resource_create = llvmpipe_resource_create; 1264 screen->resource_destroy = llvmpipe_resource_destroy; 1265 screen->resource_from_handle = llvmpipe_resource_from_handle; 1266 screen->resource_get_handle = llvmpipe_resource_get_handle; 1267 screen->user_buffer_create = llvmpipe_user_buffer_create; 1268 1269 screen->get_tex_surface = llvmpipe_get_tex_surface; 1270 screen->tex_surface_destroy = llvmpipe_tex_surface_destroy; 1271} 1272 1273 1274void 1275llvmpipe_init_context_resource_funcs(struct pipe_context *pipe) 1276{ 1277 pipe->get_transfer = llvmpipe_get_transfer; 1278 pipe->transfer_destroy = llvmpipe_transfer_destroy; 1279 pipe->transfer_map = llvmpipe_transfer_map; 1280 pipe->transfer_unmap = llvmpipe_transfer_unmap; 1281 pipe->is_resource_referenced = llvmpipe_is_resource_referenced; 1282 1283 pipe->transfer_flush_region = u_default_transfer_flush_region; 1284 pipe->transfer_inline_write = u_default_transfer_inline_write; 1285} 1286