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