r600_texture.c revision ea7a548d07ddc69c226a425af0f88f818203d6ee
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 41/* Copy from a full GPU texture to a transfer's staging one. */ 42static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 43{ 44 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 45 struct pipe_resource *texture = transfer->resource; 46 47 ctx->resource_copy_region(ctx, rtransfer->staging_texture, 48 0, 0, 0, 0, texture, transfer->level, 49 &transfer->box); 50} 51 52 53/* Copy from a transfer's staging texture to a full GPU one. */ 54static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 55{ 56 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 57 struct pipe_resource *texture = transfer->resource; 58 struct pipe_box sbox; 59 60 sbox.x = sbox.y = sbox.z = 0; 61 sbox.width = transfer->box.width; 62 sbox.height = transfer->box.height; 63 /* XXX that might be wrong */ 64 sbox.depth = 1; 65 ctx->resource_copy_region(ctx, texture, transfer->level, 66 transfer->box.x, transfer->box.y, transfer->box.z, 67 rtransfer->staging_texture, 68 0, &sbox); 69 70 ctx->flush(ctx, 0, NULL); 71} 72 73unsigned r600_texture_get_offset(struct r600_resource_texture *rtex, 74 unsigned level, unsigned layer) 75{ 76 unsigned offset = rtex->offset[level]; 77 78 switch (rtex->resource.b.b.b.target) { 79 case PIPE_TEXTURE_3D: 80 case PIPE_TEXTURE_CUBE: 81 return offset + layer * rtex->layer_size[level]; 82 default: 83 assert(layer == 0); 84 return offset; 85 } 86} 87 88static unsigned r600_get_pixel_alignment(struct pipe_screen *screen, 89 enum pipe_format format, 90 unsigned array_mode) 91{ 92 struct r600_screen* rscreen = (struct r600_screen *)screen; 93 unsigned pixsize = util_format_get_blocksize(format); 94 int p_align; 95 96 switch(array_mode) { 97 case V_038000_ARRAY_1D_TILED_THIN1: 98 p_align = MAX2(8, 99 ((rscreen->tiling_info->group_bytes / 8 / pixsize))); 100 break; 101 case V_038000_ARRAY_2D_TILED_THIN1: 102 p_align = MAX2(rscreen->tiling_info->num_banks, 103 (((rscreen->tiling_info->group_bytes / 8 / pixsize)) * 104 rscreen->tiling_info->num_banks)) * 8; 105 break; 106 case V_038000_ARRAY_LINEAR_ALIGNED: 107 p_align = MAX2(64, rscreen->tiling_info->group_bytes / pixsize); 108 break; 109 case V_038000_ARRAY_LINEAR_GENERAL: 110 default: 111 p_align = rscreen->tiling_info->group_bytes / pixsize; 112 break; 113 } 114 return p_align; 115} 116 117static unsigned r600_get_height_alignment(struct pipe_screen *screen, 118 unsigned array_mode) 119{ 120 struct r600_screen* rscreen = (struct r600_screen *)screen; 121 int h_align; 122 123 switch (array_mode) { 124 case V_038000_ARRAY_2D_TILED_THIN1: 125 h_align = rscreen->tiling_info->num_channels * 8; 126 break; 127 case V_038000_ARRAY_1D_TILED_THIN1: 128 case V_038000_ARRAY_LINEAR_ALIGNED: 129 h_align = 8; 130 break; 131 default: 132 h_align = 1; 133 break; 134 } 135 return h_align; 136} 137 138static unsigned r600_get_base_alignment(struct pipe_screen *screen, 139 enum pipe_format format, 140 unsigned array_mode) 141{ 142 struct r600_screen* rscreen = (struct r600_screen *)screen; 143 unsigned pixsize = util_format_get_blocksize(format); 144 int p_align = r600_get_pixel_alignment(screen, format, array_mode); 145 int h_align = r600_get_height_alignment(screen, array_mode); 146 int b_align; 147 148 switch (array_mode) { 149 case V_038000_ARRAY_2D_TILED_THIN1: 150 b_align = MAX2(rscreen->tiling_info->num_banks * rscreen->tiling_info->num_channels * 8 * 8 * pixsize, 151 p_align * pixsize * h_align); 152 break; 153 case V_038000_ARRAY_1D_TILED_THIN1: 154 case V_038000_ARRAY_LINEAR_ALIGNED: 155 case V_038000_ARRAY_LINEAR_GENERAL: 156 default: 157 b_align = rscreen->tiling_info->group_bytes; 158 break; 159 } 160 return b_align; 161} 162 163static unsigned mip_minify(unsigned size, unsigned level) 164{ 165 unsigned val; 166 val = u_minify(size, level); 167 if (level > 0) 168 val = util_next_power_of_two(val); 169 return val; 170} 171 172static unsigned r600_texture_get_stride(struct pipe_screen *screen, 173 struct r600_resource_texture *rtex, 174 unsigned level) 175{ 176 struct pipe_resource *ptex = &rtex->resource.b.b.b; 177 unsigned width, stride, tile_width; 178 179 if (rtex->pitch_override) 180 return rtex->pitch_override; 181 182 width = mip_minify(ptex->width0, level); 183 if (util_format_is_plain(ptex->format)) { 184 tile_width = r600_get_pixel_alignment(screen, ptex->format, 185 rtex->array_mode[level]); 186 width = align(width, tile_width); 187 } 188 stride = util_format_get_stride(ptex->format, width); 189 190 return stride; 191} 192 193static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen, 194 struct r600_resource_texture *rtex, 195 unsigned level) 196{ 197 struct pipe_resource *ptex = &rtex->resource.b.b.b; 198 unsigned height, tile_height; 199 200 height = mip_minify(ptex->height0, level); 201 if (util_format_is_plain(ptex->format)) { 202 tile_height = r600_get_height_alignment(screen, 203 rtex->array_mode[level]); 204 height = align(height, tile_height); 205 } 206 return util_format_get_nblocksy(ptex->format, height); 207} 208 209/* Get a width in pixels from a stride in bytes. */ 210static unsigned pitch_to_width(enum pipe_format format, unsigned pitch_in_bytes) 211{ 212 return (pitch_in_bytes / util_format_get_blocksize(format)) * 213 util_format_get_blockwidth(format); 214} 215 216static void r600_texture_set_array_mode(struct pipe_screen *screen, 217 struct r600_resource_texture *rtex, 218 unsigned level, unsigned array_mode) 219{ 220 struct pipe_resource *ptex = &rtex->resource.b.b.b; 221 222 switch (array_mode) { 223 case V_0280A0_ARRAY_LINEAR_GENERAL: 224 case V_0280A0_ARRAY_LINEAR_ALIGNED: 225 case V_0280A0_ARRAY_1D_TILED_THIN1: 226 default: 227 rtex->array_mode[level] = array_mode; 228 break; 229 case V_0280A0_ARRAY_2D_TILED_THIN1: 230 { 231 unsigned w, h, tile_height, tile_width; 232 233 tile_height = r600_get_height_alignment(screen, array_mode); 234 tile_width = r600_get_pixel_alignment(screen, ptex->format, array_mode); 235 236 w = mip_minify(ptex->width0, level); 237 h = mip_minify(ptex->height0, level); 238 if (w < tile_width || h < tile_height) 239 rtex->array_mode[level] = V_0280A0_ARRAY_1D_TILED_THIN1; 240 else 241 rtex->array_mode[level] = array_mode; 242 } 243 break; 244 } 245} 246 247static void r600_setup_miptree(struct pipe_screen *screen, 248 struct r600_resource_texture *rtex, 249 unsigned array_mode) 250{ 251 struct pipe_resource *ptex = &rtex->resource.b.b.b; 252 struct radeon *radeon = (struct radeon *)screen->winsys; 253 enum chip_class chipc = r600_get_family_class(radeon); 254 unsigned pitch, size, layer_size, i, offset; 255 unsigned nblocksy; 256 257 for (i = 0, offset = 0; i <= ptex->last_level; i++) { 258 r600_texture_set_array_mode(screen, rtex, i, array_mode); 259 260 pitch = r600_texture_get_stride(screen, rtex, i); 261 nblocksy = r600_texture_get_nblocksy(screen, rtex, i); 262 263 layer_size = pitch * nblocksy; 264 265 if (ptex->target == PIPE_TEXTURE_CUBE) { 266 if (chipc >= R700) 267 size = layer_size * 8; 268 else 269 size = layer_size * 6; 270 } 271 else 272 size = layer_size * u_minify(ptex->depth0, i); 273 /* align base image and start of miptree */ 274 if ((i == 0) || (i == 1)) 275 offset = align(offset, r600_get_base_alignment(screen, ptex->format, array_mode)); 276 rtex->offset[i] = offset; 277 rtex->layer_size[i] = layer_size; 278 rtex->pitch_in_bytes[i] = pitch; 279 rtex->pitch_in_pixels[i] = pitch_to_width(ptex->format, pitch); 280 offset += size; 281 } 282 rtex->size = offset; 283} 284 285/* Figure out whether u_blitter will fallback to a transfer operation. 286 * If so, don't use a staging resource. 287 */ 288static boolean permit_hardware_blit(struct pipe_screen *screen, 289 const struct pipe_resource *res) 290{ 291 unsigned bind; 292 293 if (util_format_is_depth_or_stencil(res->format)) 294 bind = PIPE_BIND_DEPTH_STENCIL; 295 else 296 bind = PIPE_BIND_RENDER_TARGET; 297 298 if (!screen->is_format_supported(screen, 299 res->format, 300 res->target, 301 res->nr_samples, 302 bind, 0)) 303 return FALSE; 304 305 if (!screen->is_format_supported(screen, 306 res->format, 307 res->target, 308 res->nr_samples, 309 PIPE_BIND_SAMPLER_VIEW, 0)) 310 return FALSE; 311 312 return TRUE; 313} 314 315static boolean r600_texture_get_handle(struct pipe_screen* screen, 316 struct pipe_resource *ptex, 317 struct winsys_handle *whandle) 318{ 319 struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; 320 struct r600_resource *resource = &rtex->resource; 321 struct radeon *radeon = (struct radeon *)screen->winsys; 322 323 return r600_bo_get_winsys_handle(radeon, resource->bo, 324 rtex->pitch_in_bytes[0], whandle); 325} 326 327static void r600_texture_destroy(struct pipe_screen *screen, 328 struct pipe_resource *ptex) 329{ 330 struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; 331 struct r600_resource *resource = &rtex->resource; 332 struct radeon *radeon = (struct radeon *)screen->winsys; 333 334 if (rtex->flushed_depth_texture) 335 pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); 336 337 if (resource->bo) { 338 r600_bo_reference(radeon, &resource->bo, NULL); 339 } 340 FREE(rtex); 341} 342 343static unsigned int r600_texture_is_referenced(struct pipe_context *context, 344 struct pipe_resource *texture, 345 unsigned level, int layer) 346{ 347 /* FIXME */ 348 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 349} 350 351static const struct u_resource_vtbl r600_texture_vtbl = 352{ 353 r600_texture_get_handle, /* get_handle */ 354 r600_texture_destroy, /* resource_destroy */ 355 r600_texture_is_referenced, /* is_resource_referenced */ 356 r600_texture_get_transfer, /* get_transfer */ 357 r600_texture_transfer_destroy, /* transfer_destroy */ 358 r600_texture_transfer_map, /* transfer_map */ 359 u_default_transfer_flush_region,/* transfer_flush_region */ 360 r600_texture_transfer_unmap, /* transfer_unmap */ 361 u_default_transfer_inline_write /* transfer_inline_write */ 362}; 363 364static struct r600_resource_texture * 365r600_texture_create_object(struct pipe_screen *screen, 366 const struct pipe_resource *base, 367 unsigned array_mode, 368 unsigned pitch_in_bytes_override, 369 unsigned max_buffer_size, 370 struct r600_bo *bo) 371{ 372 struct r600_resource_texture *rtex; 373 struct r600_resource *resource; 374 struct radeon *radeon = (struct radeon *)screen->winsys; 375 376 rtex = CALLOC_STRUCT(r600_resource_texture); 377 if (rtex == NULL) 378 return NULL; 379 380 resource = &rtex->resource; 381 resource->b.b.b = *base; 382 resource->b.b.vtbl = &r600_texture_vtbl; 383 pipe_reference_init(&resource->b.b.b.reference, 1); 384 resource->b.b.b.screen = screen; 385 resource->bo = bo; 386 rtex->pitch_override = pitch_in_bytes_override; 387 /* only mark depth textures the HW can hit as depth textures */ 388 if (util_format_is_depth_or_stencil(base->format) && permit_hardware_blit(screen, base)) 389 rtex->depth = 1; 390 391 r600_setup_miptree(screen, rtex, array_mode); 392 393 resource->size = rtex->size; 394 395 if (!resource->bo) { 396 struct pipe_resource *ptex = &rtex->resource.b.b.b; 397 int base_align = r600_get_base_alignment(screen, ptex->format, array_mode); 398 399 resource->bo = r600_bo(radeon, rtex->size, base_align, base->bind, base->usage); 400 if (!resource->bo) { 401 FREE(rtex); 402 return NULL; 403 } 404 } 405 return rtex; 406} 407 408struct pipe_resource *r600_texture_create(struct pipe_screen *screen, 409 const struct pipe_resource *templ) 410{ 411 unsigned array_mode = 0; 412 static int force_tiling = -1; 413 414 /* Would like some magic "get_bool_option_once" routine. 415 */ 416 if (force_tiling == -1) 417 force_tiling = debug_get_bool_option("R600_FORCE_TILING", FALSE); 418 419 if (force_tiling && permit_hardware_blit(screen, templ)) { 420 if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) && 421 !(templ->bind & PIPE_BIND_SCANOUT)) { 422 array_mode = V_038000_ARRAY_2D_TILED_THIN1; 423 } 424 } 425 426 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, 427 0, 0, NULL); 428 429} 430 431static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, 432 struct pipe_resource *texture, 433 const struct pipe_surface *surf_tmpl) 434{ 435 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 436 struct r600_surface *surface = CALLOC_STRUCT(r600_surface); 437 unsigned level = surf_tmpl->u.tex.level; 438 439 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); 440 if (surface == NULL) 441 return NULL; 442 /* XXX no offset */ 443/* offset = r600_texture_get_offset(rtex, level, surf_tmpl->u.tex.first_layer);*/ 444 pipe_reference_init(&surface->base.reference, 1); 445 pipe_resource_reference(&surface->base.texture, texture); 446 surface->base.context = pipe; 447 surface->base.format = surf_tmpl->format; 448 surface->base.width = mip_minify(texture->width0, level); 449 surface->base.height = mip_minify(texture->height0, level); 450 surface->base.usage = surf_tmpl->usage; 451 surface->base.texture = texture; 452 surface->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer; 453 surface->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer; 454 surface->base.u.tex.level = level; 455 456 surface->aligned_height = r600_texture_get_nblocksy(pipe->screen, 457 rtex, level); 458 return &surface->base; 459} 460 461static void r600_surface_destroy(struct pipe_context *pipe, 462 struct pipe_surface *surface) 463{ 464 pipe_resource_reference(&surface->texture, NULL); 465 FREE(surface); 466} 467 468 469struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, 470 const struct pipe_resource *templ, 471 struct winsys_handle *whandle) 472{ 473 struct radeon *rw = (struct radeon*)screen->winsys; 474 struct r600_bo *bo = NULL; 475 unsigned array_mode = 0; 476 477 /* Support only 2D textures without mipmaps */ 478 if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) || 479 templ->depth0 != 1 || templ->last_level != 0) 480 return NULL; 481 482 bo = r600_bo_handle(rw, whandle->handle, &array_mode); 483 if (bo == NULL) { 484 return NULL; 485 } 486 487 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, 488 whandle->stride, 489 0, 490 bo); 491} 492 493int r600_texture_depth_flush(struct pipe_context *ctx, 494 struct pipe_resource *texture, boolean just_create) 495{ 496 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 497 struct pipe_resource resource; 498 499 if (rtex->flushed_depth_texture) 500 goto out; 501 502 resource.target = PIPE_TEXTURE_2D; 503 resource.format = texture->format; 504 resource.width0 = texture->width0; 505 resource.height0 = texture->height0; 506 resource.depth0 = 1; 507 resource.last_level = texture->last_level; 508 resource.nr_samples = 0; 509 resource.usage = PIPE_USAGE_DYNAMIC; 510 resource.bind = 0; 511 resource.flags = R600_RESOURCE_FLAG_TRANSFER; 512 513 resource.bind |= PIPE_BIND_DEPTH_STENCIL; 514 515 rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource); 516 if (rtex->flushed_depth_texture == NULL) { 517 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 518 return -ENOMEM; 519 } 520 521 ((struct r600_resource_texture *)rtex->flushed_depth_texture)->is_flushing_texture = TRUE; 522out: 523 if (just_create) 524 return 0; 525 526 /* XXX: only do this if the depth texture has actually changed: 527 */ 528 r600_blit_uncompress_depth(ctx, rtex); 529 return 0; 530} 531 532/* Needs adjustment for pixelformat: 533 */ 534static INLINE unsigned u_box_volume( const struct pipe_box *box ) 535{ 536 return box->width * box->depth * box->height; 537}; 538 539struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, 540 struct pipe_resource *texture, 541 unsigned level, 542 unsigned usage, 543 const struct pipe_box *box) 544{ 545 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 546 struct pipe_resource resource; 547 struct r600_transfer *trans; 548 int r; 549 boolean use_staging_texture = FALSE; 550 551 /* We cannot map a tiled texture directly because the data is 552 * in a different order, therefore we do detiling using a blit. 553 * 554 * Also, use a temporary in GTT memory for read transfers, as 555 * the CPU is much happier reading out of cached system memory 556 * than uncached VRAM. 557 */ 558 if (R600_TEX_IS_TILED(rtex, level)) 559 use_staging_texture = TRUE; 560 561 if ((usage & PIPE_TRANSFER_READ) && u_box_volume(box) > 1024) 562 use_staging_texture = TRUE; 563 564 /* XXX: Use a staging texture for uploads if the underlying BO 565 * is busy. No interface for checking that currently? so do 566 * it eagerly whenever the transfer doesn't require a readback 567 * and might block. 568 */ 569 if ((usage & PIPE_TRANSFER_WRITE) && 570 !(usage & (PIPE_TRANSFER_READ | 571 PIPE_TRANSFER_DONTBLOCK | 572 PIPE_TRANSFER_UNSYNCHRONIZED))) 573 use_staging_texture = TRUE; 574 575 if (!permit_hardware_blit(ctx->screen, texture) || 576 (texture->flags & R600_RESOURCE_FLAG_TRANSFER)) 577 use_staging_texture = FALSE; 578 579 trans = CALLOC_STRUCT(r600_transfer); 580 if (trans == NULL) 581 return NULL; 582 pipe_resource_reference(&trans->transfer.resource, texture); 583 trans->transfer.level = level; 584 trans->transfer.usage = usage; 585 trans->transfer.box = *box; 586 if (rtex->depth) { 587 /* XXX: only readback the rectangle which is being mapped? 588 */ 589 /* XXX: when discard is true, no need to read back from depth texture 590 */ 591 r = r600_texture_depth_flush(ctx, texture, FALSE); 592 if (r < 0) { 593 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 594 pipe_resource_reference(&trans->transfer.resource, NULL); 595 FREE(trans); 596 return NULL; 597 } 598 trans->transfer.stride = rtex->flushed_depth_texture->pitch_in_bytes[level]; 599 trans->offset = r600_texture_get_offset(rtex->flushed_depth_texture, level, box->z); 600 return &trans->transfer; 601 } else if (use_staging_texture) { 602 resource.target = PIPE_TEXTURE_2D; 603 resource.format = texture->format; 604 resource.width0 = box->width; 605 resource.height0 = box->height; 606 resource.depth0 = 1; 607 resource.array_size = 1; 608 resource.last_level = 0; 609 resource.nr_samples = 0; 610 resource.usage = PIPE_USAGE_STAGING; 611 resource.bind = 0; 612 resource.flags = R600_RESOURCE_FLAG_TRANSFER; 613 /* For texture reading, the temporary (detiled) texture is used as 614 * a render target when blitting from a tiled texture. */ 615 if (usage & PIPE_TRANSFER_READ) { 616 resource.bind |= PIPE_BIND_RENDER_TARGET; 617 } 618 /* For texture writing, the temporary texture is used as a sampler 619 * when blitting into a tiled texture. */ 620 if (usage & PIPE_TRANSFER_WRITE) { 621 resource.bind |= PIPE_BIND_SAMPLER_VIEW; 622 } 623 /* Create the temporary texture. */ 624 trans->staging_texture = ctx->screen->resource_create(ctx->screen, &resource); 625 if (trans->staging_texture == NULL) { 626 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 627 pipe_resource_reference(&trans->transfer.resource, NULL); 628 FREE(trans); 629 return NULL; 630 } 631 632 trans->transfer.stride = 633 ((struct r600_resource_texture *)trans->staging_texture)->pitch_in_bytes[0]; 634 if (usage & PIPE_TRANSFER_READ) { 635 r600_copy_to_staging_texture(ctx, trans); 636 /* Always referenced in the blit. */ 637 ctx->flush(ctx, 0, NULL); 638 } 639 return &trans->transfer; 640 } 641 trans->transfer.stride = rtex->pitch_in_bytes[level]; 642 trans->offset = r600_texture_get_offset(rtex, level, box->z); 643 return &trans->transfer; 644} 645 646void r600_texture_transfer_destroy(struct pipe_context *ctx, 647 struct pipe_transfer *transfer) 648{ 649 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 650 struct pipe_resource *texture = transfer->resource; 651 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 652 653 if (rtransfer->staging_texture) { 654 if (transfer->usage & PIPE_TRANSFER_WRITE) { 655 r600_copy_from_staging_texture(ctx, rtransfer); 656 } 657 pipe_resource_reference(&rtransfer->staging_texture, NULL); 658 } 659 660 if (rtex->depth && !rtex->is_flushing_texture) { 661 if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtex->flushed_depth_texture) 662 r600_blit_push_depth(ctx, rtex); 663 } 664 665 pipe_resource_reference(&transfer->resource, NULL); 666 FREE(transfer); 667} 668 669void* r600_texture_transfer_map(struct pipe_context *ctx, 670 struct pipe_transfer* transfer) 671{ 672 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 673 struct r600_bo *bo; 674 enum pipe_format format = transfer->resource->format; 675 struct radeon *radeon = (struct radeon *)ctx->screen->winsys; 676 unsigned offset = 0; 677 unsigned usage = 0; 678 char *map; 679 680 if (rtransfer->staging_texture) { 681 bo = ((struct r600_resource *)rtransfer->staging_texture)->bo; 682 } else { 683 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; 684 685 if (rtex->flushed_depth_texture) 686 bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo; 687 else 688 bo = ((struct r600_resource *)transfer->resource)->bo; 689 690 offset = rtransfer->offset + 691 transfer->box.y / util_format_get_blockheight(format) * transfer->stride + 692 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 693 } 694 695 if (transfer->usage & PIPE_TRANSFER_WRITE) { 696 usage |= PB_USAGE_CPU_WRITE; 697 698 if (transfer->usage & PIPE_TRANSFER_DISCARD) { 699 } 700 701 if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) { 702 } 703 } 704 705 if (transfer->usage & PIPE_TRANSFER_READ) { 706 usage |= PB_USAGE_CPU_READ; 707 } 708 709 if (transfer->usage & PIPE_TRANSFER_DONTBLOCK) { 710 usage |= PB_USAGE_DONTBLOCK; 711 } 712 713 if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) { 714 usage |= PB_USAGE_UNSYNCHRONIZED; 715 } 716 717 map = r600_bo_map(radeon, bo, usage, ctx); 718 if (!map) { 719 return NULL; 720 } 721 722 return map + offset; 723} 724 725void r600_texture_transfer_unmap(struct pipe_context *ctx, 726 struct pipe_transfer* transfer) 727{ 728 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 729 struct radeon *radeon = (struct radeon *)ctx->screen->winsys; 730 struct r600_bo *bo; 731 732 if (rtransfer->staging_texture) { 733 bo = ((struct r600_resource *)rtransfer->staging_texture)->bo; 734 } else { 735 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; 736 737 if (rtex->flushed_depth_texture) { 738 bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo; 739 } else { 740 bo = ((struct r600_resource *)transfer->resource)->bo; 741 } 742 } 743 r600_bo_unmap(radeon, bo); 744} 745 746void r600_init_surface_functions(struct r600_pipe_context *r600) 747{ 748 r600->context.create_surface = r600_create_surface; 749 r600->context.surface_destroy = r600_surface_destroy; 750} 751 752static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, 753 const unsigned char *swizzle_view) 754{ 755 unsigned i; 756 unsigned char swizzle[4]; 757 unsigned result = 0; 758 const uint32_t swizzle_shift[4] = { 759 16, 19, 22, 25, 760 }; 761 const uint32_t swizzle_bit[4] = { 762 0, 1, 2, 3, 763 }; 764 765 if (swizzle_view) { 766 /* Combine two sets of swizzles. */ 767 for (i = 0; i < 4; i++) { 768 swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ? 769 swizzle_format[swizzle_view[i]] : swizzle_view[i]; 770 } 771 } else { 772 memcpy(swizzle, swizzle_format, 4); 773 } 774 775 /* Get swizzle. */ 776 for (i = 0; i < 4; i++) { 777 switch (swizzle[i]) { 778 case UTIL_FORMAT_SWIZZLE_Y: 779 result |= swizzle_bit[1] << swizzle_shift[i]; 780 break; 781 case UTIL_FORMAT_SWIZZLE_Z: 782 result |= swizzle_bit[2] << swizzle_shift[i]; 783 break; 784 case UTIL_FORMAT_SWIZZLE_W: 785 result |= swizzle_bit[3] << swizzle_shift[i]; 786 break; 787 case UTIL_FORMAT_SWIZZLE_0: 788 result |= V_038010_SQ_SEL_0 << swizzle_shift[i]; 789 break; 790 case UTIL_FORMAT_SWIZZLE_1: 791 result |= V_038010_SQ_SEL_1 << swizzle_shift[i]; 792 break; 793 default: /* UTIL_FORMAT_SWIZZLE_X */ 794 result |= swizzle_bit[0] << swizzle_shift[i]; 795 } 796 } 797 return result; 798} 799 800/* texture format translate */ 801uint32_t r600_translate_texformat(enum pipe_format format, 802 const unsigned char *swizzle_view, 803 uint32_t *word4_p, uint32_t *yuv_format_p) 804{ 805 uint32_t result = 0, word4 = 0, yuv_format = 0; 806 const struct util_format_description *desc; 807 boolean uniform = TRUE; 808 int i; 809 const uint32_t sign_bit[4] = { 810 S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED), 811 S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED), 812 S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED), 813 S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED) 814 }; 815 desc = util_format_description(format); 816 817 word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view); 818 819 /* Colorspace (return non-RGB formats directly). */ 820 switch (desc->colorspace) { 821 /* Depth stencil formats */ 822 case UTIL_FORMAT_COLORSPACE_ZS: 823 switch (format) { 824 case PIPE_FORMAT_Z16_UNORM: 825 result = FMT_16; 826 goto out_word4; 827 case PIPE_FORMAT_X24S8_USCALED: 828 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 829 case PIPE_FORMAT_Z24X8_UNORM: 830 case PIPE_FORMAT_Z24_UNORM_S8_USCALED: 831 result = FMT_8_24; 832 goto out_word4; 833 case PIPE_FORMAT_S8X24_USCALED: 834 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 835 case PIPE_FORMAT_X8Z24_UNORM: 836 case PIPE_FORMAT_S8_USCALED_Z24_UNORM: 837 result = FMT_24_8; 838 goto out_word4; 839 case PIPE_FORMAT_S8_USCALED: 840 result = FMT_8; 841 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 842 goto out_word4; 843 default: 844 goto out_unknown; 845 } 846 847 case UTIL_FORMAT_COLORSPACE_YUV: 848 yuv_format |= (1 << 30); 849 switch (format) { 850 case PIPE_FORMAT_UYVY: 851 case PIPE_FORMAT_YUYV: 852 default: 853 break; 854 } 855 goto out_unknown; /* TODO */ 856 857 case UTIL_FORMAT_COLORSPACE_SRGB: 858 word4 |= S_038010_FORCE_DEGAMMA(1); 859 if (format == PIPE_FORMAT_L8A8_SRGB || format == PIPE_FORMAT_L8_SRGB) 860 goto out_unknown; /* fails for some reason - TODO */ 861 break; 862 863 default: 864 break; 865 } 866 867 /* S3TC formats. TODO */ 868 if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { 869 static int r600_enable_s3tc = -1; 870 871 if (r600_enable_s3tc == -1) 872 r600_enable_s3tc = 873 debug_get_bool_option("R600_ENABLE_S3TC", FALSE); 874 875 if (!r600_enable_s3tc) 876 goto out_unknown; 877 878 switch (format) { 879 case PIPE_FORMAT_DXT1_RGB: 880 case PIPE_FORMAT_DXT1_RGBA: 881 result = FMT_BC1; 882 goto out_word4; 883 case PIPE_FORMAT_DXT3_RGBA: 884 result = FMT_BC2; 885 goto out_word4; 886 case PIPE_FORMAT_DXT5_RGBA: 887 result = FMT_BC3; 888 goto out_word4; 889 default: 890 goto out_unknown; 891 } 892 } 893 894 895 for (i = 0; i < desc->nr_channels; i++) { 896 if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) { 897 word4 |= sign_bit[i]; 898 } 899 } 900 901 /* R8G8Bx_SNORM - TODO CxV8U8 */ 902 903 /* RGTC - TODO */ 904 905 /* See whether the components are of the same size. */ 906 for (i = 1; i < desc->nr_channels; i++) { 907 uniform = uniform && desc->channel[0].size == desc->channel[i].size; 908 } 909 910 /* Non-uniform formats. */ 911 if (!uniform) { 912 switch(desc->nr_channels) { 913 case 3: 914 if (desc->channel[0].size == 5 && 915 desc->channel[1].size == 6 && 916 desc->channel[2].size == 5) { 917 result = FMT_5_6_5; 918 goto out_word4; 919 } 920 goto out_unknown; 921 case 4: 922 if (desc->channel[0].size == 5 && 923 desc->channel[1].size == 5 && 924 desc->channel[2].size == 5 && 925 desc->channel[3].size == 1) { 926 result = FMT_1_5_5_5; 927 goto out_word4; 928 } 929 if (desc->channel[0].size == 10 && 930 desc->channel[1].size == 10 && 931 desc->channel[2].size == 10 && 932 desc->channel[3].size == 2) { 933 result = FMT_2_10_10_10; 934 goto out_word4; 935 } 936 goto out_unknown; 937 } 938 goto out_unknown; 939 } 940 941 /* Find the first non-VOID channel. */ 942 for (i = 0; i < 4; i++) { 943 if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { 944 break; 945 } 946 } 947 948 if (i == 4) 949 goto out_unknown; 950 951 /* uniform formats */ 952 switch (desc->channel[i].type) { 953 case UTIL_FORMAT_TYPE_UNSIGNED: 954 case UTIL_FORMAT_TYPE_SIGNED: 955 if (!desc->channel[i].normalized && 956 desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { 957 goto out_unknown; 958 } 959 960 switch (desc->channel[i].size) { 961 case 4: 962 switch (desc->nr_channels) { 963 case 2: 964 result = FMT_4_4; 965 goto out_word4; 966 case 4: 967 result = FMT_4_4_4_4; 968 goto out_word4; 969 } 970 goto out_unknown; 971 case 8: 972 switch (desc->nr_channels) { 973 case 1: 974 result = FMT_8; 975 goto out_word4; 976 case 2: 977 result = FMT_8_8; 978 goto out_word4; 979 case 4: 980 result = FMT_8_8_8_8; 981 goto out_word4; 982 } 983 goto out_unknown; 984 case 16: 985 switch (desc->nr_channels) { 986 case 1: 987 result = FMT_16; 988 goto out_word4; 989 case 2: 990 result = FMT_16_16; 991 goto out_word4; 992 case 4: 993 result = FMT_16_16_16_16; 994 goto out_word4; 995 } 996 goto out_unknown; 997 case 32: 998 switch (desc->nr_channels) { 999 case 1: 1000 result = FMT_32; 1001 goto out_word4; 1002 case 2: 1003 result = FMT_32_32; 1004 goto out_word4; 1005 case 4: 1006 result = FMT_32_32_32_32; 1007 goto out_word4; 1008 } 1009 } 1010 goto out_unknown; 1011 1012 case UTIL_FORMAT_TYPE_FLOAT: 1013 switch (desc->channel[i].size) { 1014 case 16: 1015 switch (desc->nr_channels) { 1016 case 1: 1017 result = FMT_16_FLOAT; 1018 goto out_word4; 1019 case 2: 1020 result = FMT_16_16_FLOAT; 1021 goto out_word4; 1022 case 4: 1023 result = FMT_16_16_16_16_FLOAT; 1024 goto out_word4; 1025 } 1026 goto out_unknown; 1027 case 32: 1028 switch (desc->nr_channels) { 1029 case 1: 1030 result = FMT_32_FLOAT; 1031 goto out_word4; 1032 case 2: 1033 result = FMT_32_32_FLOAT; 1034 goto out_word4; 1035 case 4: 1036 result = FMT_32_32_32_32_FLOAT; 1037 goto out_word4; 1038 } 1039 } 1040 1041 } 1042out_word4: 1043 if (word4_p) 1044 *word4_p = word4; 1045 if (yuv_format_p) 1046 *yuv_format_p = yuv_format; 1047 return result; 1048out_unknown: 1049// R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); 1050 return ~0; 1051} 1052