1/* 2 * Copyright © 2014 Broadcom 3 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#include "pipe/p_defines.h" 26#include "util/u_blit.h" 27#include "util/u_memory.h" 28#include "util/u_format.h" 29#include "util/u_inlines.h" 30#include "util/u_surface.h" 31#include "util/u_transfer_helper.h" 32#include "util/u_upload_mgr.h" 33#include "util/u_drm.h" 34 35#include "drm-uapi/drm_fourcc.h" 36#include "drm-uapi/vc4_drm.h" 37#include "vc4_screen.h" 38#include "vc4_context.h" 39#include "vc4_resource.h" 40#include "vc4_tiling.h" 41 42static bool 43vc4_resource_bo_alloc(struct vc4_resource *rsc) 44{ 45 struct pipe_resource *prsc = &rsc->base; 46 struct pipe_screen *pscreen = prsc->screen; 47 struct vc4_bo *bo; 48 49 if (vc4_debug & VC4_DEBUG_SURFACE) { 50 fprintf(stderr, "alloc %p: size %d + offset %d -> %d\n", 51 rsc, 52 rsc->slices[0].size, 53 rsc->slices[0].offset, 54 rsc->slices[0].offset + 55 rsc->slices[0].size + 56 rsc->cube_map_stride * (prsc->array_size - 1)); 57 } 58 59 bo = vc4_bo_alloc(vc4_screen(pscreen), 60 rsc->slices[0].offset + 61 rsc->slices[0].size + 62 rsc->cube_map_stride * (prsc->array_size - 1), 63 "resource"); 64 if (bo) { 65 vc4_bo_unreference(&rsc->bo); 66 rsc->bo = bo; 67 return true; 68 } else { 69 return false; 70 } 71} 72 73static void 74vc4_resource_transfer_unmap(struct pipe_context *pctx, 75 struct pipe_transfer *ptrans) 76{ 77 struct vc4_context *vc4 = vc4_context(pctx); 78 struct vc4_transfer *trans = vc4_transfer(ptrans); 79 80 if (trans->map) { 81 struct vc4_resource *rsc = vc4_resource(ptrans->resource); 82 struct vc4_resource_slice *slice = &rsc->slices[ptrans->level]; 83 84 if (ptrans->usage & PIPE_TRANSFER_WRITE) { 85 vc4_store_tiled_image(rsc->bo->map + slice->offset + 86 ptrans->box.z * rsc->cube_map_stride, 87 slice->stride, 88 trans->map, ptrans->stride, 89 slice->tiling, rsc->cpp, 90 &ptrans->box); 91 } 92 free(trans->map); 93 } 94 95 pipe_resource_reference(&ptrans->resource, NULL); 96 slab_free(&vc4->transfer_pool, ptrans); 97} 98 99static void * 100vc4_resource_transfer_map(struct pipe_context *pctx, 101 struct pipe_resource *prsc, 102 unsigned level, unsigned usage, 103 const struct pipe_box *box, 104 struct pipe_transfer **pptrans) 105{ 106 struct vc4_context *vc4 = vc4_context(pctx); 107 struct vc4_resource *rsc = vc4_resource(prsc); 108 struct vc4_transfer *trans; 109 struct pipe_transfer *ptrans; 110 enum pipe_format format = prsc->format; 111 char *buf; 112 113 /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is 114 * being mapped. 115 */ 116 if ((usage & PIPE_TRANSFER_DISCARD_RANGE) && 117 !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) && 118 !(prsc->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) && 119 prsc->last_level == 0 && 120 prsc->width0 == box->width && 121 prsc->height0 == box->height && 122 prsc->depth0 == box->depth && 123 prsc->array_size == 1 && 124 rsc->bo->private) { 125 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; 126 } 127 128 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { 129 if (vc4_resource_bo_alloc(rsc)) { 130 /* If it might be bound as one of our vertex buffers, 131 * make sure we re-emit vertex buffer state. 132 */ 133 if (prsc->bind & PIPE_BIND_VERTEX_BUFFER) 134 vc4->dirty |= VC4_DIRTY_VTXBUF; 135 } else { 136 /* If we failed to reallocate, flush users so that we 137 * don't violate any syncing requirements. 138 */ 139 vc4_flush_jobs_reading_resource(vc4, prsc); 140 } 141 } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 142 /* If we're writing and the buffer is being used by the CL, we 143 * have to flush the CL first. If we're only reading, we need 144 * to flush if the CL has written our buffer. 145 */ 146 if (usage & PIPE_TRANSFER_WRITE) 147 vc4_flush_jobs_reading_resource(vc4, prsc); 148 else 149 vc4_flush_jobs_writing_resource(vc4, prsc); 150 } 151 152 if (usage & PIPE_TRANSFER_WRITE) { 153 rsc->writes++; 154 rsc->initialized_buffers = ~0; 155 } 156 157 trans = slab_alloc(&vc4->transfer_pool); 158 if (!trans) 159 return NULL; 160 161 /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */ 162 163 /* slab_alloc_st() doesn't zero: */ 164 memset(trans, 0, sizeof(*trans)); 165 ptrans = &trans->base; 166 167 pipe_resource_reference(&ptrans->resource, prsc); 168 ptrans->level = level; 169 ptrans->usage = usage; 170 ptrans->box = *box; 171 172 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) 173 buf = vc4_bo_map_unsynchronized(rsc->bo); 174 else 175 buf = vc4_bo_map(rsc->bo); 176 if (!buf) { 177 fprintf(stderr, "Failed to map bo\n"); 178 goto fail; 179 } 180 181 *pptrans = ptrans; 182 183 struct vc4_resource_slice *slice = &rsc->slices[level]; 184 if (rsc->tiled) { 185 /* No direct mappings of tiled, since we need to manually 186 * tile/untile. 187 */ 188 if (usage & PIPE_TRANSFER_MAP_DIRECTLY) 189 return NULL; 190 191 if (format == PIPE_FORMAT_ETC1_RGB8) { 192 /* ETC1 is arranged as 64-bit blocks, where each block 193 * is 4x4 pixels. Texture tiling operates on the 194 * 64-bit block the way it would an uncompressed 195 * pixels. 196 */ 197 assert(!(ptrans->box.x & 3)); 198 assert(!(ptrans->box.y & 3)); 199 ptrans->box.x >>= 2; 200 ptrans->box.y >>= 2; 201 ptrans->box.width = (ptrans->box.width + 3) >> 2; 202 ptrans->box.height = (ptrans->box.height + 3) >> 2; 203 } 204 205 ptrans->stride = ptrans->box.width * rsc->cpp; 206 ptrans->layer_stride = ptrans->stride * ptrans->box.height; 207 208 trans->map = malloc(ptrans->layer_stride * ptrans->box.depth); 209 210 if (usage & PIPE_TRANSFER_READ) { 211 vc4_load_tiled_image(trans->map, ptrans->stride, 212 buf + slice->offset + 213 ptrans->box.z * rsc->cube_map_stride, 214 slice->stride, 215 slice->tiling, rsc->cpp, 216 &ptrans->box); 217 } 218 return trans->map; 219 } else { 220 ptrans->stride = slice->stride; 221 ptrans->layer_stride = ptrans->stride; 222 223 return buf + slice->offset + 224 ptrans->box.y / util_format_get_blockheight(format) * ptrans->stride + 225 ptrans->box.x / util_format_get_blockwidth(format) * rsc->cpp + 226 ptrans->box.z * rsc->cube_map_stride; 227 } 228 229 230fail: 231 vc4_resource_transfer_unmap(pctx, ptrans); 232 return NULL; 233} 234 235static void 236vc4_texture_subdata(struct pipe_context *pctx, 237 struct pipe_resource *prsc, 238 unsigned level, 239 unsigned usage, 240 const struct pipe_box *box, 241 const void *data, 242 unsigned stride, 243 unsigned layer_stride) 244{ 245 struct vc4_resource *rsc = vc4_resource(prsc); 246 struct vc4_resource_slice *slice = &rsc->slices[level]; 247 248 /* For a direct mapping, we can just take the u_transfer path. */ 249 if (!rsc->tiled || 250 box->depth != 1 || 251 (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)) { 252 return u_default_texture_subdata(pctx, prsc, level, usage, box, 253 data, stride, layer_stride); 254 } 255 256 /* Otherwise, map and store the texture data directly into the tiled 257 * texture. 258 */ 259 void *buf; 260 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) 261 buf = vc4_bo_map_unsynchronized(rsc->bo); 262 else 263 buf = vc4_bo_map(rsc->bo); 264 265 vc4_store_tiled_image(buf + slice->offset + 266 box->z * rsc->cube_map_stride, 267 slice->stride, 268 (void *)data, stride, 269 slice->tiling, rsc->cpp, 270 box); 271} 272 273static void 274vc4_resource_destroy(struct pipe_screen *pscreen, 275 struct pipe_resource *prsc) 276{ 277 struct vc4_screen *screen = vc4_screen(pscreen); 278 struct vc4_resource *rsc = vc4_resource(prsc); 279 vc4_bo_unreference(&rsc->bo); 280 281 if (rsc->scanout) 282 renderonly_scanout_destroy(rsc->scanout, screen->ro); 283 284 free(rsc); 285} 286 287static boolean 288vc4_resource_get_handle(struct pipe_screen *pscreen, 289 struct pipe_context *pctx, 290 struct pipe_resource *prsc, 291 struct winsys_handle *whandle, 292 unsigned usage) 293{ 294 struct vc4_screen *screen = vc4_screen(pscreen); 295 struct vc4_resource *rsc = vc4_resource(prsc); 296 297 whandle->stride = rsc->slices[0].stride; 298 whandle->offset = 0; 299 300 /* If we're passing some reference to our BO out to some other part of 301 * the system, then we can't do any optimizations about only us being 302 * the ones seeing it (like BO caching or shadow update avoidance). 303 */ 304 rsc->bo->private = false; 305 306 if (rsc->tiled) 307 whandle->modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED; 308 else 309 whandle->modifier = DRM_FORMAT_MOD_LINEAR; 310 311 switch (whandle->type) { 312 case WINSYS_HANDLE_TYPE_SHARED: 313 if (screen->ro) { 314 /* This could probably be supported, assuming that a 315 * control node was used for pl111. 316 */ 317 fprintf(stderr, "flink unsupported with pl111\n"); 318 return FALSE; 319 } 320 321 return vc4_bo_flink(rsc->bo, &whandle->handle); 322 case WINSYS_HANDLE_TYPE_KMS: 323 if (screen->ro) { 324 assert(rsc->scanout); 325 return renderonly_get_handle(rsc->scanout, whandle); 326 } 327 whandle->handle = rsc->bo->handle; 328 return TRUE; 329 case WINSYS_HANDLE_TYPE_FD: 330 /* FDs are cross-device, so we can export directly from vc4. 331 */ 332 whandle->handle = vc4_bo_get_dmabuf(rsc->bo); 333 return whandle->handle != -1; 334 } 335 336 return FALSE; 337} 338 339static void 340vc4_setup_slices(struct vc4_resource *rsc, const char *caller) 341{ 342 struct pipe_resource *prsc = &rsc->base; 343 uint32_t width = prsc->width0; 344 uint32_t height = prsc->height0; 345 if (prsc->format == PIPE_FORMAT_ETC1_RGB8) { 346 width = (width + 3) >> 2; 347 height = (height + 3) >> 2; 348 } 349 350 uint32_t pot_width = util_next_power_of_two(width); 351 uint32_t pot_height = util_next_power_of_two(height); 352 uint32_t offset = 0; 353 uint32_t utile_w = vc4_utile_width(rsc->cpp); 354 uint32_t utile_h = vc4_utile_height(rsc->cpp); 355 356 for (int i = prsc->last_level; i >= 0; i--) { 357 struct vc4_resource_slice *slice = &rsc->slices[i]; 358 359 uint32_t level_width, level_height; 360 if (i == 0) { 361 level_width = width; 362 level_height = height; 363 } else { 364 level_width = u_minify(pot_width, i); 365 level_height = u_minify(pot_height, i); 366 } 367 368 if (!rsc->tiled) { 369 slice->tiling = VC4_TILING_FORMAT_LINEAR; 370 if (prsc->nr_samples > 1) { 371 /* MSAA (4x) surfaces are stored as raw tile buffer contents. */ 372 level_width = align(level_width, 32); 373 level_height = align(level_height, 32); 374 } else { 375 level_width = align(level_width, utile_w); 376 } 377 } else { 378 if (vc4_size_is_lt(level_width, level_height, 379 rsc->cpp)) { 380 slice->tiling = VC4_TILING_FORMAT_LT; 381 level_width = align(level_width, utile_w); 382 level_height = align(level_height, utile_h); 383 } else { 384 slice->tiling = VC4_TILING_FORMAT_T; 385 level_width = align(level_width, 386 4 * 2 * utile_w); 387 level_height = align(level_height, 388 4 * 2 * utile_h); 389 } 390 } 391 392 slice->offset = offset; 393 slice->stride = (level_width * rsc->cpp * 394 MAX2(prsc->nr_samples, 1)); 395 slice->size = level_height * slice->stride; 396 397 offset += slice->size; 398 399 if (vc4_debug & VC4_DEBUG_SURFACE) { 400 static const char tiling_chars[] = { 401 [VC4_TILING_FORMAT_LINEAR] = 'R', 402 [VC4_TILING_FORMAT_LT] = 'L', 403 [VC4_TILING_FORMAT_T] = 'T' 404 }; 405 fprintf(stderr, 406 "rsc %s %p (format %s: vc4 %d), %dx%d: " 407 "level %d (%c) -> %dx%d, stride %d@0x%08x\n", 408 caller, rsc, 409 util_format_short_name(prsc->format), 410 rsc->vc4_format, 411 prsc->width0, prsc->height0, 412 i, tiling_chars[slice->tiling], 413 level_width, level_height, 414 slice->stride, slice->offset); 415 } 416 } 417 418 /* The texture base pointer that has to point to level 0 doesn't have 419 * intra-page bits, so we have to align it, and thus shift up all the 420 * smaller slices. 421 */ 422 uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) - 423 rsc->slices[0].offset); 424 if (page_align_offset) { 425 for (int i = 0; i <= prsc->last_level; i++) 426 rsc->slices[i].offset += page_align_offset; 427 } 428 429 /* Cube map faces appear as whole miptrees at a page-aligned offset 430 * from the first face's miptree. 431 */ 432 if (prsc->target == PIPE_TEXTURE_CUBE) { 433 rsc->cube_map_stride = align(rsc->slices[0].offset + 434 rsc->slices[0].size, 4096); 435 } 436} 437 438static struct vc4_resource * 439vc4_resource_setup(struct pipe_screen *pscreen, 440 const struct pipe_resource *tmpl) 441{ 442 struct vc4_resource *rsc = CALLOC_STRUCT(vc4_resource); 443 if (!rsc) 444 return NULL; 445 struct pipe_resource *prsc = &rsc->base; 446 447 *prsc = *tmpl; 448 449 pipe_reference_init(&prsc->reference, 1); 450 prsc->screen = pscreen; 451 452 if (prsc->nr_samples <= 1) 453 rsc->cpp = util_format_get_blocksize(tmpl->format); 454 else 455 rsc->cpp = sizeof(uint32_t); 456 457 assert(rsc->cpp); 458 459 return rsc; 460} 461 462static enum vc4_texture_data_type 463get_resource_texture_format(struct pipe_resource *prsc) 464{ 465 struct vc4_resource *rsc = vc4_resource(prsc); 466 uint8_t format = vc4_get_tex_format(prsc->format); 467 468 if (!rsc->tiled) { 469 if (prsc->nr_samples > 1) { 470 return ~0; 471 } else { 472 if (format == VC4_TEXTURE_TYPE_RGBA8888) 473 return VC4_TEXTURE_TYPE_RGBA32R; 474 else 475 return ~0; 476 } 477 } 478 479 return format; 480} 481 482static struct pipe_resource * 483vc4_resource_create_with_modifiers(struct pipe_screen *pscreen, 484 const struct pipe_resource *tmpl, 485 const uint64_t *modifiers, 486 int count) 487{ 488 struct vc4_screen *screen = vc4_screen(pscreen); 489 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl); 490 struct pipe_resource *prsc = &rsc->base; 491 bool linear_ok = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count); 492 /* Use a tiled layout if we can, for better 3D performance. */ 493 bool should_tile = true; 494 495 /* VBOs/PBOs are untiled (and 1 height). */ 496 if (tmpl->target == PIPE_BUFFER) 497 should_tile = false; 498 499 /* MSAA buffers are linear. */ 500 if (tmpl->nr_samples > 1) 501 should_tile = false; 502 503 /* No tiling when we're sharing with another device (pl111). */ 504 if (screen->ro && (tmpl->bind & PIPE_BIND_SCANOUT)) 505 should_tile = false; 506 507 /* Cursors are always linear, and the user can request linear as well. 508 */ 509 if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR)) 510 should_tile = false; 511 512 /* No shared objects with LT format -- the kernel only has T-format 513 * metadata. LT objects are small enough it's not worth the trouble to 514 * give them metadata to tile. 515 */ 516 if ((tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT)) && 517 vc4_size_is_lt(prsc->width0, prsc->height0, rsc->cpp)) 518 should_tile = false; 519 520 /* If we're sharing or scanning out, we need the ioctl present to 521 * inform the kernel or the other side. 522 */ 523 if ((tmpl->bind & (PIPE_BIND_SHARED | 524 PIPE_BIND_SCANOUT)) && !screen->has_tiling_ioctl) 525 should_tile = false; 526 527 /* No user-specified modifier; determine our own. */ 528 if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) { 529 linear_ok = true; 530 rsc->tiled = should_tile; 531 } else if (should_tile && 532 drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, 533 modifiers, count)) { 534 rsc->tiled = true; 535 } else if (linear_ok) { 536 rsc->tiled = false; 537 } else { 538 fprintf(stderr, "Unsupported modifier requested\n"); 539 return NULL; 540 } 541 542 if (tmpl->target != PIPE_BUFFER) 543 rsc->vc4_format = get_resource_texture_format(prsc); 544 545 vc4_setup_slices(rsc, "create"); 546 if (!vc4_resource_bo_alloc(rsc)) 547 goto fail; 548 549 if (screen->has_tiling_ioctl) { 550 uint64_t modifier; 551 if (rsc->tiled) 552 modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED; 553 else 554 modifier = DRM_FORMAT_MOD_LINEAR; 555 struct drm_vc4_set_tiling set_tiling = { 556 .handle = rsc->bo->handle, 557 .modifier = modifier, 558 }; 559 int ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_SET_TILING, 560 &set_tiling); 561 if (ret != 0) 562 goto fail; 563 } 564 565 /* Set up the "scanout resource" (the dmabuf export of our buffer to 566 * the KMS handle) if the buffer might ever have 567 * resource_get_handle(WINSYS_HANDLE_TYPE_KMS) called on it. 568 * create_with_modifiers() doesn't give us usage flags, so we have to 569 * assume that all calls with modifiers are scanout-possible. 570 */ 571 if (screen->ro && 572 ((tmpl->bind & PIPE_BIND_SCANOUT) || 573 !(count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID))) { 574 rsc->scanout = 575 renderonly_scanout_for_resource(prsc, screen->ro, NULL); 576 if (!rsc->scanout) 577 goto fail; 578 } 579 580 vc4_bo_label(screen, rsc->bo, "%sresource %dx%d@%d/%d", 581 (tmpl->bind & PIPE_BIND_SCANOUT) ? "scanout " : "", 582 tmpl->width0, tmpl->height0, 583 rsc->cpp * 8, prsc->last_level); 584 585 return prsc; 586fail: 587 vc4_resource_destroy(pscreen, prsc); 588 return NULL; 589} 590 591struct pipe_resource * 592vc4_resource_create(struct pipe_screen *pscreen, 593 const struct pipe_resource *tmpl) 594{ 595 const uint64_t mod = DRM_FORMAT_MOD_INVALID; 596 return vc4_resource_create_with_modifiers(pscreen, tmpl, &mod, 1); 597} 598 599static struct pipe_resource * 600vc4_resource_from_handle(struct pipe_screen *pscreen, 601 const struct pipe_resource *tmpl, 602 struct winsys_handle *whandle, 603 unsigned usage) 604{ 605 struct vc4_screen *screen = vc4_screen(pscreen); 606 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl); 607 struct pipe_resource *prsc = &rsc->base; 608 struct vc4_resource_slice *slice = &rsc->slices[0]; 609 610 if (!rsc) 611 return NULL; 612 613 switch (whandle->type) { 614 case WINSYS_HANDLE_TYPE_SHARED: 615 rsc->bo = vc4_bo_open_name(screen, whandle->handle); 616 break; 617 case WINSYS_HANDLE_TYPE_FD: 618 rsc->bo = vc4_bo_open_dmabuf(screen, whandle->handle); 619 break; 620 default: 621 fprintf(stderr, 622 "Attempt to import unsupported handle type %d\n", 623 whandle->type); 624 } 625 626 if (!rsc->bo) 627 goto fail; 628 629 struct drm_vc4_get_tiling get_tiling = { 630 .handle = rsc->bo->handle, 631 }; 632 int ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling); 633 634 if (ret != 0) { 635 whandle->modifier = DRM_FORMAT_MOD_LINEAR; 636 } else if (whandle->modifier == DRM_FORMAT_MOD_INVALID) { 637 whandle->modifier = get_tiling.modifier; 638 } else if (whandle->modifier != get_tiling.modifier) { 639 fprintf(stderr, 640 "Modifier 0x%llx vs. tiling (0x%llx) mismatch\n", 641 (long long)whandle->modifier, get_tiling.modifier); 642 goto fail; 643 } 644 645 switch (whandle->modifier) { 646 case DRM_FORMAT_MOD_LINEAR: 647 rsc->tiled = false; 648 break; 649 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: 650 rsc->tiled = true; 651 break; 652 default: 653 fprintf(stderr, 654 "Attempt to import unsupported modifier 0x%llx\n", 655 (long long)whandle->modifier); 656 goto fail; 657 } 658 659 rsc->vc4_format = get_resource_texture_format(prsc); 660 vc4_setup_slices(rsc, "import"); 661 662 if (whandle->offset != 0) { 663 if (rsc->tiled) { 664 fprintf(stderr, 665 "Attempt to import unsupported " 666 "winsys offset %u\n", 667 whandle->offset); 668 goto fail; 669 } 670 671 rsc->slices[0].offset += whandle->offset; 672 673 if (rsc->slices[0].offset + rsc->slices[0].size > 674 rsc->bo->size) { 675 fprintf(stderr, "Attempt to import " 676 "with overflowing offset (%d + %d > %d)\n", 677 whandle->offset, 678 rsc->slices[0].size, 679 rsc->bo->size); 680 goto fail; 681 } 682 } 683 684 if (screen->ro) { 685 /* Make sure that renderonly has a handle to our buffer in the 686 * display's fd, so that a later renderonly_get_handle() 687 * returns correct handles or GEM names. 688 */ 689 rsc->scanout = 690 renderonly_create_gpu_import_for_resource(prsc, 691 screen->ro, 692 NULL); 693 if (!rsc->scanout) 694 goto fail; 695 } 696 697 if (rsc->tiled && whandle->stride != slice->stride) { 698 static bool warned = false; 699 if (!warned) { 700 warned = true; 701 fprintf(stderr, 702 "Attempting to import %dx%d %s with " 703 "unsupported stride %d instead of %d\n", 704 prsc->width0, prsc->height0, 705 util_format_short_name(prsc->format), 706 whandle->stride, 707 slice->stride); 708 } 709 goto fail; 710 } else if (!rsc->tiled) { 711 slice->stride = whandle->stride; 712 } 713 714 return prsc; 715 716fail: 717 vc4_resource_destroy(pscreen, prsc); 718 return NULL; 719} 720 721static struct pipe_surface * 722vc4_create_surface(struct pipe_context *pctx, 723 struct pipe_resource *ptex, 724 const struct pipe_surface *surf_tmpl) 725{ 726 struct vc4_surface *surface = CALLOC_STRUCT(vc4_surface); 727 struct vc4_resource *rsc = vc4_resource(ptex); 728 729 if (!surface) 730 return NULL; 731 732 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); 733 734 struct pipe_surface *psurf = &surface->base; 735 unsigned level = surf_tmpl->u.tex.level; 736 737 pipe_reference_init(&psurf->reference, 1); 738 pipe_resource_reference(&psurf->texture, ptex); 739 740 psurf->context = pctx; 741 psurf->format = surf_tmpl->format; 742 psurf->width = u_minify(ptex->width0, level); 743 psurf->height = u_minify(ptex->height0, level); 744 psurf->u.tex.level = level; 745 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer; 746 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer; 747 surface->offset = (rsc->slices[level].offset + 748 psurf->u.tex.first_layer * rsc->cube_map_stride); 749 surface->tiling = rsc->slices[level].tiling; 750 751 return &surface->base; 752} 753 754static void 755vc4_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf) 756{ 757 pipe_resource_reference(&psurf->texture, NULL); 758 FREE(psurf); 759} 760 761static void 762vc4_dump_surface_non_msaa(struct pipe_surface *psurf) 763{ 764 struct pipe_resource *prsc = psurf->texture; 765 struct vc4_resource *rsc = vc4_resource(prsc); 766 uint32_t *map = vc4_bo_map(rsc->bo); 767 uint32_t stride = rsc->slices[0].stride / 4; 768 uint32_t width = psurf->width; 769 uint32_t height = psurf->height; 770 uint32_t chunk_w = width / 79; 771 uint32_t chunk_h = height / 40; 772 uint32_t found_colors[10]; 773 uint32_t num_found_colors = 0; 774 775 if (rsc->vc4_format != VC4_TEXTURE_TYPE_RGBA32R) { 776 fprintf(stderr, "%s: Unsupported format %s\n", 777 __func__, util_format_short_name(psurf->format)); 778 return; 779 } 780 781 for (int by = 0; by < height; by += chunk_h) { 782 for (int bx = 0; bx < width; bx += chunk_w) { 783 int all_found_color = -1; /* nothing found */ 784 785 for (int y = by; y < MIN2(height, by + chunk_h); y++) { 786 for (int x = bx; x < MIN2(width, bx + chunk_w); x++) { 787 uint32_t pix = map[y * stride + x]; 788 789 int i; 790 for (i = 0; i < num_found_colors; i++) { 791 if (pix == found_colors[i]) 792 break; 793 } 794 if (i == num_found_colors && 795 num_found_colors < 796 ARRAY_SIZE(found_colors)) { 797 found_colors[num_found_colors++] = pix; 798 } 799 800 if (i < num_found_colors) { 801 if (all_found_color == -1) 802 all_found_color = i; 803 else if (i != all_found_color) 804 all_found_color = ARRAY_SIZE(found_colors); 805 } 806 } 807 } 808 /* If all pixels for this chunk have a consistent 809 * value, then print a character for it. Either a 810 * fixed name (particularly common for piglit tests), 811 * or a runtime-generated number. 812 */ 813 if (all_found_color >= 0 && 814 all_found_color < ARRAY_SIZE(found_colors)) { 815 static const struct { 816 uint32_t val; 817 const char *c; 818 } named_colors[] = { 819 { 0xff000000, "█" }, 820 { 0x00000000, "█" }, 821 { 0xffff0000, "r" }, 822 { 0xff00ff00, "g" }, 823 { 0xff0000ff, "b" }, 824 { 0xffffffff, "w" }, 825 }; 826 int i; 827 for (i = 0; i < ARRAY_SIZE(named_colors); i++) { 828 if (named_colors[i].val == 829 found_colors[all_found_color]) { 830 fprintf(stderr, "%s", 831 named_colors[i].c); 832 break; 833 } 834 } 835 /* For unnamed colors, print a number and the 836 * numbers will have values printed at the 837 * end. 838 */ 839 if (i == ARRAY_SIZE(named_colors)) { 840 fprintf(stderr, "%c", 841 '0' + all_found_color); 842 } 843 } else { 844 /* If there's no consistent color, print this. 845 */ 846 fprintf(stderr, "."); 847 } 848 } 849 fprintf(stderr, "\n"); 850 } 851 852 for (int i = 0; i < num_found_colors; i++) { 853 fprintf(stderr, "color %d: 0x%08x\n", i, found_colors[i]); 854 } 855} 856 857static uint32_t 858vc4_surface_msaa_get_sample(struct pipe_surface *psurf, 859 uint32_t x, uint32_t y, uint32_t sample) 860{ 861 struct pipe_resource *prsc = psurf->texture; 862 struct vc4_resource *rsc = vc4_resource(prsc); 863 uint32_t tile_w = 32, tile_h = 32; 864 uint32_t tiles_w = DIV_ROUND_UP(psurf->width, 32); 865 866 uint32_t tile_x = x / tile_w; 867 uint32_t tile_y = y / tile_h; 868 uint32_t *tile = (vc4_bo_map(rsc->bo) + 869 VC4_TILE_BUFFER_SIZE * (tile_y * tiles_w + tile_x)); 870 uint32_t subtile_x = x % tile_w; 871 uint32_t subtile_y = y % tile_h; 872 873 uint32_t quad_samples = VC4_MAX_SAMPLES * 4; 874 uint32_t tile_stride = quad_samples * tile_w / 2; 875 876 return *((uint32_t *)tile + 877 (subtile_y >> 1) * tile_stride + 878 (subtile_x >> 1) * quad_samples + 879 ((subtile_y & 1) << 1) + 880 (subtile_x & 1) + 881 sample); 882} 883 884static void 885vc4_dump_surface_msaa_char(struct pipe_surface *psurf, 886 uint32_t start_x, uint32_t start_y, 887 uint32_t w, uint32_t h) 888{ 889 bool all_same_color = true; 890 uint32_t all_pix = 0; 891 892 for (int y = start_y; y < start_y + h; y++) { 893 for (int x = start_x; x < start_x + w; x++) { 894 for (int s = 0; s < VC4_MAX_SAMPLES; s++) { 895 uint32_t pix = vc4_surface_msaa_get_sample(psurf, 896 x, y, 897 s); 898 if (x == start_x && y == start_y) 899 all_pix = pix; 900 else if (all_pix != pix) 901 all_same_color = false; 902 } 903 } 904 } 905 if (all_same_color) { 906 static const struct { 907 uint32_t val; 908 const char *c; 909 } named_colors[] = { 910 { 0xff000000, "█" }, 911 { 0x00000000, "█" }, 912 { 0xffff0000, "r" }, 913 { 0xff00ff00, "g" }, 914 { 0xff0000ff, "b" }, 915 { 0xffffffff, "w" }, 916 }; 917 int i; 918 for (i = 0; i < ARRAY_SIZE(named_colors); i++) { 919 if (named_colors[i].val == all_pix) { 920 fprintf(stderr, "%s", 921 named_colors[i].c); 922 return; 923 } 924 } 925 fprintf(stderr, "x"); 926 } else { 927 fprintf(stderr, "."); 928 } 929} 930 931static void 932vc4_dump_surface_msaa(struct pipe_surface *psurf) 933{ 934 uint32_t tile_w = 32, tile_h = 32; 935 uint32_t tiles_w = DIV_ROUND_UP(psurf->width, tile_w); 936 uint32_t tiles_h = DIV_ROUND_UP(psurf->height, tile_h); 937 uint32_t char_w = 140, char_h = 60; 938 uint32_t char_w_per_tile = char_w / tiles_w - 1; 939 uint32_t char_h_per_tile = char_h / tiles_h - 1; 940 941 fprintf(stderr, "Surface: %dx%d (%dx MSAA)\n", 942 psurf->width, psurf->height, psurf->texture->nr_samples); 943 944 for (int x = 0; x < (char_w_per_tile + 1) * tiles_w; x++) 945 fprintf(stderr, "-"); 946 fprintf(stderr, "\n"); 947 948 for (int ty = 0; ty < psurf->height; ty += tile_h) { 949 for (int y = 0; y < char_h_per_tile; y++) { 950 951 for (int tx = 0; tx < psurf->width; tx += tile_w) { 952 for (int x = 0; x < char_w_per_tile; x++) { 953 uint32_t bx1 = (x * tile_w / 954 char_w_per_tile); 955 uint32_t bx2 = ((x + 1) * tile_w / 956 char_w_per_tile); 957 uint32_t by1 = (y * tile_h / 958 char_h_per_tile); 959 uint32_t by2 = ((y + 1) * tile_h / 960 char_h_per_tile); 961 962 vc4_dump_surface_msaa_char(psurf, 963 tx + bx1, 964 ty + by1, 965 bx2 - bx1, 966 by2 - by1); 967 } 968 fprintf(stderr, "|"); 969 } 970 fprintf(stderr, "\n"); 971 } 972 973 for (int x = 0; x < (char_w_per_tile + 1) * tiles_w; x++) 974 fprintf(stderr, "-"); 975 fprintf(stderr, "\n"); 976 } 977} 978 979/** Debug routine to dump the contents of an 8888 surface to the console */ 980void 981vc4_dump_surface(struct pipe_surface *psurf) 982{ 983 if (!psurf) 984 return; 985 986 if (psurf->texture->nr_samples > 1) 987 vc4_dump_surface_msaa(psurf); 988 else 989 vc4_dump_surface_non_msaa(psurf); 990} 991 992static void 993vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource) 994{ 995 /* All calls to flush_resource are followed by a flush of the context, 996 * so there's nothing to do. 997 */ 998} 999 1000void 1001vc4_update_shadow_baselevel_texture(struct pipe_context *pctx, 1002 struct pipe_sampler_view *pview) 1003{ 1004 struct vc4_context *vc4 = vc4_context(pctx); 1005 struct vc4_sampler_view *view = vc4_sampler_view(pview); 1006 struct vc4_resource *shadow = vc4_resource(view->texture); 1007 struct vc4_resource *orig = vc4_resource(pview->texture); 1008 1009 assert(view->texture != pview->texture); 1010 1011 if (shadow->writes == orig->writes && orig->bo->private) 1012 return; 1013 1014 perf_debug("Updating %dx%d@%d shadow texture due to %s\n", 1015 orig->base.width0, orig->base.height0, 1016 pview->u.tex.first_level, 1017 pview->u.tex.first_level ? "base level" : "raster layout"); 1018 1019 for (int i = 0; i <= shadow->base.last_level; i++) { 1020 unsigned width = u_minify(shadow->base.width0, i); 1021 unsigned height = u_minify(shadow->base.height0, i); 1022 struct pipe_blit_info info = { 1023 .dst = { 1024 .resource = &shadow->base, 1025 .level = i, 1026 .box = { 1027 .x = 0, 1028 .y = 0, 1029 .z = 0, 1030 .width = width, 1031 .height = height, 1032 .depth = 1, 1033 }, 1034 .format = shadow->base.format, 1035 }, 1036 .src = { 1037 .resource = &orig->base, 1038 .level = pview->u.tex.first_level + i, 1039 .box = { 1040 .x = 0, 1041 .y = 0, 1042 .z = 0, 1043 .width = width, 1044 .height = height, 1045 .depth = 1, 1046 }, 1047 .format = orig->base.format, 1048 }, 1049 .mask = ~0, 1050 }; 1051 pctx->blit(pctx, &info); 1052 } 1053 1054 shadow->writes = orig->writes; 1055} 1056 1057/** 1058 * Converts a 4-byte index buffer to 2 bytes. 1059 * 1060 * Since GLES2 only has support for 1 and 2-byte indices, the hardware doesn't 1061 * include 4-byte index support, and we have to shrink it down. 1062 * 1063 * There's no fallback support for when indices end up being larger than 2^16, 1064 * though it will at least assertion fail. Also, if the original index data 1065 * was in user memory, it would be nice to not have uploaded it to a VBO 1066 * before translating. 1067 */ 1068struct pipe_resource * 1069vc4_get_shadow_index_buffer(struct pipe_context *pctx, 1070 const struct pipe_draw_info *info, 1071 uint32_t offset, 1072 uint32_t count, 1073 uint32_t *shadow_offset) 1074{ 1075 struct vc4_context *vc4 = vc4_context(pctx); 1076 struct vc4_resource *orig = vc4_resource(info->index.resource); 1077 perf_debug("Fallback conversion for %d uint indices\n", count); 1078 1079 void *data; 1080 struct pipe_resource *shadow_rsc = NULL; 1081 u_upload_alloc(vc4->uploader, 0, count * 2, 4, 1082 shadow_offset, &shadow_rsc, &data); 1083 uint16_t *dst = data; 1084 1085 struct pipe_transfer *src_transfer = NULL; 1086 const uint32_t *src; 1087 if (info->has_user_indices) { 1088 src = info->index.user; 1089 } else { 1090 src = pipe_buffer_map_range(pctx, &orig->base, 1091 offset, 1092 count * 4, 1093 PIPE_TRANSFER_READ, &src_transfer); 1094 } 1095 1096 for (int i = 0; i < count; i++) { 1097 uint32_t src_index = src[i]; 1098 assert(src_index <= 0xffff); 1099 dst[i] = src_index; 1100 } 1101 1102 if (src_transfer) 1103 pctx->transfer_unmap(pctx, src_transfer); 1104 1105 return shadow_rsc; 1106} 1107 1108static const struct u_transfer_vtbl transfer_vtbl = { 1109 .resource_create = vc4_resource_create, 1110 .resource_destroy = vc4_resource_destroy, 1111 .transfer_map = vc4_resource_transfer_map, 1112 .transfer_unmap = vc4_resource_transfer_unmap, 1113 .transfer_flush_region = u_default_transfer_flush_region, 1114}; 1115 1116void 1117vc4_resource_screen_init(struct pipe_screen *pscreen) 1118{ 1119 struct vc4_screen *screen = vc4_screen(pscreen); 1120 1121 pscreen->resource_create = vc4_resource_create; 1122 pscreen->resource_create_with_modifiers = 1123 vc4_resource_create_with_modifiers; 1124 pscreen->resource_from_handle = vc4_resource_from_handle; 1125 pscreen->resource_destroy = u_resource_destroy_vtbl; 1126 pscreen->resource_get_handle = vc4_resource_get_handle; 1127 pscreen->resource_destroy = vc4_resource_destroy; 1128 pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, 1129 false, false, 1130 false, true); 1131 1132 /* Test if the kernel has GET_TILING; it will return -EINVAL if the 1133 * ioctl does not exist, but -ENOENT if we pass an impossible handle. 1134 * 0 cannot be a valid GEM object, so use that. 1135 */ 1136 struct drm_vc4_get_tiling get_tiling = { 1137 .handle = 0x0, 1138 }; 1139 int ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling); 1140 if (ret == -1 && errno == ENOENT) 1141 screen->has_tiling_ioctl = true; 1142} 1143 1144void 1145vc4_resource_context_init(struct pipe_context *pctx) 1146{ 1147 pctx->transfer_map = u_transfer_helper_transfer_map; 1148 pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 1149 pctx->transfer_unmap = u_transfer_helper_transfer_unmap; 1150 pctx->buffer_subdata = u_default_buffer_subdata; 1151 pctx->texture_subdata = vc4_texture_subdata; 1152 pctx->create_surface = vc4_create_surface; 1153 pctx->surface_destroy = vc4_surface_destroy; 1154 pctx->resource_copy_region = util_resource_copy_region; 1155 pctx->blit = vc4_blit; 1156 pctx->flush_resource = vc4_flush_resource; 1157} 1158