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 (at) tungstengraphics.com> 30 * Michel Dnzer <michel (at) tungstengraphics.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 */ 59 static 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 */ 71 static 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 */ 83 static 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 92 static INLINE unsigned 93 align_nblocksx(enum pipe_format format, unsigned width, unsigned align_to) 94 { 95 return align(util_format_get_nblocksx(format, width), align_to); 96 } 97 98 static INLINE unsigned 99 align_nblocksy(enum pipe_format format, unsigned width, unsigned align_to) 100 { 101 return align(util_format_get_nblocksy(format, width), align_to); 102 } 103 104 static INLINE unsigned 105 get_pot_stride(enum pipe_format format, unsigned width) 106 { 107 return util_next_power_of_two(util_format_get_stride(format, width)); 108 } 109 110 static INLINE const char* 111 get_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 132 static void 133 i915_texture_set_level_info(struct i915_texture *tex, 134 unsigned level, unsigned nr_images) 135 { 136 assert(level < Elements(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 146 INLINE unsigned i915_texture_offset(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 157 static void 158 i915_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 175 static enum i915_winsys_buffer_tile 176 i915_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 */ 202 static boolean 203 i9x5_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 */ 237 static boolean 238 i9x5_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 */ 268 static boolean 269 i9x5_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 */ 294 static void 295 i9x5_texture_layout_cube(struct i915_texture *tex) 296 { 297 struct pipe_resource *pt = &tex->b.b; 298 const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0); 299 unsigned level; 300 unsigned face; 301 302 assert(pt->width0 == pt->height0); /* cubemap images are square */ 303 304 /* double pitch for cube layouts */ 305 tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4); 306 tex->total_nblocksy = nblocks * 4; 307 308 for (level = 0; level <= pt->last_level; level++) 309 i915_texture_set_level_info(tex, level, 6); 310 311 for (face = 0; face < 6; face++) { 312 unsigned x = initial_offsets[face][0] * nblocks; 313 unsigned y = initial_offsets[face][1] * nblocks; 314 unsigned d = nblocks; 315 316 for (level = 0; level <= pt->last_level; level++) { 317 i915_texture_set_image_offset(tex, level, face, x, y); 318 d >>= 1; 319 x += step_offsets[face][0] * d; 320 y += step_offsets[face][1] * d; 321 } 322 } 323 } 324 325 326 /* 327 * i915 layout functions 328 */ 329 330 331 static void 332 i915_texture_layout_2d(struct i915_texture *tex) 333 { 334 struct pipe_resource *pt = &tex->b.b; 335 unsigned level; 336 unsigned width = pt->width0; 337 unsigned height = pt->height0; 338 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0); 339 unsigned align_y = 2; 340 341 if (util_format_is_s3tc(pt->format)) 342 align_y = 1; 343 344 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4); 345 tex->total_nblocksy = 0; 346 347 for (level = 0; level <= pt->last_level; level++) { 348 i915_texture_set_level_info(tex, level, 1); 349 i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy); 350 351 tex->total_nblocksy += nblocksy; 352 353 width = u_minify(width, 1); 354 height = u_minify(height, 1); 355 nblocksy = align_nblocksy(pt->format, height, align_y); 356 } 357 } 358 359 static void 360 i915_texture_layout_3d(struct i915_texture *tex) 361 { 362 struct pipe_resource *pt = &tex->b.b; 363 unsigned level; 364 365 unsigned width = pt->width0; 366 unsigned height = pt->height0; 367 unsigned depth = pt->depth0; 368 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0); 369 unsigned stack_nblocksy = 0; 370 371 /* Calculate the size of a single slice. 372 */ 373 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4); 374 375 /* XXX: hardware expects/requires 9 levels at minimum. 376 */ 377 for (level = 0; level <= MAX2(8, pt->last_level); level++) { 378 i915_texture_set_level_info(tex, level, depth); 379 380 stack_nblocksy += MAX2(2, nblocksy); 381 382 width = u_minify(width, 1); 383 height = u_minify(height, 1); 384 nblocksy = util_format_get_nblocksy(pt->format, height); 385 } 386 387 /* Fixup depth image_offsets: 388 */ 389 for (level = 0; level <= pt->last_level; level++) { 390 unsigned i; 391 for (i = 0; i < depth; i++) 392 i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy); 393 394 depth = u_minify(depth, 1); 395 } 396 397 /* Multiply slice size by texture depth for total size. It's 398 * remarkable how wasteful of memory the i915 texture layouts 399 * are. They are largely fixed in the i945. 400 */ 401 tex->total_nblocksy = stack_nblocksy * pt->depth0; 402 } 403 404 static boolean 405 i915_texture_layout(struct i915_texture * tex) 406 { 407 switch (tex->b.b.target) { 408 case PIPE_TEXTURE_1D: 409 case PIPE_TEXTURE_2D: 410 case PIPE_TEXTURE_RECT: 411 if (!i9x5_special_layout(tex)) 412 i915_texture_layout_2d(tex); 413 break; 414 case PIPE_TEXTURE_3D: 415 i915_texture_layout_3d(tex); 416 break; 417 case PIPE_TEXTURE_CUBE: 418 i9x5_texture_layout_cube(tex); 419 break; 420 default: 421 assert(0); 422 return FALSE; 423 } 424 425 return TRUE; 426 } 427 428 429 /* 430 * i945 layout functions 431 */ 432 433 434 static void 435 i945_texture_layout_2d(struct i915_texture *tex) 436 { 437 struct pipe_resource *pt = &tex->b.b; 438 int align_x = 4, align_y = 2; 439 unsigned level; 440 unsigned x = 0; 441 unsigned y = 0; 442 unsigned width = pt->width0; 443 unsigned height = pt->height0; 444 unsigned nblocksx = util_format_get_nblocksx(pt->format, pt->width0); 445 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->height0); 446 447 if (util_format_is_s3tc(pt->format)) { 448 align_x = 1; 449 align_y = 1; 450 } 451 452 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4); 453 454 /* May need to adjust pitch to accomodate the placement of 455 * the 2nd mipmap level. This occurs when the alignment 456 * constraints of mipmap placement push the right edge of the 457 * 2nd mipmap level out past the width of its parent. 458 */ 459 if (pt->last_level > 0) { 460 unsigned mip1_nblocksx = 461 align_nblocksx(pt->format, u_minify(pt->width0, 1), align_x) + 462 util_format_get_nblocksx(pt->format, u_minify(pt->width0, 2)); 463 464 if (mip1_nblocksx > nblocksx) 465 tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format); 466 } 467 468 /* Pitch must be a whole number of dwords 469 */ 470 tex->stride = align(tex->stride, 64); 471 tex->total_nblocksy = 0; 472 473 for (level = 0; level <= pt->last_level; level++) { 474 i915_texture_set_level_info(tex, level, 1); 475 i915_texture_set_image_offset(tex, level, 0, x, y); 476 477 /* Because the images are packed better, the final offset 478 * might not be the maximal one: 479 */ 480 tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy); 481 482 /* Layout_below: step right after second mipmap level. 483 */ 484 if (level == 1) { 485 x += nblocksx; 486 } else { 487 y += nblocksy; 488 } 489 490 width = u_minify(width, 1); 491 height = u_minify(height, 1); 492 nblocksx = align_nblocksx(pt->format, width, align_x); 493 nblocksy = align_nblocksy(pt->format, height, align_y); 494 } 495 } 496 497 static void 498 i945_texture_layout_3d(struct i915_texture *tex) 499 { 500 struct pipe_resource *pt = &tex->b.b; 501 unsigned width = pt->width0; 502 unsigned height = pt->height0; 503 unsigned depth = pt->depth0; 504 unsigned nblocksy = util_format_get_nblocksy(pt->format, pt->width0); 505 unsigned pack_x_pitch, pack_x_nr; 506 unsigned pack_y_pitch; 507 unsigned level; 508 509 tex->stride = align(util_format_get_stride(pt->format, pt->width0), 4); 510 tex->total_nblocksy = 0; 511 512 pack_y_pitch = MAX2(nblocksy, 2); 513 pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format); 514 pack_x_nr = 1; 515 516 for (level = 0; level <= pt->last_level; level++) { 517 int x = 0; 518 int y = 0; 519 unsigned q, j; 520 521 i915_texture_set_level_info(tex, level, depth); 522 523 for (q = 0; q < depth;) { 524 for (j = 0; j < pack_x_nr && q < depth; j++, q++) { 525 i915_texture_set_image_offset(tex, level, q, x, y + tex->total_nblocksy); 526 x += pack_x_pitch; 527 } 528 529 x = 0; 530 y += pack_y_pitch; 531 } 532 533 tex->total_nblocksy += y; 534 535 if (pack_x_pitch > 4) { 536 pack_x_pitch >>= 1; 537 pack_x_nr <<= 1; 538 assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride); 539 } 540 541 if (pack_y_pitch > 2) { 542 pack_y_pitch >>= 1; 543 } 544 545 width = u_minify(width, 1); 546 height = u_minify(height, 1); 547 depth = u_minify(depth, 1); 548 nblocksy = util_format_get_nblocksy(pt->format, height); 549 } 550 } 551 552 static void 553 i945_texture_layout_cube(struct i915_texture *tex) 554 { 555 struct pipe_resource *pt = &tex->b.b; 556 const unsigned nblocks = util_format_get_nblocksx(pt->format, pt->width0); 557 const unsigned dim = pt->width0; 558 unsigned level; 559 unsigned face; 560 561 assert(pt->width0 == pt->height0); /* cubemap images are square */ 562 assert(util_next_power_of_two(pt->width0) == pt->width0); /* npot only */ 563 assert(util_format_is_s3tc(pt->format)); /* compressed only */ 564 565 /* 566 * Depending on the size of the largest images, pitch can be 567 * determined either by the old-style packing of cubemap faces, 568 * or the final row of 4x4, 2x2 and 1x1 faces below this. 569 * 570 * 64 * 2 / 4 = 32 571 * 14 * 2 = 28 572 */ 573 if (pt->width0 >= 64) 574 tex->stride = nblocks * 2 * util_format_get_blocksize(pt->format); 575 else 576 tex->stride = 14 * 2 * util_format_get_blocksize(pt->format); 577 578 /* 579 * Something similary apply for height as well. 580 */ 581 if (pt->width0 >= 4) 582 tex->total_nblocksy = nblocks * 4 + 1; 583 else 584 tex->total_nblocksy = 1; 585 586 /* Set all the levels to effectively occupy the whole rectangular region */ 587 for (level = 0; level <= pt->last_level; level++) 588 i915_texture_set_level_info(tex, level, 6); 589 590 for (face = 0; face < 6; face++) { 591 /* all calculations in pixels */ 592 unsigned total_height = tex->total_nblocksy * 4; 593 unsigned x = initial_offsets[face][0] * dim; 594 unsigned y = initial_offsets[face][1] * dim; 595 unsigned d = dim; 596 597 if (dim == 4 && face >= 4) { 598 x = (face - 4) * 8; 599 y = tex->total_nblocksy * 4 - 4; /* 4 = 1 block */ 600 } else if (dim < 4 && (face > 0)) { 601 x = face * 8; 602 y = total_height - 4; 603 } 604 605 for (level = 0; level <= pt->last_level; level++) { 606 i915_texture_set_image_offset(tex, level, face, 607 util_format_get_nblocksx(pt->format, x), 608 util_format_get_nblocksy(pt->format, y)); 609 610 d >>= 1; 611 612 switch (d) { 613 case 4: 614 switch (face) { 615 case PIPE_TEX_FACE_POS_X: 616 case PIPE_TEX_FACE_NEG_X: 617 x += step_offsets[face][0] * d; 618 y += step_offsets[face][1] * d; 619 break; 620 case PIPE_TEX_FACE_POS_Y: 621 case PIPE_TEX_FACE_NEG_Y: 622 y += 12; 623 x -= 8; 624 break; 625 case PIPE_TEX_FACE_POS_Z: 626 case PIPE_TEX_FACE_NEG_Z: 627 y = total_height - 4; 628 x = (face - 4) * 8; 629 break; 630 } 631 break; 632 case 2: 633 y = total_height - 4; 634 x = bottom_offsets[face]; 635 break; 636 case 1: 637 x += 48; 638 break; 639 default: 640 x += step_offsets[face][0] * d; 641 y += step_offsets[face][1] * d; 642 break; 643 } 644 } 645 } 646 } 647 648 static boolean 649 i945_texture_layout(struct i915_texture * tex) 650 { 651 switch (tex->b.b.target) { 652 case PIPE_TEXTURE_1D: 653 case PIPE_TEXTURE_2D: 654 case PIPE_TEXTURE_RECT: 655 if (!i9x5_special_layout(tex)) 656 i945_texture_layout_2d(tex); 657 break; 658 case PIPE_TEXTURE_3D: 659 i945_texture_layout_3d(tex); 660 break; 661 case PIPE_TEXTURE_CUBE: 662 if (!util_format_is_s3tc(tex->b.b.format)) 663 i9x5_texture_layout_cube(tex); 664 else 665 i945_texture_layout_cube(tex); 666 break; 667 default: 668 assert(0); 669 return FALSE; 670 } 671 672 return TRUE; 673 } 674 675 676 677 /* 678 * Screen texture functions 679 */ 680 681 682 683 static boolean 684 i915_texture_get_handle(struct pipe_screen * screen, 685 struct pipe_resource *texture, 686 struct winsys_handle *whandle) 687 { 688 struct i915_screen *is = i915_screen(screen); 689 struct i915_texture *tex = i915_texture(texture); 690 struct i915_winsys *iws = is->iws; 691 692 return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride); 693 } 694 695 696 static void 697 i915_texture_destroy(struct pipe_screen *screen, 698 struct pipe_resource *pt) 699 { 700 struct i915_texture *tex = i915_texture(pt); 701 struct i915_winsys *iws = i915_screen(screen)->iws; 702 uint i; 703 704 if (tex->buffer) 705 iws->buffer_destroy(iws, tex->buffer); 706 707 for (i = 0; i < Elements(tex->image_offset); i++) 708 if (tex->image_offset[i]) 709 FREE(tex->image_offset[i]); 710 711 FREE(tex); 712 } 713 714 static struct pipe_transfer * 715 i915_texture_get_transfer(struct pipe_context *pipe, 716 struct pipe_resource *resource, 717 unsigned level, 718 unsigned usage, 719 const struct pipe_box *box) 720 { 721 struct i915_context *i915 = i915_context(pipe); 722 struct i915_texture *tex = i915_texture(resource); 723 struct i915_transfer *transfer = util_slab_alloc(&i915->texture_transfer_pool); 724 boolean use_staging_texture = FALSE; 725 726 if (transfer == NULL) 727 return NULL; 728 729 transfer->b.resource = resource; 730 transfer->b.level = level; 731 transfer->b.usage = usage; 732 transfer->b.box = *box; 733 transfer->b.stride = tex->stride; 734 transfer->staging_texture = NULL; 735 /* XXX: handle depth textures everyhwere*/ 736 transfer->b.layer_stride = 0; 737 transfer->b.data = NULL; 738 739 /* if we use staging transfers, only support textures we can render to, 740 * because we need that for u_blitter */ 741 if (i915->blitter && 742 util_blitter_is_copy_supported(i915->blitter, resource, resource, 743 PIPE_MASK_RGBAZS) && 744 (usage & PIPE_TRANSFER_WRITE) && 745 !(usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED))) 746 use_staging_texture = TRUE; 747 748 use_staging_texture = FALSE; 749 750 if (use_staging_texture) { 751 /* 752 * Allocate the untiled staging texture. 753 * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map() 754 */ 755 transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE); 756 } 757 758 return (struct pipe_transfer*)transfer; 759 } 760 761 static void 762 i915_transfer_destroy(struct pipe_context *pipe, 763 struct pipe_transfer *transfer) 764 { 765 struct i915_context *i915 = i915_context(pipe); 766 struct i915_transfer *itransfer = (struct i915_transfer*)transfer; 767 768 if ((itransfer->staging_texture) && 769 (transfer->usage & PIPE_TRANSFER_WRITE)) { 770 struct pipe_box sbox; 771 772 u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox); 773 pipe->resource_copy_region(pipe, itransfer->b.resource, itransfer->b.level, 774 itransfer->b.box.x, itransfer->b.box.y, itransfer->b.box.z, 775 itransfer->staging_texture, 776 0, &sbox); 777 pipe->flush(pipe, NULL); 778 pipe_resource_reference(&itransfer->staging_texture, NULL); 779 } 780 781 util_slab_free(&i915->texture_transfer_pool, itransfer); 782 } 783 784 static void * 785 i915_texture_transfer_map(struct pipe_context *pipe, 786 struct pipe_transfer *transfer) 787 { 788 struct i915_transfer *itransfer = (struct i915_transfer*)transfer; 789 struct pipe_resource *resource = itransfer->b.resource; 790 struct i915_texture *tex = NULL; 791 struct i915_winsys *iws = i915_screen(pipe->screen)->iws; 792 struct pipe_box *box = &itransfer->b.box; 793 enum pipe_format format = resource->format; 794 unsigned offset; 795 char *map; 796 797 if (resource->target != PIPE_TEXTURE_3D && 798 resource->target != PIPE_TEXTURE_CUBE) 799 assert(box->z == 0); 800 801 if (itransfer->staging_texture) { 802 tex = i915_texture(itransfer->staging_texture); 803 } else { 804 /* TODO this is a sledgehammer */ 805 tex = i915_texture(resource); 806 pipe->flush(pipe, NULL); 807 } 808 809 offset = i915_texture_offset(tex, itransfer->b.level, box->z); 810 811 map = iws->buffer_map(iws, tex->buffer, 812 (itransfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE); 813 if (map == NULL) { 814 return NULL; 815 } 816 817 return map + offset + 818 box->y / util_format_get_blockheight(format) * itransfer->b.stride + 819 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 820 } 821 822 static void 823 i915_texture_transfer_unmap(struct pipe_context *pipe, 824 struct pipe_transfer *transfer) 825 { 826 struct i915_transfer *itransfer = (struct i915_transfer*)transfer; 827 struct i915_texture *tex = i915_texture(itransfer->b.resource); 828 struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; 829 830 if (itransfer->staging_texture) 831 tex = i915_texture(itransfer->staging_texture); 832 833 iws->buffer_unmap(iws, tex->buffer); 834 } 835 836 static void i915_transfer_inline_write( struct pipe_context *pipe, 837 struct pipe_resource *resource, 838 unsigned level, 839 unsigned usage, 840 const struct pipe_box *box, 841 const void *data, 842 unsigned stride, 843 unsigned layer_stride) 844 { 845 struct pipe_transfer *transfer = NULL; 846 struct i915_transfer *itransfer = NULL; 847 const uint8_t *src_data = data; 848 unsigned i; 849 850 transfer = pipe->get_transfer(pipe, 851 resource, 852 level, 853 usage, 854 box ); 855 if (transfer == NULL) 856 goto out; 857 858 itransfer = (struct i915_transfer*)transfer; 859 860 if (itransfer->staging_texture) { 861 struct i915_texture *tex = i915_texture(itransfer->staging_texture); 862 enum pipe_format format = tex->b.b.format; 863 struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws; 864 size_t offset; 865 size_t size; 866 867 offset = i915_texture_offset(tex, transfer->level, transfer->box.z); 868 869 for (i = 0; i < box->depth; i++) { 870 if (!tex->b.b.last_level && 871 tex->b.b.width0 == transfer->box.width) { 872 unsigned nby = util_format_get_nblocksy(format, transfer->box.y); 873 assert(!offset); 874 assert(!transfer->box.x); 875 assert(tex->stride == transfer->stride); 876 877 offset += tex->stride * nby; 878 size = util_format_get_2d_size(format, transfer->stride, 879 transfer->box.height); 880 iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); 881 882 } else { 883 unsigned nby = util_format_get_nblocksy(format, transfer->box.y); 884 int i; 885 offset += util_format_get_stride(format, transfer->box.x); 886 size = transfer->stride; 887 888 for (i = 0; i < nby; i++) { 889 iws->buffer_write(iws, tex->buffer, offset, size, transfer->data); 890 offset += tex->stride; 891 } 892 } 893 offset += layer_stride; 894 } 895 } else { 896 uint8_t *map = pipe_transfer_map(pipe, &itransfer->b); 897 if (map == NULL) 898 goto nomap; 899 900 for (i = 0; i < box->depth; i++) { 901 util_copy_rect(map, 902 resource->format, 903 itransfer->b.stride, /* bytes */ 904 0, 0, 905 box->width, 906 box->height, 907 src_data, 908 stride, /* bytes */ 909 0, 0); 910 map += itransfer->b.layer_stride; 911 src_data += layer_stride; 912 } 913 nomap: 914 if (map) 915 pipe_transfer_unmap(pipe, &itransfer->b); 916 } 917 918 out: 919 if (itransfer) 920 pipe_transfer_destroy(pipe, &itransfer->b); 921 } 922 923 924 925 struct u_resource_vtbl i915_texture_vtbl = 926 { 927 i915_texture_get_handle, /* get_handle */ 928 i915_texture_destroy, /* resource_destroy */ 929 i915_texture_get_transfer, /* get_transfer */ 930 i915_transfer_destroy, /* transfer_destroy */ 931 i915_texture_transfer_map, /* transfer_map */ 932 u_default_transfer_flush_region, /* transfer_flush_region */ 933 i915_texture_transfer_unmap, /* transfer_unmap */ 934 i915_transfer_inline_write /* transfer_inline_write */ 935 }; 936 937 938 939 940 struct pipe_resource * 941 i915_texture_create(struct pipe_screen *screen, 942 const struct pipe_resource *template, 943 boolean force_untiled) 944 { 945 struct i915_screen *is = i915_screen(screen); 946 struct i915_winsys *iws = is->iws; 947 struct i915_texture *tex = CALLOC_STRUCT(i915_texture); 948 unsigned buf_usage = 0; 949 950 if (!tex) 951 return NULL; 952 953 tex->b.b = *template; 954 tex->b.vtbl = &i915_texture_vtbl; 955 pipe_reference_init(&tex->b.b.reference, 1); 956 tex->b.b.screen = screen; 957 958 if ( (force_untiled) || (template->usage == PIPE_USAGE_STREAM) ) 959 tex->tiling = I915_TILE_NONE; 960 else 961 tex->tiling = i915_texture_tiling(is, tex); 962 963 if (is->is_i945) { 964 if (!i945_texture_layout(tex)) 965 goto fail; 966 } else { 967 if (!i915_texture_layout(tex)) 968 goto fail; 969 } 970 971 /* for scanouts and cursors, cursors arn't scanouts */ 972 973 /* XXX: use a custom flag for cursors, don't rely on magically 974 * guessing that this is Xorg asking for a cursor 975 */ 976 if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64) 977 buf_usage = I915_NEW_SCANOUT; 978 else 979 buf_usage = I915_NEW_TEXTURE; 980 981 tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy, 982 &tex->tiling, buf_usage); 983 if (!tex->buffer) 984 goto fail; 985 986 I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__, 987 tex, tex->stride, 988 tex->stride / util_format_get_blocksize(tex->b.b.format), 989 tex->total_nblocksy, get_tiling_string(tex->tiling)); 990 991 return &tex->b.b; 992 993 fail: 994 FREE(tex); 995 return NULL; 996 } 997 998 struct pipe_resource * 999 i915_texture_from_handle(struct pipe_screen * screen, 1000 const struct pipe_resource *template, 1001 struct winsys_handle *whandle) 1002 { 1003 struct i915_screen *is = i915_screen(screen); 1004 struct i915_texture *tex; 1005 struct i915_winsys *iws = is->iws; 1006 struct i915_winsys_buffer *buffer; 1007 unsigned stride; 1008 enum i915_winsys_buffer_tile tiling; 1009 1010 assert(screen); 1011 1012 buffer = iws->buffer_from_handle(iws, whandle, &tiling, &stride); 1013 1014 /* Only supports one type */ 1015 if ((template->target != PIPE_TEXTURE_2D && 1016 template->target != PIPE_TEXTURE_RECT) || 1017 template->last_level != 0 || 1018 template->depth0 != 1) { 1019 return NULL; 1020 } 1021 1022 tex = CALLOC_STRUCT(i915_texture); 1023 if (!tex) 1024 return NULL; 1025 1026 tex->b.b = *template; 1027 tex->b.vtbl = &i915_texture_vtbl; 1028 pipe_reference_init(&tex->b.b.reference, 1); 1029 tex->b.b.screen = screen; 1030 1031 tex->stride = stride; 1032 tex->tiling = tiling; 1033 tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8); 1034 1035 i915_texture_set_level_info(tex, 0, 1); 1036 i915_texture_set_image_offset(tex, 0, 0, 0, 0); 1037 1038 tex->buffer = buffer; 1039 1040 I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__, 1041 tex, tex->stride, 1042 tex->stride / util_format_get_blocksize(tex->b.b.format), 1043 tex->total_nblocksy, get_tiling_string(tex->tiling)); 1044 1045 return &tex->b.b; 1046 } 1047 1048