r600_texture.c revision b4f0ab0b22625ac1bb3cf16342039557c086ebae
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 "r600_formats.h" 28#include "r600d.h" 29 30#include <errno.h> 31#include "util/u_format_s3tc.h" 32#include "util/u_memory.h" 33 34/* Copy from a full GPU texture to a transfer's staging one. */ 35static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 36{ 37 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 38 struct pipe_resource *texture = transfer->resource; 39 40 ctx->resource_copy_region(ctx, &rtransfer->staging->b.b, 41 0, 0, 0, 0, texture, transfer->level, 42 &transfer->box); 43} 44 45 46/* Copy from a transfer's staging texture to a full GPU one. */ 47static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 48{ 49 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 50 struct pipe_resource *texture = transfer->resource; 51 struct pipe_box sbox; 52 53 sbox.x = sbox.y = sbox.z = 0; 54 sbox.width = transfer->box.width; 55 sbox.height = transfer->box.height; 56 /* XXX that might be wrong */ 57 sbox.depth = 1; 58 ctx->resource_copy_region(ctx, texture, transfer->level, 59 transfer->box.x, transfer->box.y, transfer->box.z, 60 &rtransfer->staging->b.b, 61 0, &sbox); 62} 63 64unsigned r600_texture_get_offset(struct r600_resource_texture *rtex, 65 unsigned level, unsigned layer) 66{ 67 unsigned offset = rtex->offset[level]; 68 69 switch (rtex->resource.b.b.target) { 70 case PIPE_TEXTURE_3D: 71 case PIPE_TEXTURE_CUBE: 72 default: 73 return offset + layer * rtex->layer_size[level]; 74 } 75} 76 77static unsigned r600_get_block_alignment(struct pipe_screen *screen, 78 enum pipe_format format, 79 unsigned array_mode) 80{ 81 struct r600_screen* rscreen = (struct r600_screen *)screen; 82 unsigned pixsize = util_format_get_blocksize(format); 83 int p_align; 84 85 switch(array_mode) { 86 case V_038000_ARRAY_1D_TILED_THIN1: 87 p_align = MAX2(8, 88 ((rscreen->tiling_info.group_bytes / 8 / pixsize))); 89 break; 90 case V_038000_ARRAY_2D_TILED_THIN1: 91 p_align = MAX2(rscreen->tiling_info.num_banks, 92 (((rscreen->tiling_info.group_bytes / 8 / pixsize)) * 93 rscreen->tiling_info.num_banks)) * 8; 94 break; 95 case V_038000_ARRAY_LINEAR_ALIGNED: 96 p_align = MAX2(64, rscreen->tiling_info.group_bytes / pixsize); 97 break; 98 case V_038000_ARRAY_LINEAR_GENERAL: 99 default: 100 p_align = rscreen->tiling_info.group_bytes / pixsize; 101 break; 102 } 103 return p_align; 104} 105 106static unsigned r600_get_height_alignment(struct pipe_screen *screen, 107 unsigned array_mode) 108{ 109 struct r600_screen* rscreen = (struct r600_screen *)screen; 110 int h_align; 111 112 switch (array_mode) { 113 case V_038000_ARRAY_2D_TILED_THIN1: 114 h_align = rscreen->tiling_info.num_channels * 8; 115 break; 116 case V_038000_ARRAY_1D_TILED_THIN1: 117 case V_038000_ARRAY_LINEAR_ALIGNED: 118 h_align = 8; 119 break; 120 case V_038000_ARRAY_LINEAR_GENERAL: 121 default: 122 h_align = 1; 123 break; 124 } 125 return h_align; 126} 127 128static unsigned r600_get_base_alignment(struct pipe_screen *screen, 129 enum pipe_format format, 130 unsigned array_mode) 131{ 132 struct r600_screen* rscreen = (struct r600_screen *)screen; 133 unsigned pixsize = util_format_get_blocksize(format); 134 int p_align = r600_get_block_alignment(screen, format, array_mode); 135 int h_align = r600_get_height_alignment(screen, array_mode); 136 int b_align; 137 138 switch (array_mode) { 139 case V_038000_ARRAY_2D_TILED_THIN1: 140 b_align = MAX2(rscreen->tiling_info.num_banks * rscreen->tiling_info.num_channels * 8 * 8 * pixsize, 141 p_align * pixsize * h_align); 142 break; 143 case V_038000_ARRAY_1D_TILED_THIN1: 144 case V_038000_ARRAY_LINEAR_ALIGNED: 145 case V_038000_ARRAY_LINEAR_GENERAL: 146 default: 147 b_align = rscreen->tiling_info.group_bytes; 148 break; 149 } 150 return b_align; 151} 152 153static unsigned mip_minify(unsigned size, unsigned level) 154{ 155 unsigned val; 156 val = u_minify(size, level); 157 if (level > 0) 158 val = util_next_power_of_two(val); 159 return val; 160} 161 162static unsigned r600_texture_get_nblocksx(struct pipe_screen *screen, 163 struct r600_resource_texture *rtex, 164 unsigned level) 165{ 166 struct pipe_resource *ptex = &rtex->resource.b.b; 167 unsigned nblocksx, block_align, width; 168 unsigned blocksize = util_format_get_blocksize(rtex->real_format); 169 170 if (rtex->pitch_override) 171 return rtex->pitch_override / blocksize; 172 173 width = mip_minify(ptex->width0, level); 174 nblocksx = util_format_get_nblocksx(rtex->real_format, width); 175 176 block_align = r600_get_block_alignment(screen, rtex->real_format, 177 rtex->array_mode[level]); 178 nblocksx = align(nblocksx, block_align); 179 return nblocksx; 180} 181 182static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen, 183 struct r600_resource_texture *rtex, 184 unsigned level) 185{ 186 struct pipe_resource *ptex = &rtex->resource.b.b; 187 unsigned height, tile_height; 188 189 height = mip_minify(ptex->height0, level); 190 height = util_format_get_nblocksy(rtex->real_format, height); 191 tile_height = r600_get_height_alignment(screen, 192 rtex->array_mode[level]); 193 194 /* XXX Hack around an alignment issue. Less tests fail with this. 195 * 196 * The thing is depth-stencil buffers should be tiled, i.e. 197 * the alignment should be >=8. If I make them tiled, stencil starts 198 * working because it no longer overlaps with the depth buffer 199 * in memory, but texturing like drawpix-stencil breaks. */ 200 if (util_format_is_depth_or_stencil(rtex->real_format) && tile_height < 8) 201 tile_height = 8; 202 203 height = align(height, tile_height); 204 return height; 205} 206 207static void r600_texture_set_array_mode(struct pipe_screen *screen, 208 struct r600_resource_texture *rtex, 209 unsigned level, unsigned array_mode) 210{ 211 struct pipe_resource *ptex = &rtex->resource.b.b; 212 213 switch (array_mode) { 214 case V_0280A0_ARRAY_LINEAR_GENERAL: 215 case V_0280A0_ARRAY_LINEAR_ALIGNED: 216 case V_0280A0_ARRAY_1D_TILED_THIN1: 217 default: 218 rtex->array_mode[level] = array_mode; 219 break; 220 case V_0280A0_ARRAY_2D_TILED_THIN1: 221 { 222 unsigned w, h, tile_height, tile_width; 223 224 tile_height = r600_get_height_alignment(screen, array_mode); 225 tile_width = r600_get_block_alignment(screen, rtex->real_format, array_mode); 226 227 w = mip_minify(ptex->width0, level); 228 h = mip_minify(ptex->height0, level); 229 if (w <= tile_width || h <= tile_height) 230 rtex->array_mode[level] = V_0280A0_ARRAY_1D_TILED_THIN1; 231 else 232 rtex->array_mode[level] = array_mode; 233 } 234 break; 235 } 236} 237 238static int r600_init_surface(struct radeon_surface *surface, 239 const struct pipe_resource *ptex, 240 unsigned array_mode, bool is_transfer) 241{ 242 surface->npix_x = ptex->width0; 243 surface->npix_y = ptex->height0; 244 surface->npix_z = ptex->depth0; 245 surface->blk_w = util_format_get_blockwidth(ptex->format); 246 surface->blk_h = util_format_get_blockheight(ptex->format); 247 surface->blk_d = 1; 248 surface->array_size = 1; 249 surface->last_level = ptex->last_level; 250 surface->bpe = util_format_get_blocksize(ptex->format); 251 /* align byte per element on dword */ 252 if (surface->bpe == 3) { 253 surface->bpe = 4; 254 } 255 surface->nsamples = 1; 256 surface->flags = 0; 257 switch (array_mode) { 258 case V_038000_ARRAY_1D_TILED_THIN1: 259 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 260 break; 261 case V_038000_ARRAY_2D_TILED_THIN1: 262 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 263 break; 264 case V_038000_ARRAY_LINEAR_ALIGNED: 265 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 266 break; 267 case V_038000_ARRAY_LINEAR_GENERAL: 268 default: 269 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); 270 break; 271 } 272 switch (ptex->target) { 273 case PIPE_TEXTURE_1D: 274 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE); 275 break; 276 case PIPE_TEXTURE_RECT: 277 case PIPE_TEXTURE_2D: 278 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 279 break; 280 case PIPE_TEXTURE_3D: 281 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE); 282 break; 283 case PIPE_TEXTURE_1D_ARRAY: 284 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE); 285 surface->array_size = ptex->array_size; 286 break; 287 case PIPE_TEXTURE_2D_ARRAY: 288 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE); 289 surface->array_size = ptex->array_size; 290 break; 291 case PIPE_TEXTURE_CUBE: 292 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE); 293 break; 294 case PIPE_BUFFER: 295 default: 296 return -EINVAL; 297 } 298 if (ptex->bind & PIPE_BIND_SCANOUT) { 299 surface->flags |= RADEON_SURF_SCANOUT; 300 } 301 if (util_format_is_depth_and_stencil(ptex->format) && !is_transfer) { 302 surface->flags |= RADEON_SURF_ZBUFFER; 303 surface->flags |= RADEON_SURF_SBUFFER; 304 } 305 306 return 0; 307} 308 309static int r600_setup_surface(struct pipe_screen *screen, 310 struct r600_resource_texture *rtex, 311 unsigned array_mode, 312 unsigned pitch_in_bytes_override) 313{ 314 struct pipe_resource *ptex = &rtex->resource.b.b; 315 struct r600_screen *rscreen = (struct r600_screen*)screen; 316 unsigned i; 317 int r; 318 319 r = rscreen->ws->surface_init(rscreen->ws, &rtex->surface); 320 if (r) { 321 return r; 322 } 323 rtex->size = rtex->surface.bo_size; 324 if (pitch_in_bytes_override && pitch_in_bytes_override != rtex->surface.level[0].pitch_bytes) { 325 /* old ddx on evergreen over estimate alignment for 1d, only 1 level 326 * for those 327 */ 328 rtex->surface.level[0].nblk_x = pitch_in_bytes_override / rtex->surface.bpe; 329 rtex->surface.level[0].pitch_bytes = pitch_in_bytes_override; 330 rtex->surface.level[0].slice_size = pitch_in_bytes_override * rtex->surface.level[0].nblk_y; 331 if (rtex->surface.flags & RADEON_SURF_SBUFFER) { 332 rtex->surface.stencil_offset = rtex->surface.level[0].slice_size; 333 } 334 } 335 for (i = 0; i <= ptex->last_level; i++) { 336 rtex->offset[i] = rtex->surface.level[i].offset; 337 rtex->layer_size[i] = rtex->surface.level[i].slice_size; 338 rtex->pitch_in_bytes[i] = rtex->surface.level[i].pitch_bytes; 339 switch (rtex->surface.level[i].mode) { 340 case RADEON_SURF_MODE_LINEAR_ALIGNED: 341 rtex->array_mode[i] = V_038000_ARRAY_LINEAR_ALIGNED; 342 break; 343 case RADEON_SURF_MODE_1D: 344 rtex->array_mode[i] = V_038000_ARRAY_1D_TILED_THIN1; 345 break; 346 case RADEON_SURF_MODE_2D: 347 rtex->array_mode[i] = V_038000_ARRAY_2D_TILED_THIN1; 348 break; 349 default: 350 case RADEON_SURF_MODE_LINEAR: 351 rtex->array_mode[i] = 0; 352 break; 353 } 354 } 355 return 0; 356} 357 358static void r600_setup_miptree(struct pipe_screen *screen, 359 struct r600_resource_texture *rtex, 360 unsigned array_mode) 361{ 362 struct pipe_resource *ptex = &rtex->resource.b.b; 363 enum chip_class chipc = ((struct r600_screen*)screen)->chip_class; 364 unsigned size, layer_size, i, offset; 365 unsigned nblocksx, nblocksy; 366 367 for (i = 0, offset = 0; i <= ptex->last_level; i++) { 368 unsigned blocksize = util_format_get_blocksize(rtex->real_format); 369 unsigned base_align = r600_get_base_alignment(screen, rtex->real_format, array_mode); 370 371 r600_texture_set_array_mode(screen, rtex, i, array_mode); 372 373 nblocksx = r600_texture_get_nblocksx(screen, rtex, i); 374 nblocksy = r600_texture_get_nblocksy(screen, rtex, i); 375 376 if (chipc >= EVERGREEN && array_mode == V_038000_ARRAY_LINEAR_GENERAL) 377 layer_size = align(nblocksx, 64) * nblocksy * blocksize; 378 else 379 layer_size = nblocksx * nblocksy * blocksize; 380 381 if (ptex->target == PIPE_TEXTURE_CUBE) { 382 if (chipc >= R700) 383 size = layer_size * 8; 384 else 385 size = layer_size * 6; 386 } 387 else if (ptex->target == PIPE_TEXTURE_3D) 388 size = layer_size * u_minify(ptex->depth0, i); 389 else 390 size = layer_size * ptex->array_size; 391 392 /* align base image and start of miptree */ 393 if ((i == 0) || (i == 1)) 394 offset = align(offset, base_align); 395 rtex->offset[i] = offset; 396 rtex->layer_size[i] = layer_size; 397 rtex->pitch_in_blocks[i] = nblocksx; /* CB talks in elements */ 398 rtex->pitch_in_bytes[i] = nblocksx * blocksize; 399 400 offset += size; 401 } 402 rtex->size = offset; 403} 404 405/* Figure out whether u_blitter will fallback to a transfer operation. 406 * If so, don't use a staging resource. 407 */ 408static boolean permit_hardware_blit(struct pipe_screen *screen, 409 const struct pipe_resource *res) 410{ 411 unsigned bind; 412 413 if (util_format_is_depth_or_stencil(res->format)) 414 bind = PIPE_BIND_DEPTH_STENCIL; 415 else 416 bind = PIPE_BIND_RENDER_TARGET; 417 418 /* hackaround for S3TC */ 419 if (util_format_is_compressed(res->format)) 420 return TRUE; 421 422 if (!screen->is_format_supported(screen, 423 res->format, 424 res->target, 425 res->nr_samples, 426 bind)) 427 return FALSE; 428 429 if (!screen->is_format_supported(screen, 430 res->format, 431 res->target, 432 res->nr_samples, 433 PIPE_BIND_SAMPLER_VIEW)) 434 return FALSE; 435 436 return TRUE; 437} 438 439static boolean r600_texture_get_handle(struct pipe_screen* screen, 440 struct pipe_resource *ptex, 441 struct winsys_handle *whandle) 442{ 443 struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; 444 struct r600_resource *resource = &rtex->resource; 445 struct radeon_surface *surface = &rtex->surface; 446 struct r600_screen *rscreen = (struct r600_screen*)screen; 447 448 rscreen->ws->buffer_set_tiling(resource->buf, 449 NULL, 450 surface->level[0].mode >= RADEON_SURF_MODE_1D ? 451 RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR, 452 surface->level[0].mode >= RADEON_SURF_MODE_2D ? 453 RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR, 454 surface->bankw, surface->bankh, 455 surface->tile_split, 456 surface->stencil_tile_split, 457 surface->mtilea, 458 rtex->pitch_in_bytes[0]); 459 460 return rscreen->ws->buffer_get_handle(resource->buf, 461 rtex->pitch_in_bytes[0], whandle); 462} 463 464static void r600_texture_destroy(struct pipe_screen *screen, 465 struct pipe_resource *ptex) 466{ 467 struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; 468 struct r600_resource *resource = &rtex->resource; 469 470 if (rtex->flushed_depth_texture) 471 pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); 472 473 if (rtex->stencil) 474 pipe_resource_reference((struct pipe_resource **)&rtex->stencil, NULL); 475 476 pb_reference(&resource->buf, NULL); 477 FREE(rtex); 478} 479 480static const struct u_resource_vtbl r600_texture_vtbl = 481{ 482 r600_texture_get_handle, /* get_handle */ 483 r600_texture_destroy, /* resource_destroy */ 484 r600_texture_get_transfer, /* get_transfer */ 485 r600_texture_transfer_destroy, /* transfer_destroy */ 486 r600_texture_transfer_map, /* transfer_map */ 487 NULL, /* transfer_flush_region */ 488 r600_texture_transfer_unmap, /* transfer_unmap */ 489 NULL /* transfer_inline_write */ 490}; 491 492static struct r600_resource_texture * 493r600_texture_create_object(struct pipe_screen *screen, 494 const struct pipe_resource *base, 495 unsigned array_mode, 496 unsigned pitch_in_bytes_override, 497 unsigned max_buffer_size, 498 struct pb_buffer *buf, 499 boolean alloc_bo, 500 struct radeon_surface *surface) 501{ 502 struct r600_resource_texture *rtex; 503 struct r600_resource *resource; 504 struct r600_screen *rscreen = (struct r600_screen*)screen; 505 int r; 506 507 rtex = CALLOC_STRUCT(r600_resource_texture); 508 if (rtex == NULL) 509 return NULL; 510 511 resource = &rtex->resource; 512 resource->b.b = *base; 513 resource->b.vtbl = &r600_texture_vtbl; 514 pipe_reference_init(&resource->b.b.reference, 1); 515 resource->b.b.screen = screen; 516 rtex->pitch_override = pitch_in_bytes_override; 517 rtex->real_format = base->format; 518 519 /* We must split depth and stencil into two separate buffers on Evergreen. */ 520 if (!(base->flags & R600_RESOURCE_FLAG_TRANSFER) && 521 ((struct r600_screen*)screen)->chip_class >= EVERGREEN && 522 util_format_is_depth_and_stencil(base->format) && 523 !rscreen->use_surface_alloc) { 524 struct pipe_resource stencil; 525 unsigned stencil_pitch_override = 0; 526 527 switch (base->format) { 528 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 529 rtex->real_format = PIPE_FORMAT_Z24X8_UNORM; 530 break; 531 case PIPE_FORMAT_S8_UINT_Z24_UNORM: 532 rtex->real_format = PIPE_FORMAT_X8Z24_UNORM; 533 break; 534 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 535 rtex->real_format = PIPE_FORMAT_Z32_FLOAT; 536 break; 537 default: 538 assert(0); 539 FREE(rtex); 540 return NULL; 541 } 542 543 /* Divide the pitch in bytes by 4 for stencil, because it has a smaller pixel size. */ 544 if (pitch_in_bytes_override) { 545 assert(base->format == PIPE_FORMAT_Z24_UNORM_S8_UINT || 546 base->format == PIPE_FORMAT_S8_UINT_Z24_UNORM); 547 stencil_pitch_override = pitch_in_bytes_override / 4; 548 } 549 550 /* Allocate the stencil buffer. */ 551 stencil = *base; 552 stencil.format = PIPE_FORMAT_S8_UINT; 553 rtex->stencil = r600_texture_create_object(screen, &stencil, array_mode, 554 stencil_pitch_override, 555 max_buffer_size, NULL, FALSE, surface); 556 if (!rtex->stencil) { 557 FREE(rtex); 558 return NULL; 559 } 560 /* Proceed in creating the depth buffer. */ 561 } 562 563 /* only mark depth textures the HW can hit as depth textures */ 564 if (util_format_is_depth_or_stencil(rtex->real_format) && permit_hardware_blit(screen, base)) 565 rtex->is_depth = true; 566 567 r600_setup_miptree(screen, rtex, array_mode); 568 if (rscreen->use_surface_alloc) { 569 rtex->surface = *surface; 570 r = r600_setup_surface(screen, rtex, array_mode, 571 pitch_in_bytes_override); 572 if (r) { 573 FREE(rtex); 574 return NULL; 575 } 576 } 577 578 /* If we initialized separate stencil for Evergreen. place it after depth. */ 579 if (rtex->stencil) { 580 unsigned stencil_align, stencil_offset; 581 582 stencil_align = r600_get_base_alignment(screen, rtex->stencil->real_format, array_mode); 583 stencil_offset = align(rtex->size, stencil_align); 584 585 for (unsigned i = 0; i <= rtex->stencil->resource.b.b.last_level; i++) 586 rtex->stencil->offset[i] += stencil_offset; 587 588 rtex->size = stencil_offset + rtex->stencil->size; 589 } 590 591 /* Now create the backing buffer. */ 592 if (!buf && alloc_bo) { 593 struct pipe_resource *ptex = &rtex->resource.b.b; 594 unsigned base_align = r600_get_base_alignment(screen, ptex->format, array_mode); 595 596 if (rscreen->use_surface_alloc) { 597 base_align = rtex->surface.bo_alignment; 598 } else if (util_format_is_depth_or_stencil(rtex->real_format)) { 599 /* ugly work around depth buffer need stencil room at end of bo */ 600 rtex->size += ptex->width0 * ptex->height0; 601 } 602 if (!r600_init_resource(rscreen, resource, rtex->size, base_align, base->bind, base->usage)) { 603 pipe_resource_reference((struct pipe_resource**)&rtex->stencil, NULL); 604 FREE(rtex); 605 return NULL; 606 } 607 } else if (buf) { 608 resource->buf = buf; 609 resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf); 610 resource->domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM; 611 } 612 613 if (rtex->stencil) { 614 pb_reference(&rtex->stencil->resource.buf, rtex->resource.buf); 615 rtex->stencil->resource.cs_buf = rtex->resource.cs_buf; 616 rtex->stencil->resource.domains = rtex->resource.domains; 617 } 618 return rtex; 619} 620 621struct pipe_resource *r600_texture_create(struct pipe_screen *screen, 622 const struct pipe_resource *templ) 623{ 624 struct r600_screen *rscreen = (struct r600_screen*)screen; 625 struct radeon_surface surface; 626 unsigned array_mode = 0; 627 int r; 628 629 if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER)) { 630 if (rscreen->use_surface_alloc && 631 !(templ->bind & PIPE_BIND_SCANOUT) && 632 templ->usage != PIPE_USAGE_STAGING && 633 templ->usage != PIPE_USAGE_STREAM && 634 permit_hardware_blit(screen, templ)) { 635 array_mode = V_038000_ARRAY_2D_TILED_THIN1; 636 } else if (util_format_is_compressed(templ->format)) { 637 array_mode = V_038000_ARRAY_1D_TILED_THIN1; 638 } 639 } 640 641 r = r600_init_surface(&surface, templ, array_mode, 642 templ->flags & R600_RESOURCE_FLAG_TRANSFER); 643 if (r) { 644 return NULL; 645 } 646 r = rscreen->ws->surface_best(rscreen->ws, &surface); 647 if (r) { 648 return NULL; 649 } 650 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, 651 0, 0, NULL, TRUE, &surface); 652} 653 654static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, 655 struct pipe_resource *texture, 656 const struct pipe_surface *surf_tmpl) 657{ 658 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 659 struct r600_surface *surface = CALLOC_STRUCT(r600_surface); 660 unsigned level = surf_tmpl->u.tex.level; 661 662 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); 663 if (surface == NULL) 664 return NULL; 665 pipe_reference_init(&surface->base.reference, 1); 666 pipe_resource_reference(&surface->base.texture, texture); 667 surface->base.context = pipe; 668 surface->base.format = surf_tmpl->format; 669 surface->base.width = mip_minify(texture->width0, level); 670 surface->base.height = mip_minify(texture->height0, level); 671 surface->base.usage = surf_tmpl->usage; 672 surface->base.texture = texture; 673 surface->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer; 674 surface->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer; 675 surface->base.u.tex.level = level; 676 677 surface->aligned_height = r600_texture_get_nblocksy(pipe->screen, 678 rtex, level); 679 return &surface->base; 680} 681 682static void r600_surface_destroy(struct pipe_context *pipe, 683 struct pipe_surface *surface) 684{ 685 pipe_resource_reference(&surface->texture, NULL); 686 FREE(surface); 687} 688 689struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, 690 const struct pipe_resource *templ, 691 struct winsys_handle *whandle) 692{ 693 struct r600_screen *rscreen = (struct r600_screen*)screen; 694 struct pb_buffer *buf = NULL; 695 unsigned stride = 0; 696 unsigned array_mode = 0; 697 enum radeon_bo_layout micro, macro; 698 struct radeon_surface surface; 699 int r; 700 701 /* Support only 2D textures without mipmaps */ 702 if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) || 703 templ->depth0 != 1 || templ->last_level != 0) 704 return NULL; 705 706 buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, &stride); 707 if (!buf) 708 return NULL; 709 710 rscreen->ws->buffer_get_tiling(buf, µ, ¯o, 711 &surface.bankw, &surface.bankh, 712 &surface.tile_split, 713 &surface.stencil_tile_split, 714 &surface.mtilea); 715 716 if (macro == RADEON_LAYOUT_TILED) 717 array_mode = V_0280A0_ARRAY_2D_TILED_THIN1; 718 else if (micro == RADEON_LAYOUT_TILED) 719 array_mode = V_0280A0_ARRAY_1D_TILED_THIN1; 720 else 721 array_mode = 0; 722 723 r = r600_init_surface(&surface, templ, array_mode, 0); 724 if (r) { 725 return NULL; 726 } 727 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, 728 stride, 0, buf, FALSE, &surface); 729} 730 731int r600_texture_depth_flush(struct pipe_context *ctx, 732 struct pipe_resource *texture, boolean just_create) 733{ 734 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 735 struct pipe_resource resource; 736 737 if (rtex->flushed_depth_texture) 738 goto out; 739 740 resource.target = texture->target; 741 resource.format = texture->format; 742 resource.width0 = texture->width0; 743 resource.height0 = texture->height0; 744 resource.depth0 = texture->depth0; 745 resource.array_size = texture->array_size; 746 resource.last_level = texture->last_level; 747 resource.nr_samples = texture->nr_samples; 748 resource.usage = PIPE_USAGE_DYNAMIC; 749 resource.bind = texture->bind | PIPE_BIND_DEPTH_STENCIL; 750 resource.flags = R600_RESOURCE_FLAG_TRANSFER | texture->flags; 751 752 rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource); 753 if (rtex->flushed_depth_texture == NULL) { 754 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 755 return -ENOMEM; 756 } 757 758 ((struct r600_resource_texture *)rtex->flushed_depth_texture)->is_flushing_texture = TRUE; 759out: 760 if (just_create) 761 return 0; 762 763 /* XXX: only do this if the depth texture has actually changed: 764 */ 765 r600_blit_uncompress_depth(ctx, rtex); 766 return 0; 767} 768 769/* Needs adjustment for pixelformat: 770 */ 771static INLINE unsigned u_box_volume( const struct pipe_box *box ) 772{ 773 return box->width * box->depth * box->height; 774}; 775 776struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, 777 struct pipe_resource *texture, 778 unsigned level, 779 unsigned usage, 780 const struct pipe_box *box) 781{ 782 struct r600_context *rctx = (struct r600_context*)ctx; 783 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 784 struct pipe_resource resource; 785 struct r600_transfer *trans; 786 int r; 787 boolean use_staging_texture = FALSE; 788 789 /* We cannot map a tiled texture directly because the data is 790 * in a different order, therefore we do detiling using a blit. 791 * 792 * Also, use a temporary in GTT memory for read transfers, as 793 * the CPU is much happier reading out of cached system memory 794 * than uncached VRAM. 795 */ 796 if (R600_TEX_IS_TILED(rtex, level)) { 797 use_staging_texture = TRUE; 798 } 799 800 if ((usage & PIPE_TRANSFER_READ) && u_box_volume(box) > 1024) 801 use_staging_texture = TRUE; 802 803 /* Use a staging texture for uploads if the underlying BO is busy. */ 804 if (!(usage & PIPE_TRANSFER_READ) && 805 (rctx->ws->cs_is_buffer_referenced(rctx->cs, rtex->resource.cs_buf, RADEON_USAGE_READWRITE) || 806 rctx->ws->buffer_is_busy(rtex->resource.buf, RADEON_USAGE_READWRITE))) { 807 use_staging_texture = TRUE; 808 } 809 810 if (!permit_hardware_blit(ctx->screen, texture) || 811 (texture->flags & R600_RESOURCE_FLAG_TRANSFER)) { 812 use_staging_texture = FALSE; 813 } 814 815 if (use_staging_texture && (usage & PIPE_TRANSFER_MAP_DIRECTLY)) { 816 return NULL; 817 } 818 819 trans = CALLOC_STRUCT(r600_transfer); 820 if (trans == NULL) 821 return NULL; 822 pipe_resource_reference(&trans->transfer.resource, texture); 823 trans->transfer.level = level; 824 trans->transfer.usage = usage; 825 trans->transfer.box = *box; 826 if (rtex->is_depth) { 827 /* XXX: only readback the rectangle which is being mapped? 828 */ 829 /* XXX: when discard is true, no need to read back from depth texture 830 */ 831 r = r600_texture_depth_flush(ctx, texture, FALSE); 832 if (r < 0) { 833 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 834 pipe_resource_reference(&trans->transfer.resource, NULL); 835 FREE(trans); 836 return NULL; 837 } 838 trans->transfer.stride = rtex->flushed_depth_texture->pitch_in_bytes[level]; 839 trans->offset = r600_texture_get_offset(rtex->flushed_depth_texture, level, box->z); 840 return &trans->transfer; 841 } else if (use_staging_texture) { 842 resource.target = PIPE_TEXTURE_2D; 843 resource.format = texture->format; 844 resource.width0 = box->width; 845 resource.height0 = box->height; 846 resource.depth0 = 1; 847 resource.array_size = 1; 848 resource.last_level = 0; 849 resource.nr_samples = 0; 850 resource.usage = PIPE_USAGE_STAGING; 851 resource.bind = 0; 852 resource.flags = R600_RESOURCE_FLAG_TRANSFER; 853 /* For texture reading, the temporary (detiled) texture is used as 854 * a render target when blitting from a tiled texture. */ 855 if (usage & PIPE_TRANSFER_READ) { 856 resource.bind |= PIPE_BIND_RENDER_TARGET; 857 } 858 /* For texture writing, the temporary texture is used as a sampler 859 * when blitting into a tiled texture. */ 860 if (usage & PIPE_TRANSFER_WRITE) { 861 resource.bind |= PIPE_BIND_SAMPLER_VIEW; 862 } 863 /* Create the temporary texture. */ 864 trans->staging = (struct r600_resource*)ctx->screen->resource_create(ctx->screen, &resource); 865 if (trans->staging == NULL) { 866 R600_ERR("failed to create temporary texture to hold untiled copy\n"); 867 pipe_resource_reference(&trans->transfer.resource, NULL); 868 FREE(trans); 869 return NULL; 870 } 871 872 trans->transfer.stride = 873 ((struct r600_resource_texture *)trans->staging)->pitch_in_bytes[0]; 874 if (usage & PIPE_TRANSFER_READ) { 875 r600_copy_to_staging_texture(ctx, trans); 876 /* Always referenced in the blit. */ 877 r600_flush(ctx, NULL, 0); 878 } 879 return &trans->transfer; 880 } 881 trans->transfer.stride = rtex->pitch_in_bytes[level]; 882 trans->transfer.layer_stride = rtex->layer_size[level]; 883 trans->offset = r600_texture_get_offset(rtex, level, box->z); 884 return &trans->transfer; 885} 886 887void r600_texture_transfer_destroy(struct pipe_context *ctx, 888 struct pipe_transfer *transfer) 889{ 890 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 891 struct pipe_resource *texture = transfer->resource; 892 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; 893 894 if (rtransfer->staging) { 895 if (transfer->usage & PIPE_TRANSFER_WRITE) { 896 r600_copy_from_staging_texture(ctx, rtransfer); 897 } 898 pipe_resource_reference((struct pipe_resource**)&rtransfer->staging, NULL); 899 } 900 901 if (rtex->is_depth && !rtex->is_flushing_texture) { 902 if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtex->flushed_depth_texture) { 903 r600_blit_push_depth(ctx, rtex); 904 } 905 } 906 907 pipe_resource_reference(&transfer->resource, NULL); 908 FREE(transfer); 909} 910 911void* r600_texture_transfer_map(struct pipe_context *ctx, 912 struct pipe_transfer* transfer) 913{ 914 struct r600_context *rctx = (struct r600_context *)ctx; 915 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 916 struct radeon_winsys_cs_handle *buf; 917 enum pipe_format format = transfer->resource->format; 918 unsigned offset = 0; 919 char *map; 920 921 if ((transfer->resource->bind & PIPE_BIND_GLOBAL) && transfer->resource->target == PIPE_BUFFER) { 922 return r600_compute_global_transfer_map(ctx, transfer); 923 } 924 925 if (rtransfer->staging) { 926 buf = ((struct r600_resource *)rtransfer->staging)->cs_buf; 927 } else { 928 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; 929 930 if (rtex->flushed_depth_texture) 931 buf = ((struct r600_resource *)rtex->flushed_depth_texture)->cs_buf; 932 else 933 buf = ((struct r600_resource *)transfer->resource)->cs_buf; 934 935 offset = rtransfer->offset + 936 transfer->box.y / util_format_get_blockheight(format) * transfer->stride + 937 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 938 } 939 940 if (!(map = rctx->ws->buffer_map(buf, rctx->cs, transfer->usage))) { 941 return NULL; 942 } 943 944 return map + offset; 945} 946 947void r600_texture_transfer_unmap(struct pipe_context *ctx, 948 struct pipe_transfer* transfer) 949{ 950 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 951 struct r600_context *rctx = (struct r600_context*)ctx; 952 struct radeon_winsys_cs_handle *buf; 953 954 if ((transfer->resource->bind & PIPE_BIND_GLOBAL) && transfer->resource->target == PIPE_BUFFER) { 955 return r600_compute_global_transfer_unmap(ctx, transfer); 956 } 957 958 if (rtransfer->staging) { 959 buf = ((struct r600_resource *)rtransfer->staging)->cs_buf; 960 } else { 961 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; 962 963 if (rtex->flushed_depth_texture) { 964 buf = ((struct r600_resource *)rtex->flushed_depth_texture)->cs_buf; 965 } else { 966 buf = ((struct r600_resource *)transfer->resource)->cs_buf; 967 } 968 } 969 rctx->ws->buffer_unmap(buf); 970} 971 972void r600_init_surface_functions(struct r600_context *r600) 973{ 974 r600->context.create_surface = r600_create_surface; 975 r600->context.surface_destroy = r600_surface_destroy; 976} 977 978static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, 979 const unsigned char *swizzle_view) 980{ 981 unsigned i; 982 unsigned char swizzle[4]; 983 unsigned result = 0; 984 const uint32_t swizzle_shift[4] = { 985 16, 19, 22, 25, 986 }; 987 const uint32_t swizzle_bit[4] = { 988 0, 1, 2, 3, 989 }; 990 991 if (swizzle_view) { 992 util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle); 993 } else { 994 memcpy(swizzle, swizzle_format, 4); 995 } 996 997 /* Get swizzle. */ 998 for (i = 0; i < 4; i++) { 999 switch (swizzle[i]) { 1000 case UTIL_FORMAT_SWIZZLE_Y: 1001 result |= swizzle_bit[1] << swizzle_shift[i]; 1002 break; 1003 case UTIL_FORMAT_SWIZZLE_Z: 1004 result |= swizzle_bit[2] << swizzle_shift[i]; 1005 break; 1006 case UTIL_FORMAT_SWIZZLE_W: 1007 result |= swizzle_bit[3] << swizzle_shift[i]; 1008 break; 1009 case UTIL_FORMAT_SWIZZLE_0: 1010 result |= V_038010_SQ_SEL_0 << swizzle_shift[i]; 1011 break; 1012 case UTIL_FORMAT_SWIZZLE_1: 1013 result |= V_038010_SQ_SEL_1 << swizzle_shift[i]; 1014 break; 1015 default: /* UTIL_FORMAT_SWIZZLE_X */ 1016 result |= swizzle_bit[0] << swizzle_shift[i]; 1017 } 1018 } 1019 return result; 1020} 1021 1022/* texture format translate */ 1023uint32_t r600_translate_texformat(struct pipe_screen *screen, 1024 enum pipe_format format, 1025 const unsigned char *swizzle_view, 1026 uint32_t *word4_p, uint32_t *yuv_format_p) 1027{ 1028 uint32_t result = 0, word4 = 0, yuv_format = 0; 1029 const struct util_format_description *desc; 1030 boolean uniform = TRUE; 1031 static int r600_enable_s3tc = -1; 1032 bool is_srgb_valid = FALSE; 1033 1034 int i; 1035 const uint32_t sign_bit[4] = { 1036 S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED), 1037 S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED), 1038 S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED), 1039 S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED) 1040 }; 1041 desc = util_format_description(format); 1042 1043 word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view); 1044 1045 /* Colorspace (return non-RGB formats directly). */ 1046 switch (desc->colorspace) { 1047 /* Depth stencil formats */ 1048 case UTIL_FORMAT_COLORSPACE_ZS: 1049 switch (format) { 1050 case PIPE_FORMAT_Z16_UNORM: 1051 result = FMT_16; 1052 goto out_word4; 1053 case PIPE_FORMAT_X24S8_UINT: 1054 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 1055 case PIPE_FORMAT_Z24X8_UNORM: 1056 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 1057 result = FMT_8_24; 1058 goto out_word4; 1059 case PIPE_FORMAT_S8X24_UINT: 1060 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 1061 case PIPE_FORMAT_X8Z24_UNORM: 1062 case PIPE_FORMAT_S8_UINT_Z24_UNORM: 1063 result = FMT_24_8; 1064 goto out_word4; 1065 case PIPE_FORMAT_S8_UINT: 1066 result = FMT_8; 1067 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 1068 goto out_word4; 1069 case PIPE_FORMAT_Z32_FLOAT: 1070 result = FMT_32_FLOAT; 1071 goto out_word4; 1072 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 1073 result = FMT_X24_8_32_FLOAT; 1074 goto out_word4; 1075 default: 1076 goto out_unknown; 1077 } 1078 1079 case UTIL_FORMAT_COLORSPACE_YUV: 1080 yuv_format |= (1 << 30); 1081 switch (format) { 1082 case PIPE_FORMAT_UYVY: 1083 case PIPE_FORMAT_YUYV: 1084 default: 1085 break; 1086 } 1087 goto out_unknown; /* XXX */ 1088 1089 case UTIL_FORMAT_COLORSPACE_SRGB: 1090 word4 |= S_038010_FORCE_DEGAMMA(1); 1091 break; 1092 1093 default: 1094 break; 1095 } 1096 1097 if (r600_enable_s3tc == -1) { 1098 struct r600_screen *rscreen = (struct r600_screen *)screen; 1099 if (rscreen->info.drm_minor >= 9) 1100 r600_enable_s3tc = 1; 1101 else 1102 r600_enable_s3tc = debug_get_bool_option("R600_ENABLE_S3TC", FALSE); 1103 } 1104 1105 if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) { 1106 if (!r600_enable_s3tc) 1107 goto out_unknown; 1108 1109 switch (format) { 1110 case PIPE_FORMAT_RGTC1_SNORM: 1111 case PIPE_FORMAT_LATC1_SNORM: 1112 word4 |= sign_bit[0]; 1113 case PIPE_FORMAT_RGTC1_UNORM: 1114 case PIPE_FORMAT_LATC1_UNORM: 1115 result = FMT_BC4; 1116 goto out_word4; 1117 case PIPE_FORMAT_RGTC2_SNORM: 1118 case PIPE_FORMAT_LATC2_SNORM: 1119 word4 |= sign_bit[0] | sign_bit[1]; 1120 case PIPE_FORMAT_RGTC2_UNORM: 1121 case PIPE_FORMAT_LATC2_UNORM: 1122 result = FMT_BC5; 1123 goto out_word4; 1124 default: 1125 goto out_unknown; 1126 } 1127 } 1128 1129 if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { 1130 1131 if (!r600_enable_s3tc) 1132 goto out_unknown; 1133 1134 if (!util_format_s3tc_enabled) { 1135 goto out_unknown; 1136 } 1137 1138 switch (format) { 1139 case PIPE_FORMAT_DXT1_RGB: 1140 case PIPE_FORMAT_DXT1_RGBA: 1141 case PIPE_FORMAT_DXT1_SRGB: 1142 case PIPE_FORMAT_DXT1_SRGBA: 1143 result = FMT_BC1; 1144 is_srgb_valid = TRUE; 1145 goto out_word4; 1146 case PIPE_FORMAT_DXT3_RGBA: 1147 case PIPE_FORMAT_DXT3_SRGBA: 1148 result = FMT_BC2; 1149 is_srgb_valid = TRUE; 1150 goto out_word4; 1151 case PIPE_FORMAT_DXT5_RGBA: 1152 case PIPE_FORMAT_DXT5_SRGBA: 1153 result = FMT_BC3; 1154 is_srgb_valid = TRUE; 1155 goto out_word4; 1156 default: 1157 goto out_unknown; 1158 } 1159 } 1160 1161 if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) { 1162 switch (format) { 1163 case PIPE_FORMAT_R8G8_B8G8_UNORM: 1164 case PIPE_FORMAT_G8R8_B8R8_UNORM: 1165 result = FMT_GB_GR; 1166 goto out_word4; 1167 case PIPE_FORMAT_G8R8_G8B8_UNORM: 1168 case PIPE_FORMAT_R8G8_R8B8_UNORM: 1169 result = FMT_BG_RG; 1170 goto out_word4; 1171 default: 1172 goto out_unknown; 1173 } 1174 } 1175 1176 if (format == PIPE_FORMAT_R9G9B9E5_FLOAT) { 1177 result = FMT_5_9_9_9_SHAREDEXP; 1178 goto out_word4; 1179 } else if (format == PIPE_FORMAT_R11G11B10_FLOAT) { 1180 result = FMT_10_11_11_FLOAT; 1181 goto out_word4; 1182 } 1183 1184 1185 for (i = 0; i < desc->nr_channels; i++) { 1186 if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) { 1187 word4 |= sign_bit[i]; 1188 } 1189 } 1190 1191 /* R8G8Bx_SNORM - XXX CxV8U8 */ 1192 1193 /* See whether the components are of the same size. */ 1194 for (i = 1; i < desc->nr_channels; i++) { 1195 uniform = uniform && desc->channel[0].size == desc->channel[i].size; 1196 } 1197 1198 /* Non-uniform formats. */ 1199 if (!uniform) { 1200 if (desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB && 1201 desc->channel[0].pure_integer) 1202 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 1203 switch(desc->nr_channels) { 1204 case 3: 1205 if (desc->channel[0].size == 5 && 1206 desc->channel[1].size == 6 && 1207 desc->channel[2].size == 5) { 1208 result = FMT_5_6_5; 1209 goto out_word4; 1210 } 1211 goto out_unknown; 1212 case 4: 1213 if (desc->channel[0].size == 5 && 1214 desc->channel[1].size == 5 && 1215 desc->channel[2].size == 5 && 1216 desc->channel[3].size == 1) { 1217 result = FMT_1_5_5_5; 1218 goto out_word4; 1219 } 1220 if (desc->channel[0].size == 10 && 1221 desc->channel[1].size == 10 && 1222 desc->channel[2].size == 10 && 1223 desc->channel[3].size == 2) { 1224 result = FMT_2_10_10_10; 1225 goto out_word4; 1226 } 1227 goto out_unknown; 1228 } 1229 goto out_unknown; 1230 } 1231 1232 /* Find the first non-VOID channel. */ 1233 for (i = 0; i < 4; i++) { 1234 if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { 1235 break; 1236 } 1237 } 1238 1239 if (i == 4) 1240 goto out_unknown; 1241 1242 /* uniform formats */ 1243 switch (desc->channel[i].type) { 1244 case UTIL_FORMAT_TYPE_UNSIGNED: 1245 case UTIL_FORMAT_TYPE_SIGNED: 1246#if 0 1247 if (!desc->channel[i].normalized && 1248 desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { 1249 goto out_unknown; 1250 } 1251#endif 1252 if (desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB && 1253 desc->channel[i].pure_integer) 1254 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); 1255 1256 switch (desc->channel[i].size) { 1257 case 4: 1258 switch (desc->nr_channels) { 1259 case 2: 1260 result = FMT_4_4; 1261 goto out_word4; 1262 case 4: 1263 result = FMT_4_4_4_4; 1264 goto out_word4; 1265 } 1266 goto out_unknown; 1267 case 8: 1268 switch (desc->nr_channels) { 1269 case 1: 1270 result = FMT_8; 1271 goto out_word4; 1272 case 2: 1273 result = FMT_8_8; 1274 goto out_word4; 1275 case 4: 1276 result = FMT_8_8_8_8; 1277 is_srgb_valid = TRUE; 1278 goto out_word4; 1279 } 1280 goto out_unknown; 1281 case 16: 1282 switch (desc->nr_channels) { 1283 case 1: 1284 result = FMT_16; 1285 goto out_word4; 1286 case 2: 1287 result = FMT_16_16; 1288 goto out_word4; 1289 case 4: 1290 result = FMT_16_16_16_16; 1291 goto out_word4; 1292 } 1293 goto out_unknown; 1294 case 32: 1295 switch (desc->nr_channels) { 1296 case 1: 1297 result = FMT_32; 1298 goto out_word4; 1299 case 2: 1300 result = FMT_32_32; 1301 goto out_word4; 1302 case 4: 1303 result = FMT_32_32_32_32; 1304 goto out_word4; 1305 } 1306 } 1307 goto out_unknown; 1308 1309 case UTIL_FORMAT_TYPE_FLOAT: 1310 switch (desc->channel[i].size) { 1311 case 16: 1312 switch (desc->nr_channels) { 1313 case 1: 1314 result = FMT_16_FLOAT; 1315 goto out_word4; 1316 case 2: 1317 result = FMT_16_16_FLOAT; 1318 goto out_word4; 1319 case 4: 1320 result = FMT_16_16_16_16_FLOAT; 1321 goto out_word4; 1322 } 1323 goto out_unknown; 1324 case 32: 1325 switch (desc->nr_channels) { 1326 case 1: 1327 result = FMT_32_FLOAT; 1328 goto out_word4; 1329 case 2: 1330 result = FMT_32_32_FLOAT; 1331 goto out_word4; 1332 case 4: 1333 result = FMT_32_32_32_32_FLOAT; 1334 goto out_word4; 1335 } 1336 } 1337 goto out_unknown; 1338 } 1339 1340out_word4: 1341 1342 if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB && !is_srgb_valid) 1343 return ~0; 1344 if (word4_p) 1345 *word4_p = word4; 1346 if (yuv_format_p) 1347 *yuv_format_p = yuv_format; 1348 return result; 1349out_unknown: 1350 /* R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); */ 1351 return ~0; 1352} 1353