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 "pipe/p_state.h" 34#include "pipe/p_context.h" 35#include "pipe/p_defines.h" 36#include "util/u_inlines.h" 37#include "util/u_format.h" 38#include "util/u_math.h" 39#include "util/u_memory.h" 40#include "util/u_rect.h" 41 42#include "i915_context.h" 43#include "i915_resource.h" 44#include "i915_screen.h" 45#include "i915_winsys.h" 46#include "i915_debug.h" 47 48 49#define DEBUG_TEXTURES 0 50 51/* 52 * Helper function and arrays 53 */ 54 55 56/** 57 * Initial offset for Cube map. 58 */ 59static const int initial_offsets[6][2] = { 60 [PIPE_TEX_FACE_POS_X] = {0, 0}, 61 [PIPE_TEX_FACE_POS_Y] = {1, 0}, 62 [PIPE_TEX_FACE_POS_Z] = {1, 1}, 63 [PIPE_TEX_FACE_NEG_X] = {0, 2}, 64 [PIPE_TEX_FACE_NEG_Y] = {1, 2}, 65 [PIPE_TEX_FACE_NEG_Z] = {1, 3}, 66}; 67 68/** 69 * Step offsets for Cube map. 70 */ 71static const int step_offsets[6][2] = { 72 [PIPE_TEX_FACE_POS_X] = { 0, 2}, 73 [PIPE_TEX_FACE_POS_Y] = {-1, 2}, 74 [PIPE_TEX_FACE_POS_Z] = {-1, 1}, 75 [PIPE_TEX_FACE_NEG_X] = { 0, 2}, 76 [PIPE_TEX_FACE_NEG_Y] = {-1, 2}, 77 [PIPE_TEX_FACE_NEG_Z] = {-1, 1}, 78}; 79 80/** 81 * For compressed level 2 82 */ 83static const int bottom_offsets[6] = { 84 [PIPE_TEX_FACE_POS_X] = 16 + 0 * 8, 85 [PIPE_TEX_FACE_POS_Y] = 16 + 1 * 8, 86 [PIPE_TEX_FACE_POS_Z] = 16 + 2 * 8, 87 [PIPE_TEX_FACE_NEG_X] = 16 + 3 * 8, 88 [PIPE_TEX_FACE_NEG_Y] = 16 + 4 * 8, 89 [PIPE_TEX_FACE_NEG_Z] = 16 + 5 * 8, 90}; 91 92static inline unsigned 93align_nblocksx(enum pipe_format format, unsigned width, unsigned align_to) 94{ 95 return align(util_format_get_nblocksx(format, width), align_to); 96} 97 98static inline unsigned 99align_nblocksy(enum pipe_format format, unsigned width, unsigned align_to) 100{ 101 return align(util_format_get_nblocksy(format, width), align_to); 102} 103 104static inline unsigned 105get_pot_stride(enum pipe_format format, unsigned width) 106{ 107 return util_next_power_of_two(util_format_get_stride(format, width)); 108} 109 110static inline const char* 111get_tiling_string(enum i915_winsys_buffer_tile tile) 112{ 113 switch(tile) { 114 case I915_TILE_NONE: 115 return "none"; 116 case I915_TILE_X: 117 return "x"; 118 case I915_TILE_Y: 119 return "y"; 120 default: 121 assert(FALSE); 122 return "?"; 123 } 124} 125 126 127/* 128 * More advanced helper funcs 129 */ 130 131 132static void 133i915_texture_set_level_info(struct i915_texture *tex, 134 unsigned level, unsigned nr_images) 135{ 136 assert(level < ARRAY_SIZE(tex->nr_images)); 137 assert(nr_images); 138 assert(!tex->image_offset[level]); 139 140 tex->nr_images[level] = nr_images; 141 tex->image_offset[level] = MALLOC(nr_images * sizeof(struct offset_pair)); 142 tex->image_offset[level][0].nblocksx = 0; 143 tex->image_offset[level][0].nblocksy = 0; 144} 145 146unsigned i915_texture_offset(const struct i915_texture *tex, 147 unsigned level, unsigned layer) 148{ 149 unsigned x, y; 150 x = tex->image_offset[level][layer].nblocksx 151 * util_format_get_blocksize(tex->b.b.format); 152 y = tex->image_offset[level][layer].nblocksy; 153 154 return y * tex->stride + x; 155} 156 157static void 158i915_texture_set_image_offset(struct i915_texture *tex, 159 unsigned level, unsigned img, 160 unsigned nblocksx, unsigned nblocksy) 161{ 162 /* for the first image and level make sure offset is zero */ 163 assert(!(img == 0 && level == 0) || (nblocksx == 0 && nblocksy == 0)); 164 assert(img < tex->nr_images[level]); 165 166 tex->image_offset[level][img].nblocksx = nblocksx; 167 tex->image_offset[level][img].nblocksy = nblocksy; 168 169#if DEBUG_TEXTURES 170 debug_printf("%s: %p level %u, img %u (%u, %u)\n", __FUNCTION__, 171 tex, level, img, x, y); 172#endif 173} 174 175static enum i915_winsys_buffer_tile 176i915_texture_tiling(struct i915_screen *is, struct i915_texture *tex) 177{ 178 if (!is->debug.tiling) 179 return I915_TILE_NONE; 180 181 if (tex->b.b.target == PIPE_TEXTURE_1D) 182 return I915_TILE_NONE; 183 184 if (util_format_is_s3tc(tex->b.b.format)) 185 return I915_TILE_X; 186 187 if (is->debug.use_blitter) 188 return I915_TILE_X; 189 else 190 return I915_TILE_Y; 191} 192 193 194/* 195 * Shared layout functions 196 */ 197 198 199/** 200 * Special case to deal with scanout textures. 201 */ 202static boolean 203i9x5_scanout_layout(struct i915_texture *tex) 204{ 205 struct pipe_resource *pt = &tex->b.b; 206 207 if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4) 208 return FALSE; 209 210 i915_texture_set_level_info(tex, 0, 1); 211 i915_texture_set_image_offset(tex, 0, 0, 0, 0); 212 213 if (pt->width0 >= 240) { 214 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64); 215 tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8); 216 tex->tiling = I915_TILE_X; 217 /* special case for cursors */ 218 } else if (pt->width0 == 64 && pt->height0 == 64) { 219 tex->stride = get_pot_stride(pt->format, pt->width0); 220 tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8); 221 } else { 222 return FALSE; 223 } 224 225#if DEBUG_TEXTURE 226 debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__, 227 pt->width0, pt->height0, util_format_get_blocksize(pt->format), 228 tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy); 229#endif 230 231 return TRUE; 232} 233 234/** 235 * Special case to deal with shared textures. 236 */ 237static boolean 238i9x5_display_target_layout(struct i915_texture *tex) 239{ 240 struct pipe_resource *pt = &tex->b.b; 241 242 if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4) 243 return FALSE; 244 245 /* fallback to normal textures for small textures */ 246 if (pt->width0 < 240) 247 return FALSE; 248 249 i915_texture_set_level_info(tex, 0, 1); 250 i915_texture_set_image_offset(tex, 0, 0, 0, 0); 251 252 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64); 253 tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8); 254 tex->tiling = I915_TILE_X; 255 256#if DEBUG_TEXTURE 257 debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__, 258 pt->width0, pt->height0, util_format_get_blocksize(pt->format), 259 tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy); 260#endif 261 262 return TRUE; 263} 264 265/** 266 * Helper function for special layouts 267 */ 268static boolean 269i9x5_special_layout(struct i915_texture *tex) 270{ 271 struct pipe_resource *pt = &tex->b.b; 272 273 /* Scanouts needs special care */ 274 if (pt->bind & PIPE_BIND_SCANOUT) 275 if (i9x5_scanout_layout(tex)) 276 return TRUE; 277 278 /* Shared buffers needs to be compatible with X servers 279 * 280 * XXX: need a better name than shared for this if it is to be part 281 * of core gallium, and probably move the flag to resource.flags, 282 * rather than bindings. 283 */ 284 if (pt->bind & (PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET)) 285 if (i9x5_display_target_layout(tex)) 286 return TRUE; 287 288 return FALSE; 289} 290 291/** 292 * Cube layout used on i915 and for non-compressed textures on i945. 293 */ 294static void 295i9x5_texture_layout_cube(struct i915_texture *tex) 296{ 297 struct pipe_resource *pt = &tex->b.b; 298 unsigned width = util_next_power_of_two(pt->width0); 299 const unsigned nblocks = util_format_get_nblocksx(pt->format, width); 300 unsigned level; 301 unsigned face; 302 303 assert(pt->width0 == pt->height0); /* cubemap images are square */ 304 305 /* double pitch for cube layouts */ 306 tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4); 307 tex->total_nblocksy = nblocks * 4; 308 309 for (level = 0; level <= pt->last_level; level++) 310 i915_texture_set_level_info(tex, level, 6); 311 312 for (face = 0; face < 6; face++) { 313 unsigned x = initial_offsets[face][0] * nblocks; 314 unsigned y = initial_offsets[face][1] * nblocks; 315 unsigned d = nblocks; 316 317 for (level = 0; level <= pt->last_level; level++) { 318 i915_texture_set_image_offset(tex, level, face, x, y); 319 d >>= 1; 320 x += step_offsets[face][0] * d; 321 y += step_offsets[face][1] * d; 322 } 323 } 324} 325 326 327/* 328 * i915 layout functions 329 */ 330 331 332static void 333i915_texture_layout_2d(struct i915_texture *tex) 334{ 335 struct pipe_resource *pt = &tex->b.b; 336 unsigned level; 337 unsigned width = util_next_power_of_two(pt->width0); 338 unsigned height = util_next_power_of_two(pt->height0); 339 unsigned nblocksy = util_format_get_nblocksy(pt->format, width); 340 unsigned align_y = 2; 341 342 if (util_format_is_s3tc(pt->format)) 343 align_y = 1; 344 345 tex->stride = align(util_format_get_stride(pt->format, width), 4); 346 tex->total_nblocksy = 0; 347 348 for (level = 0; level <= pt->last_level; level++) { 349 i915_texture_set_level_info(tex, level, 1); 350 i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy); 351 352 tex->total_nblocksy += nblocksy; 353 354 width = u_minify(width, 1); 355 height = u_minify(height, 1); 356 nblocksy = align_nblocksy(pt->format, height, align_y); 357 } 358} 359 360static void 361i915_texture_layout_3d(struct i915_texture *tex) 362{ 363 struct pipe_resource *pt = &tex->b.b; 364 unsigned level; 365 366 unsigned width = util_next_power_of_two(pt->width0); 367 unsigned height = util_next_power_of_two(pt->height0); 368 unsigned depth = util_next_power_of_two(pt->depth0); 369 unsigned nblocksy = util_format_get_nblocksy(pt->format, height); 370 unsigned stack_nblocksy = 0; 371 372 /* Calculate the size of a single slice. 373 */ 374 tex->stride = align(util_format_get_stride(pt->format, width), 4); 375 376 /* XXX: hardware expects/requires 9 levels at minimum. 377 */ 378 for (level = 0; level <= MAX2(8, pt->last_level); level++) { 379 i915_texture_set_level_info(tex, level, depth); 380 381 stack_nblocksy += MAX2(2, nblocksy); 382 383 width = u_minify(width, 1); 384 height = u_minify(height, 1); 385 nblocksy = util_format_get_nblocksy(pt->format, height); 386 } 387 388 /* Fixup depth image_offsets: 389 */ 390 for (level = 0; level <= pt->last_level; level++) { 391 unsigned i; 392 for (i = 0; i < depth; i++) 393 i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy); 394 395 depth = u_minify(depth, 1); 396 } 397 398 /* Multiply slice size by texture depth for total size. It's 399 * remarkable how wasteful of memory the i915 texture layouts 400 * are. They are largely fixed in the i945. 401 */ 402 tex->total_nblocksy = stack_nblocksy * util_next_power_of_two(pt->depth0); 403} 404 405static boolean 406i915_texture_layout(struct i915_texture * tex) 407{ 408 switch (tex->b.b.target) { 409 case PIPE_TEXTURE_1D: 410 case PIPE_TEXTURE_2D: 411 case PIPE_TEXTURE_RECT: 412 if (!i9x5_special_layout(tex)) 413 i915_texture_layout_2d(tex); 414 break; 415 case PIPE_TEXTURE_3D: 416 i915_texture_layout_3d(tex); 417 break; 418 case PIPE_TEXTURE_CUBE: 419 i9x5_texture_layout_cube(tex); 420 break; 421 default: 422 assert(0); 423 return FALSE; 424 } 425 426 return TRUE; 427} 428 429 430/* 431 * i945 layout functions 432 */ 433 434 435static void 436i945_texture_layout_2d(struct i915_texture *tex) 437{ 438 struct pipe_resource *pt = &tex->b.b; 439 int align_x = 4, align_y = 2; 440 unsigned level; 441 unsigned x = 0; 442 unsigned y = 0; 443 unsigned width = util_next_power_of_two(pt->width0); 444 unsigned height = util_next_power_of_two(pt->height0); 445 unsigned nblocksx = util_format_get_nblocksx(pt->format, width); 446 unsigned nblocksy = util_format_get_nblocksy(pt->format, height); 447 448 if (util_format_is_s3tc(pt->format)) { 449 align_x = 1; 450 align_y = 1; 451 } 452 453 tex->stride = align(util_format_get_stride(pt->format, width), 4); 454 455 /* May need to adjust pitch to accommodate the placement of 456 * the 2nd mipmap level. This occurs when the alignment 457 * constraints of mipmap placement push the right edge of the 458 * 2nd mipmap level out past the width of its parent. 459 */ 460 if (pt->last_level > 0) { 461 unsigned mip1_nblocksx = 462 align_nblocksx(pt->format, u_minify(width, 1), align_x) + 463 util_format_get_nblocksx(pt->format, u_minify(width, 2)); 464 465 if (mip1_nblocksx > nblocksx) 466 tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format); 467 } 468 469 /* Pitch must be a whole number of dwords 470 */ 471 tex->stride = align(tex->stride, 64); 472 tex->total_nblocksy = 0; 473 474 for (level = 0; level <= pt->last_level; level++) { 475 i915_texture_set_level_info(tex, level, 1); 476 i915_texture_set_image_offset(tex, level, 0, x, y); 477 478 /* Because the images are packed better, the final offset 479 * might not be the maximal one: 480 */ 481 tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy); 482 483 /* Layout_below: step right after second mipmap level. 484 */ 485 if (level == 1) { 486 x += nblocksx; 487 } else { 488 y += nblocksy; 489 } 490 491 width = u_minify(width, 1); 492 height = u_minify(height, 1); 493 nblocksx = align_nblocksx(pt->format, width, align_x); 494 nblocksy = align_nblocksy(pt->format, height, align_y); 495 } 496} 497 498static void 499i945_texture_layout_3d(struct i915_texture *tex) 500{ 501 struct pipe_resource *pt = &tex->b.b; 502 unsigned width = util_next_power_of_two(pt->width0); 503 unsigned height = util_next_power_of_two(pt->height0); 504 unsigned depth = util_next_power_of_two(pt->depth0); 505 unsigned nblocksy = util_format_get_nblocksy(pt->format, width); 506 unsigned pack_x_pitch, pack_x_nr; 507 unsigned pack_y_pitch; 508 unsigned level; 509 510 tex->stride = align(util_format_get_stride(pt->format, width), 4); 511 tex->total_nblocksy = 0; 512 513 pack_y_pitch = MAX2(nblocksy, 2); 514 pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format); 515 pack_x_nr = 1; 516 517 for (level = 0; level <= pt->last_level; level++) { 518 int x = 0; 519 int y = 0; 520 unsigned q, j; 521 522 i915_texture_set_level_info(tex, level, depth); 523 524 for (q = 0; q < depth;) { 525 for (j = 0; j < pack_x_nr && q < depth; j++, q++) { 526 i915_texture_set_image_offset(tex, level, q, x, y + tex->total_nblocksy); 527 x += pack_x_pitch; 528 } 529 530 x = 0; 531 y += pack_y_pitch; 532 } 533 534 tex->total_nblocksy += y; 535 536 if (pack_x_pitch > 4) { 537 pack_x_pitch >>= 1; 538 pack_x_nr <<= 1; 539 assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride); 540 } 541 542 if (pack_y_pitch > 2) { 543 pack_y_pitch >>= 1; 544 } 545 546 width = u_minify(width, 1); 547 height = u_minify(height, 1); 548 depth = u_minify(depth, 1); 549 nblocksy = util_format_get_nblocksy(pt->format, height); 550 } 551} 552 553static void 554i945_texture_layout_cube(struct i915_texture *tex) 555{ 556 struct pipe_resource *pt = &tex->b.b; 557 unsigned width = util_next_power_of_two(pt->width0); 558 const unsigned nblocks = util_format_get_nblocksx(pt->format, width); 559 const unsigned dim = width; 560 unsigned level; 561 unsigned face; 562 563 assert(pt->width0 == pt->height0); /* cubemap images are square */ 564 assert(util_format_is_s3tc(pt->format)); /* compressed only */ 565 566 /* 567 * Depending on the size of the largest images, pitch can be 568 * determined either by the old-style packing of cubemap faces, 569 * or the final row of 4x4, 2x2 and 1x1 faces below this. 570 * 571 * 64 * 2 / 4 = 32 572 * 14 * 2 = 28 573 */ 574 if (width >= 64) 575 tex->stride = nblocks * 2 * util_format_get_blocksize(pt->format); 576 else 577 tex->stride = 14 * 2 * util_format_get_blocksize(pt->format); 578 579 /* 580 * Something similary apply for height as well. 581 */ 582 if (width >= 4) 583 tex->total_nblocksy = nblocks * 4 + 1; 584 else 585 tex->total_nblocksy = 1; 586 587 /* Set all the levels to effectively occupy the whole rectangular region */ 588 for (level = 0; level <= pt->last_level; level++) 589 i915_texture_set_level_info(tex, level, 6); 590 591 for (face = 0; face < 6; face++) { 592 /* all calculations in pixels */ 593 unsigned total_height = tex->total_nblocksy * 4; 594 unsigned x = initial_offsets[face][0] * dim; 595 unsigned y = initial_offsets[face][1] * dim; 596 unsigned d = dim; 597 598 if (dim == 4 && face >= 4) { 599 x = (face - 4) * 8; 600 y = tex->total_nblocksy * 4 - 4; /* 4 = 1 block */ 601 } else if (dim < 4 && (face > 0)) { 602 x = face * 8; 603 y = total_height - 4; 604 } 605 606 for (level = 0; level <= pt->last_level; level++) { 607 i915_texture_set_image_offset(tex, level, face, 608 util_format_get_nblocksx(pt->format, x), 609 util_format_get_nblocksy(pt->format, y)); 610 611 d >>= 1; 612 613 switch (d) { 614 case 4: 615 switch (face) { 616 case PIPE_TEX_FACE_POS_X: 617 case PIPE_TEX_FACE_NEG_X: 618 x += step_offsets[face][0] * d; 619 y += step_offsets[face][1] * d; 620 break; 621 case PIPE_TEX_FACE_POS_Y: 622 case PIPE_TEX_FACE_NEG_Y: 623 y += 12; 624 x -= 8; 625 break; 626 case PIPE_TEX_FACE_POS_Z: 627 case PIPE_TEX_FACE_NEG_Z: 628 y = total_height - 4; 629 x = (face - 4) * 8; 630 break; 631 } 632 break; 633 case 2: 634 y = total_height - 4; 635 x = bottom_offsets[face]; 636 break; 637 case 1: 638 x += 48; 639 break; 640 default: 641 x += step_offsets[face][0] * d; 642 y += step_offsets[face][1] * d; 643 break; 644 } 645 } 646 } 647} 648 649static boolean 650i945_texture_layout(struct i915_texture * tex) 651{ 652 switch (tex->b.b.target) { 653 case PIPE_TEXTURE_1D: 654 case PIPE_TEXTURE_2D: 655 case PIPE_TEXTURE_RECT: 656 if (!i9x5_special_layout(tex)) 657 i945_texture_layout_2d(tex); 658 break; 659 case PIPE_TEXTURE_3D: 660 i945_texture_layout_3d(tex); 661 break; 662 case PIPE_TEXTURE_CUBE: 663 if (!util_format_is_s3tc(tex->b.b.format)) 664 i9x5_texture_layout_cube(tex); 665 else 666 i945_texture_layout_cube(tex); 667 break; 668 default: 669 assert(0); 670 return FALSE; 671 } 672 673 return TRUE; 674} 675 676 677 678/* 679 * Screen texture functions 680 */ 681 682 683 684static boolean 685i915_texture_get_handle(struct pipe_screen * screen, 686 struct pipe_resource *texture, 687 struct winsys_handle *whandle) 688{ 689 struct i915_screen *is = i915_screen(screen); 690 struct i915_texture *tex = i915_texture(texture); 691 struct i915_winsys *iws = is->iws; 692 693 return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride); 694} 695 696 697static void 698i915_texture_destroy(struct pipe_screen *screen, 699 struct pipe_resource *pt) 700{ 701 struct i915_texture *tex = i915_texture(pt); 702 struct i915_winsys *iws = i915_screen(screen)->iws; 703 uint i; 704 705 if (tex->buffer) 706 iws->buffer_destroy(iws, tex->buffer); 707 708 for (i = 0; i < ARRAY_SIZE(tex->image_offset); i++) 709 FREE(tex->image_offset[i]); 710 711 FREE(tex); 712} 713 714static void * 715i915_texture_transfer_map(struct pipe_context *pipe, 716 struct pipe_resource *resource, 717 unsigned level, 718 unsigned usage, 719 const struct pipe_box *box, 720 struct pipe_transfer **ptransfer) 721{ 722 struct i915_context *i915 = i915_context(pipe); 723 struct i915_texture *tex = i915_texture(resource); 724 struct i915_transfer *transfer = slab_alloc_st(&i915->texture_transfer_pool); 725 boolean use_staging_texture = FALSE; 726 struct i915_winsys *iws = i915_screen(pipe->screen)->iws; 727 enum pipe_format format = resource->format; 728 unsigned offset; 729 char *map; 730 731 if (!transfer) 732 return NULL; 733 734 transfer->b.resource = resource; 735 transfer->b.level = level; 736 transfer->b.usage = usage; 737 transfer->b.box = *box; 738 transfer->b.stride = tex->stride; 739 transfer->staging_texture = NULL; 740 /* XXX: handle depth textures everyhwere*/ 741 transfer->b.layer_stride = 0; 742 743 /* if we use staging transfers, only support textures we can render to, 744 * because we need that for u_blitter */ 745 if (i915->blitter && 746 util_blitter_is_copy_supported(i915->blitter, resource, resource) && 747 (usage & PIPE_TRANSFER_WRITE) && 748 !(usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED))) 749 use_staging_texture = TRUE; 750 751 use_staging_texture = FALSE; 752 753 if (use_staging_texture) { 754 /* 755 * Allocate the untiled staging texture. 756 * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map() 757 */ 758 transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE); 759 } 760 761 if (resource->target != PIPE_TEXTURE_3D && 762 resource->target != PIPE_TEXTURE_CUBE) 763 assert(box->z == 0); 764 765 if (transfer->staging_texture) { 766 tex = i915_texture(transfer->staging_texture); 767 } else { 768 /* TODO this is a sledgehammer */ 769 tex = i915_texture(resource); 770 pipe->flush(pipe, NULL, 0); 771 } 772 773 offset = i915_texture_offset(tex, transfer->b.level, box->z); 774 775 map = iws->buffer_map(iws, tex->buffer, 776 (transfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE); 777 if (!map) { 778 pipe_resource_reference(&transfer->staging_texture, NULL); 779 FREE(transfer); 780 return NULL; 781 } 782 783 *ptransfer = &transfer->b; 784 785 return map + offset + 786 box->y / util_format_get_blockheight(format) * transfer->b.stride + 787 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 788} 789 790static void 791i915_texture_transfer_unmap(struct pipe_context *pipe, 792 struct pipe_transfer *transfer) 793{ 794 struct i915_context *i915 = i915_context(pipe); 795 struct i915_transfer *itransfer = (struct i915_transfer*)transfer; 796 struct i915_texture *tex = i915_texture(itransfer->b.resource); 797 struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; 798 799 if (itransfer->staging_texture) 800 tex = i915_texture(itransfer->staging_texture); 801 802 iws->buffer_unmap(iws, tex->buffer); 803 804 if ((itransfer->staging_texture) && 805 (transfer->usage & PIPE_TRANSFER_WRITE)) { 806 struct pipe_box sbox; 807 808 u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox); 809 pipe->resource_copy_region(pipe, itransfer->b.resource, itransfer->b.level, 810 itransfer->b.box.x, itransfer->b.box.y, itransfer->b.box.z, 811 itransfer->staging_texture, 812 0, &sbox); 813 pipe->flush(pipe, NULL, 0); 814 pipe_resource_reference(&itransfer->staging_texture, NULL); 815 } 816 817 slab_free_st(&i915->texture_transfer_pool, itransfer); 818} 819 820#if 0 821static void i915_texture_subdata(struct pipe_context *pipe, 822 struct pipe_resource *resource, 823 unsigned level, 824 unsigned usage, 825 const struct pipe_box *box, 826 const void *data, 827 unsigned stride, 828 unsigned layer_stride) 829{ 830 struct pipe_transfer *transfer = NULL; 831 struct i915_transfer *itransfer = NULL; 832 const uint8_t *src_data = data; 833 unsigned i; 834 835 transfer = pipe->transfer_get(pipe, 836 resource, 837 level, 838 usage, 839 box ); 840 if (transfer == NULL) 841 goto out; 842 843 itransfer = (struct i915_transfer*)transfer; 844 845 if (itransfer->staging_texture) { 846 struct i915_texture *tex = i915_texture(itransfer->staging_texture); 847 enum pipe_format format = tex->b.b.format; 848 struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; 849 size_t offset; 850 size_t size; 851 852 offset = i915_texture_offset(tex, transfer->level, transfer->box.z); 853 854 for (i = 0; i < box->depth; i++) { 855 if (!tex->b.b.last_level && 856 tex->b.b.width0 == transfer->box.width) { 857 unsigned nby = util_format_get_nblocksy(format, transfer->box.y); 858 assert(!offset); 859 assert(!transfer->box.x); 860 assert(tex->stride == transfer->stride); 861 862 offset += tex->stride * nby; 863 size = util_format_get_2d_size(format, transfer->stride, 864 transfer->box.height); 865 iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); 866 867 } else { 868 unsigned nby = util_format_get_nblocksy(format, transfer->box.y); 869 int i; 870 offset += util_format_get_stride(format, transfer->box.x); 871 size = transfer->stride; 872 873 for (i = 0; i < nby; i++) { 874 iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); 875 offset += tex->stride; 876 } 877 } 878 offset += layer_stride; 879 } 880 } else { 881 uint8_t *map = pipe_transfer_map(pipe, &itransfer->b); 882 if (map == NULL) 883 goto nomap; 884 885 for (i = 0; i < box->depth; i++) { 886 util_copy_rect(map, 887 resource->format, 888 itransfer->b.stride, /* bytes */ 889 0, 0, 890 box->width, 891 box->height, 892 src_data, 893 stride, /* bytes */ 894 0, 0); 895 map += itransfer->b.layer_stride; 896 src_data += layer_stride; 897 } 898nomap: 899 if (map) 900 pipe_transfer_unmap(pipe, &itransfer->b); 901 } 902 903out: 904 if (itransfer) 905 pipe_transfer_destroy(pipe, &itransfer->b); 906} 907#endif 908 909struct u_resource_vtbl i915_texture_vtbl = 910{ 911 i915_texture_get_handle, /* get_handle */ 912 i915_texture_destroy, /* resource_destroy */ 913 i915_texture_transfer_map, /* transfer_map */ 914 u_default_transfer_flush_region, /* transfer_flush_region */ 915 i915_texture_transfer_unmap, /* transfer_unmap */ 916}; 917 918 919struct pipe_resource * 920i915_texture_create(struct pipe_screen *screen, 921 const struct pipe_resource *template, 922 boolean force_untiled) 923{ 924 struct i915_screen *is = i915_screen(screen); 925 struct i915_winsys *iws = is->iws; 926 struct i915_texture *tex = CALLOC_STRUCT(i915_texture); 927 unsigned buf_usage = 0; 928 929 if (!tex) 930 return NULL; 931 932 tex->b.b = *template; 933 tex->b.vtbl = &i915_texture_vtbl; 934 pipe_reference_init(&tex->b.b.reference, 1); 935 tex->b.b.screen = screen; 936 937 if ( (force_untiled) || (template->usage == PIPE_USAGE_STREAM) ) 938 tex->tiling = I915_TILE_NONE; 939 else 940 tex->tiling = i915_texture_tiling(is, tex); 941 942 if (is->is_i945) { 943 if (!i945_texture_layout(tex)) 944 goto fail; 945 } else { 946 if (!i915_texture_layout(tex)) 947 goto fail; 948 } 949 950 /* for scanouts and cursors, cursors arn't scanouts */ 951 952 /* XXX: use a custom flag for cursors, don't rely on magically 953 * guessing that this is Xorg asking for a cursor 954 */ 955 if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64) 956 buf_usage = I915_NEW_SCANOUT; 957 else 958 buf_usage = I915_NEW_TEXTURE; 959 960 tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy, 961 &tex->tiling, buf_usage); 962 if (!tex->buffer) 963 goto fail; 964 965 I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__, 966 tex, tex->stride, 967 tex->stride / util_format_get_blocksize(tex->b.b.format), 968 tex->total_nblocksy, get_tiling_string(tex->tiling)); 969 970 return &tex->b.b; 971 972fail: 973 FREE(tex); 974 return NULL; 975} 976 977struct pipe_resource * 978i915_texture_from_handle(struct pipe_screen * screen, 979 const struct pipe_resource *template, 980 struct winsys_handle *whandle) 981{ 982 struct i915_screen *is = i915_screen(screen); 983 struct i915_texture *tex; 984 struct i915_winsys *iws = is->iws; 985 struct i915_winsys_buffer *buffer; 986 unsigned stride; 987 enum i915_winsys_buffer_tile tiling; 988 989 assert(screen); 990 991 buffer = iws->buffer_from_handle(iws, whandle, template->height0, &tiling, &stride); 992 993 /* Only supports one type */ 994 if ((template->target != PIPE_TEXTURE_2D && 995 template->target != PIPE_TEXTURE_RECT) || 996 template->last_level != 0 || 997 template->depth0 != 1) { 998 return NULL; 999 } 1000 1001 tex = CALLOC_STRUCT(i915_texture); 1002 if (!tex) 1003 return NULL; 1004 1005 tex->b.b = *template; 1006 tex->b.vtbl = &i915_texture_vtbl; 1007 pipe_reference_init(&tex->b.b.reference, 1); 1008 tex->b.b.screen = screen; 1009 1010 tex->stride = stride; 1011 tex->tiling = tiling; 1012 tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8); 1013 1014 i915_texture_set_level_info(tex, 0, 1); 1015 i915_texture_set_image_offset(tex, 0, 0, 0, 0); 1016 1017 tex->buffer = buffer; 1018 1019 I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__, 1020 tex, tex->stride, 1021 tex->stride / util_format_get_blocksize(tex->b.b.format), 1022 tex->total_nblocksy, get_tiling_string(tex->tiling)); 1023 1024 return &tex->b.b; 1025} 1026 1027