r600_texture.c revision ee07e0e39ad1c4d13d540b23220fecc564d07b16
1/* 2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Jerome Glisse 25 * Corbin Simpson 26 */ 27#include <errno.h> 28#include <pipe/p_screen.h> 29#include <util/u_format.h> 30#include <util/u_math.h> 31#include <util/u_inlines.h> 32#include <util/u_memory.h> 33#include "state_tracker/drm_driver.h" 34#include "pipebuffer/pb_buffer.h" 35#include "r600_pipe.h" 36#include "r600_resource.h" 37#include "r600_state_inlines.h" 38#include "r600d.h" 39#include "r600_formats.h" 40 41extern struct u_resource_vtbl r600_texture_vtbl; 42 43/* Copy from a full GPU texture to a transfer's staging one. */ 44static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 45{ 46 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 47 struct pipe_resource *texture = transfer->resource; 48 struct pipe_subresource subdst; 49 50 subdst.face = 0; 51 subdst.level = 0; 52 ctx->resource_copy_region(ctx, rtransfer->staging_texture, 53 subdst, 0, 0, 0, texture, transfer->sr, 54 transfer->box.x, transfer->box.y, transfer->box.z, 55 transfer->box.width, transfer->box.height); 56} 57 58 59/* Copy from a transfer's staging texture to a full GPU one. */ 60static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 61{ 62 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 63 struct pipe_resource *texture = transfer->resource; 64 struct pipe_subresource subsrc; 65 66 subsrc.face = 0; 67 subsrc.level = 0; 68 ctx->resource_copy_region(ctx, texture, transfer->sr, 69 transfer->box.x, transfer->box.y, transfer->box.z, 70 rtransfer->staging_texture, subsrc, 71 0, 0, 0, 72 transfer->box.width, transfer->box.height); 73 74 ctx->flush(ctx, 0, NULL); 75} 76 77static unsigned r600_texture_get_offset(struct r600_resource_texture *rtex, 78 unsigned level, unsigned zslice, 79 unsigned face) 80{ 81 unsigned offset = rtex->offset[level]; 82 83 switch (rtex->resource.base.b.target) { 84 case PIPE_TEXTURE_3D: 85 assert(face == 0); 86 return offset + zslice * rtex->layer_size[level]; 87 case PIPE_TEXTURE_CUBE: 88 assert(zslice == 0); 89 return offset + face * rtex->layer_size[level]; 90 default: 91 assert(zslice == 0 && face == 0); 92 return offset; 93 } 94} 95 96static unsigned r600_get_pixel_alignment(struct pipe_screen *screen, 97 enum pipe_format format, 98 unsigned array_mode) 99{ 100 struct r600_screen* rscreen = (struct r600_screen *)screen; 101 unsigned pixsize = util_format_get_blocksize(format); 102 int p_align; 103 104 switch(array_mode) { 105 case V_038000_ARRAY_1D_TILED_THIN1: 106 p_align = MAX2(8, 107 ((rscreen->tiling_info->group_bytes / 8 / pixsize))); 108 break; 109 case V_038000_ARRAY_2D_TILED_THIN1: 110 p_align = MAX2(rscreen->tiling_info->num_banks, 111 (((rscreen->tiling_info->group_bytes / 8 / pixsize)) * 112 rscreen->tiling_info->num_banks)); 113 break; 114 case 0: 115 default: 116 p_align = 64; 117 break; 118 } 119 return p_align; 120} 121 122static unsigned r600_get_height_alignment(struct pipe_screen *screen, 123 unsigned array_mode) 124{ 125 struct r600_screen* rscreen = (struct r600_screen *)screen; 126 int h_align; 127 128 switch (array_mode) { 129 case V_038000_ARRAY_2D_TILED_THIN1: 130 h_align = rscreen->tiling_info->num_channels * 8; 131 break; 132 case V_038000_ARRAY_1D_TILED_THIN1: 133 h_align = 8; 134 break; 135 default: 136 h_align = 1; 137 break; 138 } 139 return h_align; 140} 141 142static unsigned mip_minify(unsigned size, unsigned level) 143{ 144 unsigned val; 145 val = u_minify(size, level); 146 if (level > 0) 147 val = util_next_power_of_two(val); 148 return val; 149} 150 151static unsigned r600_texture_get_stride(struct pipe_screen *screen, 152 struct r600_resource_texture *rtex, 153 unsigned level) 154{ 155 struct pipe_resource *ptex = &rtex->resource.base.b; 156 struct radeon *radeon = (struct radeon *)screen->winsys; 157 enum chip_class chipc = r600_get_family_class(radeon); 158 unsigned width, stride, tile_width; 159 160 if (rtex->pitch_override) 161 return rtex->pitch_override; 162 163 width = mip_minify(ptex->width0, level); 164 if (util_format_is_plain(ptex->format)) { 165 tile_width = r600_get_pixel_alignment(screen, ptex->format, 166 rtex->array_mode[level]); 167 width = align(width, tile_width); 168 } 169 stride = util_format_get_stride(ptex->format, width); 170 if (chipc == EVERGREEN) 171 stride = align(stride, 512); 172 return stride; 173} 174 175static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen, 176 struct r600_resource_texture *rtex, 177 unsigned level) 178{ 179 struct pipe_resource *ptex = &rtex->resource.base.b; 180 unsigned height, tile_height; 181 182 height = mip_minify(ptex->height0, level); 183 if (util_format_is_plain(ptex->format)) { 184 tile_height = r600_get_height_alignment(screen, 185 rtex->array_mode[level]); 186 height = align(height, tile_height); 187 } 188 return util_format_get_nblocksy(ptex->format, height); 189} 190 191/* Get a width in pixels from a stride in bytes. */ 192static unsigned pitch_to_width(enum pipe_format format, 193 unsigned pitch_in_bytes) 194{ 195 return (pitch_in_bytes / util_format_get_blocksize(format)) * 196 util_format_get_blockwidth(format); 197} 198 199static void r600_texture_set_array_mode(struct pipe_screen *screen, 200 struct r600_resource_texture *rtex, 201 unsigned level, unsigned array_mode) 202{ 203 struct pipe_resource *ptex = &rtex->resource.base.b; 204 205 switch (array_mode) { 206 case V_0280A0_ARRAY_LINEAR_GENERAL: 207 case V_0280A0_ARRAY_LINEAR_ALIGNED: 208 case V_0280A0_ARRAY_1D_TILED_THIN1: 209 default: 210 rtex->array_mode[level] = array_mode; 211 break; 212 case V_0280A0_ARRAY_2D_TILED_THIN1: 213 { 214 unsigned w, h, tile_height, tile_width; 215 216 tile_height = r600_get_height_alignment(screen, array_mode); 217 tile_width = r600_get_pixel_alignment(screen, ptex->format, array_mode); 218 219 w = mip_minify(ptex->width0, level); 220 h = mip_minify(ptex->height0, level); 221 if (w < tile_width || h < tile_height) 222 rtex->array_mode[level] = V_0280A0_ARRAY_1D_TILED_THIN1; 223 else 224 rtex->array_mode[level] = array_mode; 225 } 226 break; 227 } 228} 229 230static void r600_setup_miptree(struct pipe_screen *screen, 231 struct r600_resource_texture *rtex, 232 unsigned array_mode) 233{ 234 struct pipe_resource *ptex = &rtex->resource.base.b; 235 struct radeon *radeon = (struct radeon *)screen->winsys; 236 enum chip_class chipc = r600_get_family_class(radeon); 237 unsigned pitch, size, layer_size, i, offset; 238 unsigned nblocksy; 239 240 for (i = 0, offset = 0; i <= ptex->last_level; i++) { 241 r600_texture_set_array_mode(screen, rtex, i, array_mode); 242 243 pitch = r600_texture_get_stride(screen, rtex, i); 244 nblocksy = r600_texture_get_nblocksy(screen, rtex, i); 245 246 layer_size = pitch * nblocksy; 247 248 if (ptex->target == PIPE_TEXTURE_CUBE) { 249 if (chipc >= R700) 250 size = layer_size * 8; 251 else 252 size = layer_size * 6; 253 } 254 else 255 size = layer_size * u_minify(ptex->depth0, i); 256 rtex->offset[i] = offset; 257 rtex->layer_size[i] = layer_size; 258 rtex->pitch_in_bytes[i] = pitch; 259 rtex->pitch_in_pixels[i] = pitch_to_width(ptex->format, pitch); 260 offset += size; 261 } 262 rtex->size = offset; 263} 264 265static struct r600_resource_texture * 266r600_texture_create_object(struct pipe_screen *screen, 267 const struct pipe_resource *base, 268 unsigned array_mode, 269 unsigned pitch_in_bytes_override, 270 unsigned max_buffer_size, 271 struct r600_bo *bo) 272{ 273 struct r600_resource_texture *rtex; 274 struct r600_resource *resource; 275 struct radeon *radeon = (struct radeon *)screen->winsys; 276 277 rtex = CALLOC_STRUCT(r600_resource_texture); 278 if (rtex == NULL) 279 return NULL; 280 281 resource = &rtex->resource; 282 resource->base.b = *base; 283 resource->base.vtbl = &r600_texture_vtbl; 284 pipe_reference_init(&resource->base.b.reference, 1); 285 resource->base.b.screen = screen; 286 resource->bo = bo; 287 rtex->pitch_override = pitch_in_bytes_override; 288 289 if (array_mode) 290 rtex->tiled = 1; 291 r600_setup_miptree(screen, rtex, array_mode); 292 293 resource->size = rtex->size; 294 295 if (!resource->bo) { 296 resource->bo = r600_bo(radeon, rtex->size, 4096, base->bind, base->usage); 297 if (!resource->bo) { 298 FREE(rtex); 299 return NULL; 300 } 301 } 302 return rtex; 303} 304 305struct pipe_resource *r600_texture_create(struct pipe_screen *screen, 306 const struct pipe_resource *templ) 307{ 308 unsigned array_mode = 0; 309 static int force_tiling = -1; 310 311 /* Would like some magic "get_bool_option_once" routine. 312 */ 313 if (force_tiling == -1) 314 force_tiling = debug_get_bool_option("R600_FORCE_TILING", FALSE); 315 316 if (force_tiling) { 317 if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) && 318 !(templ->bind & PIPE_BIND_SCANOUT)) { 319 array_mode = V_038000_ARRAY_2D_TILED_THIN1; 320 } 321 } 322 323 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, 324 0, 0, NULL); 325 326} 327 328static void r600_texture_destroy(struct pipe_screen *screen, 329 struct pipe_resource *ptex) 330{ 331 struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; 332 struct r600_resource *resource = &rtex->resource; 333 struct radeon *radeon = (struct radeon *)screen->winsys; 334 335 if (rtex->flushed_depth_texture) 336 pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); 337 338 if (resource->bo) { 339 r600_bo_reference(radeon, &resource->bo, NULL); 340 } 341 FREE(rtex); 342} 343 344static struct pipe_surface *r600_get_tex_surface(struct pipe_screen *screen, 345 struct pipe_resource *texture, 346 unsigned face, unsigned level, 347 unsigned zslice, unsigned flags) 348{ 349 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 350 struct r600_surface *surface = CALLOC_STRUCT(r600_surface); 351 unsigned offset, tile_height; 352 353 if (surface == NULL) 354 return NULL; 355 offset = r600_texture_get_offset(rtex, level, zslice, face); 356 pipe_reference_init(&surface->base.reference, 1); 357 pipe_resource_reference(&surface->base.texture, texture); 358 surface->base.format = texture->format; 359 surface->base.width = mip_minify(texture->width0, level); 360 surface->base.height = mip_minify(texture->height0, level); 361 surface->base.offset = offset; 362 surface->base.usage = flags; 363 surface->base.zslice = zslice; 364 surface->base.texture = texture; 365 surface->base.face = face; 366 surface->base.level = level; 367 368 tile_height = r600_get_height_alignment(screen, rtex->array_mode[level]); 369 surface->aligned_height = align(surface->base.height, tile_height); 370 return &surface->base; 371} 372 373static void r600_tex_surface_destroy(struct pipe_surface *surface) 374{ 375 pipe_resource_reference(&surface->texture, NULL); 376 FREE(surface); 377} 378 379 380struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, 381 const struct pipe_resource *templ, 382 struct winsys_handle *whandle) 383{ 384 struct radeon *rw = (struct radeon*)screen->winsys; 385 struct r600_bo *bo = NULL; 386 unsigned array_mode = 0; 387 388 /* Support only 2D textures without mipmaps */ 389 if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) || 390 templ->depth0 != 1 || templ->last_level != 0) 391 return NULL; 392 393 bo = r600_bo_handle(rw, whandle->handle, &array_mode); 394 if (bo == NULL) { 395 return NULL; 396 } 397 398 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, 399 whandle->stride, 400 0, 401 bo); 402} 403 404static unsigned int r600_texture_is_referenced(struct pipe_context *context, 405 struct pipe_resource *texture, 406 unsigned face, unsigned level) 407{ 408 /* FIXME */ 409 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 410} 411 412int (*r600_blit_uncompress_depth_ptr)(struct pipe_context *ctx, struct r600_resource_texture *texture); 413 414int r600_texture_depth_flush(struct pipe_context *ctx, 415 struct pipe_resource *texture) 416{ 417 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 418 struct pipe_resource resource; 419 420 if (rtex->flushed_depth_texture) 421 goto out; 422 423 resource.target = PIPE_TEXTURE_2D; 424 resource.format = texture->format; 425 resource.width0 = texture->width0; 426 resource.height0 = texture->height0; 427 resource.depth0 = 1; 428 resource.last_level = 0; 429 resource.nr_samples = 0; 430 resource.usage = PIPE_USAGE_DYNAMIC; 431 resource.bind = 0; 432 resource.flags = R600_RESOURCE_FLAG_TRANSFER; 433 434 resource.bind |= PIPE_BIND_DEPTH_STENCIL; 435 436 rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource); 437 if (rtex->flushed_depth_texture == NULL) { 438 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 439 return -ENOMEM; 440 } 441 442out: 443 /* XXX: only do this if the depth texture has actually changed: 444 */ 445 r600_blit_uncompress_depth_ptr(ctx, rtex); 446 return 0; 447} 448 449/* Needs adjustment for pixelformat: 450 */ 451static INLINE unsigned u_box_volume( const struct pipe_box *box ) 452{ 453 return box->width * box->depth * box->height; 454}; 455 456 457struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, 458 struct pipe_resource *texture, 459 struct pipe_subresource sr, 460 unsigned usage, 461 const struct pipe_box *box) 462{ 463 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 464 struct pipe_resource resource; 465 struct r600_transfer *trans; 466 int r; 467 boolean use_staging_texture = FALSE; 468 boolean discard = FALSE; 469 470 if (!(usage & PIPE_TRANSFER_READ) && (usage & PIPE_TRANSFER_DISCARD)) 471 discard = TRUE; 472 473 /* We cannot map a tiled texture directly because the data is 474 * in a different order, therefore we do detiling using a blit. 475 * 476 * Also, use a temporary in GTT memory for read transfers, as 477 * the CPU is much happier reading out of cached system memory 478 * than uncached VRAM. 479 */ 480 if (rtex->tiled) 481 use_staging_texture = TRUE; 482 483 if (usage & PIPE_TRANSFER_READ && 484 u_box_volume(box) > 1024) 485 use_staging_texture = TRUE; 486 487 /* XXX: Use a staging texture for uploads if the underlying BO 488 * is busy. No interface for checking that currently? so do 489 * it eagerly whenever the transfer doesn't require a readback 490 * and might block. 491 */ 492 if ((usage & PIPE_TRANSFER_WRITE) && 493 discard && 494 !(usage & (PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED))) 495 use_staging_texture = TRUE; 496 497 trans = CALLOC_STRUCT(r600_transfer); 498 if (trans == NULL) 499 return NULL; 500 pipe_resource_reference(&trans->transfer.resource, texture); 501 trans->transfer.sr = sr; 502 trans->transfer.usage = usage; 503 trans->transfer.box = *box; 504 if (rtex->depth) { 505 /* XXX: only readback the rectangle which is being mapped? 506 */ 507 /* XXX: when discard is true, no need to read back from depth texture 508 */ 509 r = r600_texture_depth_flush(ctx, texture); 510 if (r < 0) { 511 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 512 pipe_resource_reference(&trans->transfer.resource, NULL); 513 FREE(trans); 514 return NULL; 515 } 516 } else if (use_staging_texture) { 517 resource.target = PIPE_TEXTURE_2D; 518 resource.format = texture->format; 519 resource.width0 = box->width; 520 resource.height0 = box->height; 521 resource.depth0 = 1; 522 resource.last_level = 0; 523 resource.nr_samples = 0; 524 resource.usage = PIPE_USAGE_STAGING; 525 resource.bind = 0; 526 resource.flags = R600_RESOURCE_FLAG_TRANSFER; 527 /* For texture reading, the temporary (detiled) texture is used as 528 * a render target when blitting from a tiled texture. */ 529 if (usage & PIPE_TRANSFER_READ) { 530 resource.bind |= PIPE_BIND_RENDER_TARGET; 531 } 532 /* For texture writing, the temporary texture is used as a sampler 533 * when blitting into a tiled texture. */ 534 if (usage & PIPE_TRANSFER_WRITE) { 535 resource.bind |= PIPE_BIND_SAMPLER_VIEW; 536 } 537 /* Create the temporary texture. */ 538 trans->staging_texture = ctx->screen->resource_create(ctx->screen, &resource); 539 if (trans->staging_texture == NULL) { 540 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 541 pipe_resource_reference(&trans->transfer.resource, NULL); 542 FREE(trans); 543 return NULL; 544 } 545 546 trans->transfer.stride = 547 ((struct r600_resource_texture *)trans->staging_texture)->pitch_in_bytes[0]; 548 if (!discard) { 549 r600_copy_to_staging_texture(ctx, trans); 550 /* Always referenced in the blit. */ 551 ctx->flush(ctx, 0, NULL); 552 } 553 return &trans->transfer; 554 } 555 trans->transfer.stride = rtex->pitch_in_bytes[sr.level]; 556 trans->offset = r600_texture_get_offset(rtex, sr.level, box->z, sr.face); 557 return &trans->transfer; 558} 559 560void r600_texture_transfer_destroy(struct pipe_context *ctx, 561 struct pipe_transfer *transfer) 562{ 563 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 564 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; 565 566 if (rtransfer->staging_texture) { 567 if (transfer->usage & PIPE_TRANSFER_WRITE) { 568 r600_copy_from_staging_texture(ctx, rtransfer); 569 } 570 pipe_resource_reference(&rtransfer->staging_texture, NULL); 571 } 572 if (rtex->flushed_depth_texture) { 573 pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); 574 } 575 pipe_resource_reference(&transfer->resource, NULL); 576 FREE(transfer); 577} 578 579void* r600_texture_transfer_map(struct pipe_context *ctx, 580 struct pipe_transfer* transfer) 581{ 582 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 583 struct r600_bo *bo; 584 enum pipe_format format = transfer->resource->format; 585 struct radeon *radeon = (struct radeon *)ctx->screen->winsys; 586 unsigned offset = 0; 587 unsigned usage = 0; 588 char *map; 589 590 if (rtransfer->staging_texture) { 591 bo = ((struct r600_resource *)rtransfer->staging_texture)->bo; 592 } else { 593 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; 594 595 if (rtex->flushed_depth_texture) 596 bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo; 597 else 598 bo = ((struct r600_resource *)transfer->resource)->bo; 599 600 offset = rtransfer->offset + 601 transfer->box.y / util_format_get_blockheight(format) * transfer->stride + 602 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 603 } 604 605 if (transfer->usage & PIPE_TRANSFER_WRITE) { 606 usage |= PB_USAGE_CPU_WRITE; 607 608 if (transfer->usage & PIPE_TRANSFER_DISCARD) { 609 } 610 611 if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) { 612 } 613 } 614 615 if (transfer->usage & PIPE_TRANSFER_READ) { 616 usage |= PB_USAGE_CPU_READ; 617 } 618 619 if (transfer->usage & PIPE_TRANSFER_DONTBLOCK) { 620 usage |= PB_USAGE_DONTBLOCK; 621 } 622 623 if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) { 624 usage |= PB_USAGE_UNSYNCHRONIZED; 625 } 626 627 map = r600_bo_map(radeon, bo, usage, ctx); 628 if (!map) { 629 return NULL; 630 } 631 632 return map + offset; 633} 634 635void r600_texture_transfer_unmap(struct pipe_context *ctx, 636 struct pipe_transfer* transfer) 637{ 638 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 639 struct radeon *radeon = (struct radeon *)ctx->screen->winsys; 640 struct r600_bo *bo; 641 642 if (rtransfer->staging_texture) { 643 bo = ((struct r600_resource *)rtransfer->staging_texture)->bo; 644 } else { 645 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; 646 647 if (rtex->flushed_depth_texture) { 648 bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo; 649 } else { 650 bo = ((struct r600_resource *)transfer->resource)->bo; 651 } 652 } 653 r600_bo_unmap(radeon, bo); 654} 655 656struct u_resource_vtbl r600_texture_vtbl = 657{ 658 u_default_resource_get_handle, /* get_handle */ 659 r600_texture_destroy, /* resource_destroy */ 660 r600_texture_is_referenced, /* is_resource_referenced */ 661 r600_texture_get_transfer, /* get_transfer */ 662 r600_texture_transfer_destroy, /* transfer_destroy */ 663 r600_texture_transfer_map, /* transfer_map */ 664 u_default_transfer_flush_region,/* transfer_flush_region */ 665 r600_texture_transfer_unmap, /* transfer_unmap */ 666 u_default_transfer_inline_write /* transfer_inline_write */ 667}; 668 669void r600_init_screen_texture_functions(struct pipe_screen *screen) 670{ 671 screen->get_tex_surface = r600_get_tex_surface; 672 screen->tex_surface_destroy = r600_tex_surface_destroy; 673} 674 675static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, 676 const unsigned char *swizzle_view) 677{ 678 unsigned i; 679 unsigned char swizzle[4]; 680 unsigned result = 0; 681 const uint32_t swizzle_shift[4] = { 682 16, 19, 22, 25, 683 }; 684 const uint32_t swizzle_bit[4] = { 685 0, 1, 2, 3, 686 }; 687 688 if (swizzle_view) { 689 /* Combine two sets of swizzles. */ 690 for (i = 0; i < 4; i++) { 691 swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ? 692 swizzle_format[swizzle_view[i]] : swizzle_view[i]; 693 } 694 } else { 695 memcpy(swizzle, swizzle_format, 4); 696 } 697 698 /* Get swizzle. */ 699 for (i = 0; i < 4; i++) { 700 switch (swizzle[i]) { 701 case UTIL_FORMAT_SWIZZLE_Y: 702 result |= swizzle_bit[1] << swizzle_shift[i]; 703 break; 704 case UTIL_FORMAT_SWIZZLE_Z: 705 result |= swizzle_bit[2] << swizzle_shift[i]; 706 break; 707 case UTIL_FORMAT_SWIZZLE_W: 708 result |= swizzle_bit[3] << swizzle_shift[i]; 709 break; 710 case UTIL_FORMAT_SWIZZLE_0: 711 result |= V_038010_SQ_SEL_0 << swizzle_shift[i]; 712 break; 713 case UTIL_FORMAT_SWIZZLE_1: 714 result |= V_038010_SQ_SEL_1 << swizzle_shift[i]; 715 break; 716 default: /* UTIL_FORMAT_SWIZZLE_X */ 717 result |= swizzle_bit[0] << swizzle_shift[i]; 718 } 719 } 720 return result; 721} 722 723/* texture format translate */ 724uint32_t r600_translate_texformat(enum pipe_format format, 725 const unsigned char *swizzle_view, 726 uint32_t *word4_p, uint32_t *yuv_format_p) 727{ 728 uint32_t result = 0, word4 = 0, yuv_format = 0; 729 const struct util_format_description *desc; 730 boolean uniform = TRUE; 731 int i; 732 const uint32_t sign_bit[4] = { 733 S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED), 734 S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED), 735 S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED), 736 S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED) 737 }; 738 desc = util_format_description(format); 739 740 word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view); 741 742 /* Colorspace (return non-RGB formats directly). */ 743 switch (desc->colorspace) { 744 /* Depth stencil formats */ 745 case UTIL_FORMAT_COLORSPACE_ZS: 746 switch (format) { 747 case PIPE_FORMAT_Z16_UNORM: 748 result = FMT_16; 749 goto out_word4; 750 case PIPE_FORMAT_X24S8_USCALED: 751 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 752 case PIPE_FORMAT_Z24X8_UNORM: 753 case PIPE_FORMAT_Z24_UNORM_S8_USCALED: 754 result = FMT_8_24; 755 goto out_word4; 756 case PIPE_FORMAT_S8X24_USCALED: 757 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 758 case PIPE_FORMAT_X8Z24_UNORM: 759 case PIPE_FORMAT_S8_USCALED_Z24_UNORM: 760 result = FMT_24_8; 761 goto out_word4; 762 case PIPE_FORMAT_S8_USCALED: 763 result = V_0280A0_COLOR_8; 764 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 765 goto out_word4; 766 default: 767 goto out_unknown; 768 } 769 770 case UTIL_FORMAT_COLORSPACE_YUV: 771 yuv_format |= (1 << 30); 772 switch (format) { 773 case PIPE_FORMAT_UYVY: 774 case PIPE_FORMAT_YUYV: 775 default: 776 break; 777 } 778 goto out_unknown; /* TODO */ 779 780 case UTIL_FORMAT_COLORSPACE_SRGB: 781 word4 |= S_038010_FORCE_DEGAMMA(1); 782 if (format == PIPE_FORMAT_L8A8_SRGB || format == PIPE_FORMAT_L8_SRGB) 783 goto out_unknown; /* fails for some reason - TODO */ 784 break; 785 786 default: 787 break; 788 } 789 790 /* S3TC formats. TODO */ 791 if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { 792 goto out_unknown; 793 } 794 795 796 for (i = 0; i < desc->nr_channels; i++) { 797 if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) { 798 word4 |= sign_bit[i]; 799 } 800 } 801 802 /* R8G8Bx_SNORM - TODO CxV8U8 */ 803 804 /* RGTC - TODO */ 805 806 /* See whether the components are of the same size. */ 807 for (i = 1; i < desc->nr_channels; i++) { 808 uniform = uniform && desc->channel[0].size == desc->channel[i].size; 809 } 810 811 /* Non-uniform formats. */ 812 if (!uniform) { 813 switch(desc->nr_channels) { 814 case 3: 815 if (desc->channel[0].size == 5 && 816 desc->channel[1].size == 6 && 817 desc->channel[2].size == 5) { 818 result = FMT_5_6_5; 819 goto out_word4; 820 } 821 goto out_unknown; 822 case 4: 823 if (desc->channel[0].size == 5 && 824 desc->channel[1].size == 5 && 825 desc->channel[2].size == 5 && 826 desc->channel[3].size == 1) { 827 result = FMT_1_5_5_5; 828 goto out_word4; 829 } 830 if (desc->channel[0].size == 10 && 831 desc->channel[1].size == 10 && 832 desc->channel[2].size == 10 && 833 desc->channel[3].size == 2) { 834 result = FMT_10_10_10_2; 835 goto out_word4; 836 } 837 goto out_unknown; 838 } 839 goto out_unknown; 840 } 841 842 /* Find the first non-VOID channel. */ 843 for (i = 0; i < 4; i++) { 844 if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { 845 break; 846 } 847 } 848 849 if (i == 4) 850 goto out_unknown; 851 852 /* uniform formats */ 853 switch (desc->channel[i].type) { 854 case UTIL_FORMAT_TYPE_UNSIGNED: 855 case UTIL_FORMAT_TYPE_SIGNED: 856 if (!desc->channel[i].normalized && 857 desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { 858 goto out_unknown; 859 } 860 861 switch (desc->channel[i].size) { 862 case 4: 863 switch (desc->nr_channels) { 864 case 2: 865 result = FMT_4_4; 866 goto out_word4; 867 case 4: 868 result = FMT_4_4_4_4; 869 goto out_word4; 870 } 871 goto out_unknown; 872 case 8: 873 switch (desc->nr_channels) { 874 case 1: 875 result = FMT_8; 876 goto out_word4; 877 case 2: 878 result = FMT_8_8; 879 goto out_word4; 880 case 4: 881 result = FMT_8_8_8_8; 882 goto out_word4; 883 } 884 goto out_unknown; 885 case 16: 886 switch (desc->nr_channels) { 887 case 1: 888 result = FMT_16; 889 goto out_word4; 890 case 2: 891 result = FMT_16_16; 892 goto out_word4; 893 case 4: 894 result = FMT_16_16_16_16; 895 goto out_word4; 896 } 897 } 898 goto out_unknown; 899 900 case UTIL_FORMAT_TYPE_FLOAT: 901 switch (desc->channel[i].size) { 902 case 16: 903 switch (desc->nr_channels) { 904 case 1: 905 result = FMT_16_FLOAT; 906 goto out_word4; 907 case 2: 908 result = FMT_16_16_FLOAT; 909 goto out_word4; 910 case 4: 911 result = FMT_16_16_16_16_FLOAT; 912 goto out_word4; 913 } 914 goto out_unknown; 915 case 32: 916 switch (desc->nr_channels) { 917 case 1: 918 result = FMT_32_FLOAT; 919 goto out_word4; 920 case 2: 921 result = FMT_32_32_FLOAT; 922 goto out_word4; 923 case 4: 924 result = FMT_32_32_32_32_FLOAT; 925 goto out_word4; 926 } 927 } 928 929 } 930out_word4: 931 if (word4_p) 932 *word4_p = word4; 933 if (yuv_format_p) 934 *yuv_format_p = yuv_format; 935 return result; 936out_unknown: 937// R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); 938 return ~0; 939} 940