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