1/* 2 * Copyright © 2014-2017 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_format_zs.h" 34#include "util/u_drm.h" 35 36#include "drm-uapi/drm_fourcc.h" 37#include "v3d_screen.h" 38#include "v3d_context.h" 39#include "v3d_resource.h" 40#include "v3d_tiling.h" 41#include "broadcom/cle/v3d_packet_v33_pack.h" 42 43static void 44v3d_debug_resource_layout(struct v3d_resource *rsc, const char *caller) 45{ 46 if (!(V3D_DEBUG & V3D_DEBUG_SURFACE)) 47 return; 48 49 struct pipe_resource *prsc = &rsc->base; 50 51 if (prsc->target == PIPE_BUFFER) { 52 fprintf(stderr, 53 "rsc %s %p (format %s), %dx%d buffer @0x%08x-0x%08x\n", 54 caller, rsc, 55 util_format_short_name(prsc->format), 56 prsc->width0, prsc->height0, 57 rsc->bo->offset, 58 rsc->bo->offset + rsc->bo->size - 1); 59 return; 60 } 61 62 static const char *const tiling_descriptions[] = { 63 [VC5_TILING_RASTER] = "R", 64 [VC5_TILING_LINEARTILE] = "LT", 65 [VC5_TILING_UBLINEAR_1_COLUMN] = "UB1", 66 [VC5_TILING_UBLINEAR_2_COLUMN] = "UB2", 67 [VC5_TILING_UIF_NO_XOR] = "UIF", 68 [VC5_TILING_UIF_XOR] = "UIF^", 69 }; 70 71 for (int i = 0; i <= prsc->last_level; i++) { 72 struct v3d_resource_slice *slice = &rsc->slices[i]; 73 74 int level_width = slice->stride / rsc->cpp; 75 int level_height = slice->padded_height; 76 int level_depth = 77 u_minify(util_next_power_of_two(prsc->depth0), i); 78 79 fprintf(stderr, 80 "rsc %s %p (format %s), %dx%d: " 81 "level %d (%s) %dx%dx%d -> %dx%dx%d, stride %d@0x%08x\n", 82 caller, rsc, 83 util_format_short_name(prsc->format), 84 prsc->width0, prsc->height0, 85 i, tiling_descriptions[slice->tiling], 86 u_minify(prsc->width0, i), 87 u_minify(prsc->height0, i), 88 u_minify(prsc->depth0, i), 89 level_width, 90 level_height, 91 level_depth, 92 slice->stride, 93 rsc->bo->offset + slice->offset); 94 } 95} 96 97static bool 98v3d_resource_bo_alloc(struct v3d_resource *rsc) 99{ 100 struct pipe_resource *prsc = &rsc->base; 101 struct pipe_screen *pscreen = prsc->screen; 102 struct v3d_bo *bo; 103 104 bo = v3d_bo_alloc(v3d_screen(pscreen), rsc->size, "resource"); 105 if (bo) { 106 v3d_bo_unreference(&rsc->bo); 107 rsc->bo = bo; 108 v3d_debug_resource_layout(rsc, "alloc"); 109 return true; 110 } else { 111 return false; 112 } 113} 114 115static void 116v3d_resource_transfer_unmap(struct pipe_context *pctx, 117 struct pipe_transfer *ptrans) 118{ 119 struct v3d_context *v3d = v3d_context(pctx); 120 struct v3d_transfer *trans = v3d_transfer(ptrans); 121 122 if (trans->map) { 123 struct v3d_resource *rsc = v3d_resource(ptrans->resource); 124 struct v3d_resource_slice *slice = &rsc->slices[ptrans->level]; 125 126 if (ptrans->usage & PIPE_TRANSFER_WRITE) { 127 for (int z = 0; z < ptrans->box.depth; z++) { 128 void *dst = rsc->bo->map + 129 v3d_layer_offset(&rsc->base, 130 ptrans->level, 131 ptrans->box.z + z); 132 v3d_store_tiled_image(dst, 133 slice->stride, 134 (trans->map + 135 ptrans->stride * 136 ptrans->box.height * z), 137 ptrans->stride, 138 slice->tiling, rsc->cpp, 139 slice->padded_height, 140 &ptrans->box); 141 } 142 } 143 free(trans->map); 144 } 145 146 pipe_resource_reference(&ptrans->resource, NULL); 147 slab_free(&v3d->transfer_pool, ptrans); 148} 149 150static void 151v3d_map_usage_prep(struct pipe_context *pctx, 152 struct pipe_resource *prsc, 153 unsigned usage) 154{ 155 struct v3d_context *v3d = v3d_context(pctx); 156 struct v3d_resource *rsc = v3d_resource(prsc); 157 158 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { 159 if (v3d_resource_bo_alloc(rsc)) { 160 /* If it might be bound as one of our vertex buffers 161 * or UBOs, make sure we re-emit vertex buffer state 162 * or uniforms. 163 */ 164 if (prsc->bind & PIPE_BIND_VERTEX_BUFFER) 165 v3d->dirty |= VC5_DIRTY_VTXBUF; 166 if (prsc->bind & PIPE_BIND_CONSTANT_BUFFER) 167 v3d->dirty |= VC5_DIRTY_CONSTBUF; 168 } else { 169 /* If we failed to reallocate, flush users so that we 170 * don't violate any syncing requirements. 171 */ 172 v3d_flush_jobs_reading_resource(v3d, prsc); 173 } 174 } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 175 /* If we're writing and the buffer is being used by the CL, we 176 * have to flush the CL first. If we're only reading, we need 177 * to flush if the CL has written our buffer. 178 */ 179 if (usage & PIPE_TRANSFER_WRITE) 180 v3d_flush_jobs_reading_resource(v3d, prsc); 181 else 182 v3d_flush_jobs_writing_resource(v3d, prsc); 183 } 184 185 if (usage & PIPE_TRANSFER_WRITE) { 186 rsc->writes++; 187 rsc->initialized_buffers = ~0; 188 } 189} 190 191static void * 192v3d_resource_transfer_map(struct pipe_context *pctx, 193 struct pipe_resource *prsc, 194 unsigned level, unsigned usage, 195 const struct pipe_box *box, 196 struct pipe_transfer **pptrans) 197{ 198 struct v3d_context *v3d = v3d_context(pctx); 199 struct v3d_resource *rsc = v3d_resource(prsc); 200 struct v3d_transfer *trans; 201 struct pipe_transfer *ptrans; 202 enum pipe_format format = prsc->format; 203 char *buf; 204 205 /* MSAA maps should have been handled by u_transfer_helper. */ 206 assert(prsc->nr_samples <= 1); 207 208 /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is 209 * being mapped. 210 */ 211 if ((usage & PIPE_TRANSFER_DISCARD_RANGE) && 212 !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) && 213 !(prsc->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) && 214 prsc->last_level == 0 && 215 prsc->width0 == box->width && 216 prsc->height0 == box->height && 217 prsc->depth0 == box->depth && 218 prsc->array_size == 1 && 219 rsc->bo->private) { 220 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; 221 } 222 223 v3d_map_usage_prep(pctx, prsc, usage); 224 225 trans = slab_alloc(&v3d->transfer_pool); 226 if (!trans) 227 return NULL; 228 229 /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */ 230 231 /* slab_alloc_st() doesn't zero: */ 232 memset(trans, 0, sizeof(*trans)); 233 ptrans = &trans->base; 234 235 pipe_resource_reference(&ptrans->resource, prsc); 236 ptrans->level = level; 237 ptrans->usage = usage; 238 ptrans->box = *box; 239 240 /* Note that the current kernel implementation is synchronous, so no 241 * need to do syncing stuff here yet. 242 */ 243 244 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) 245 buf = v3d_bo_map_unsynchronized(rsc->bo); 246 else 247 buf = v3d_bo_map(rsc->bo); 248 if (!buf) { 249 fprintf(stderr, "Failed to map bo\n"); 250 goto fail; 251 } 252 253 *pptrans = ptrans; 254 255 /* Our load/store routines work on entire compressed blocks. */ 256 ptrans->box.x /= util_format_get_blockwidth(format); 257 ptrans->box.y /= util_format_get_blockheight(format); 258 ptrans->box.width = DIV_ROUND_UP(ptrans->box.width, 259 util_format_get_blockwidth(format)); 260 ptrans->box.height = DIV_ROUND_UP(ptrans->box.height, 261 util_format_get_blockheight(format)); 262 263 struct v3d_resource_slice *slice = &rsc->slices[level]; 264 if (rsc->tiled) { 265 /* No direct mappings of tiled, since we need to manually 266 * tile/untile. 267 */ 268 if (usage & PIPE_TRANSFER_MAP_DIRECTLY) 269 return NULL; 270 271 ptrans->stride = ptrans->box.width * rsc->cpp; 272 ptrans->layer_stride = ptrans->stride * ptrans->box.height; 273 274 trans->map = malloc(ptrans->layer_stride * ptrans->box.depth); 275 276 if (usage & PIPE_TRANSFER_READ) { 277 for (int z = 0; z < ptrans->box.depth; z++) { 278 void *src = rsc->bo->map + 279 v3d_layer_offset(&rsc->base, 280 ptrans->level, 281 ptrans->box.z + z); 282 v3d_load_tiled_image((trans->map + 283 ptrans->stride * 284 ptrans->box.height * z), 285 ptrans->stride, 286 src, 287 slice->stride, 288 slice->tiling, rsc->cpp, 289 slice->padded_height, 290 &ptrans->box); 291 } 292 } 293 return trans->map; 294 } else { 295 ptrans->stride = slice->stride; 296 ptrans->layer_stride = rsc->cube_map_stride; 297 298 return buf + slice->offset + 299 ptrans->box.y * ptrans->stride + 300 ptrans->box.x * rsc->cpp + 301 ptrans->box.z * rsc->cube_map_stride; 302 } 303 304 305fail: 306 v3d_resource_transfer_unmap(pctx, ptrans); 307 return NULL; 308} 309 310static void 311v3d_texture_subdata(struct pipe_context *pctx, 312 struct pipe_resource *prsc, 313 unsigned level, 314 unsigned usage, 315 const struct pipe_box *box, 316 const void *data, 317 unsigned stride, 318 unsigned layer_stride) 319{ 320 struct v3d_resource *rsc = v3d_resource(prsc); 321 struct v3d_resource_slice *slice = &rsc->slices[level]; 322 323 /* For a direct mapping, we can just take the u_transfer path. */ 324 if (!rsc->tiled) { 325 return u_default_texture_subdata(pctx, prsc, level, usage, box, 326 data, stride, layer_stride); 327 } 328 329 /* Otherwise, map and store the texture data directly into the tiled 330 * texture. Note that gallium's texture_subdata may be called with 331 * obvious usage flags missing! 332 */ 333 v3d_map_usage_prep(pctx, prsc, usage | (PIPE_TRANSFER_WRITE | 334 PIPE_TRANSFER_DISCARD_RANGE)); 335 336 void *buf; 337 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED) 338 buf = v3d_bo_map_unsynchronized(rsc->bo); 339 else 340 buf = v3d_bo_map(rsc->bo); 341 342 for (int i = 0; i < box->depth; i++) { 343 v3d_store_tiled_image(buf + 344 v3d_layer_offset(&rsc->base, 345 level, 346 box->z + i), 347 slice->stride, 348 (void *)data + layer_stride * i, 349 stride, 350 slice->tiling, rsc->cpp, slice->padded_height, 351 box); 352 } 353} 354 355static void 356v3d_resource_destroy(struct pipe_screen *pscreen, 357 struct pipe_resource *prsc) 358{ 359 struct v3d_screen *screen = v3d_screen(pscreen); 360 struct v3d_resource *rsc = v3d_resource(prsc); 361 362 if (rsc->scanout) 363 renderonly_scanout_destroy(rsc->scanout, screen->ro); 364 365 v3d_bo_unreference(&rsc->bo); 366 free(rsc); 367} 368 369static boolean 370v3d_resource_get_handle(struct pipe_screen *pscreen, 371 struct pipe_context *pctx, 372 struct pipe_resource *prsc, 373 struct winsys_handle *whandle, 374 unsigned usage) 375{ 376 struct v3d_screen *screen = v3d_screen(pscreen); 377 struct v3d_resource *rsc = v3d_resource(prsc); 378 struct v3d_bo *bo = rsc->bo; 379 380 whandle->stride = rsc->slices[0].stride; 381 whandle->offset = 0; 382 383 /* If we're passing some reference to our BO out to some other part of 384 * the system, then we can't do any optimizations about only us being 385 * the ones seeing it (like BO caching). 386 */ 387 bo->private = false; 388 389 if (rsc->tiled) { 390 /* A shared tiled buffer should always be allocated as UIF, 391 * not UBLINEAR or LT. 392 */ 393 assert(rsc->slices[0].tiling == VC5_TILING_UIF_XOR || 394 rsc->slices[0].tiling == VC5_TILING_UIF_NO_XOR); 395 whandle->modifier = DRM_FORMAT_MOD_BROADCOM_UIF; 396 } else { 397 whandle->modifier = DRM_FORMAT_MOD_LINEAR; 398 } 399 400 switch (whandle->type) { 401 case WINSYS_HANDLE_TYPE_SHARED: 402 return v3d_bo_flink(bo, &whandle->handle); 403 case WINSYS_HANDLE_TYPE_KMS: 404 if (screen->ro) { 405 assert(rsc->scanout); 406 bool ok = renderonly_get_handle(rsc->scanout, whandle); 407 whandle->stride = rsc->slices[0].stride; 408 return ok; 409 } 410 whandle->handle = bo->handle; 411 return TRUE; 412 case WINSYS_HANDLE_TYPE_FD: 413 whandle->handle = v3d_bo_get_dmabuf(bo); 414 return whandle->handle != -1; 415 } 416 417 return FALSE; 418} 419 420#define PAGE_UB_ROWS (VC5_UIFCFG_PAGE_SIZE / VC5_UIFBLOCK_ROW_SIZE) 421#define PAGE_UB_ROWS_TIMES_1_5 ((PAGE_UB_ROWS * 3) >> 1) 422#define PAGE_CACHE_UB_ROWS (VC5_PAGE_CACHE_SIZE / VC5_UIFBLOCK_ROW_SIZE) 423#define PAGE_CACHE_MINUS_1_5_UB_ROWS (PAGE_CACHE_UB_ROWS - PAGE_UB_ROWS_TIMES_1_5) 424 425/** 426 * Computes the HW's UIFblock padding for a given height/cpp. 427 * 428 * The goal of the padding is to keep pages of the same color (bank number) at 429 * least half a page away from each other vertically when crossing between 430 * between columns of UIF blocks. 431 */ 432static uint32_t 433v3d_get_ub_pad(struct v3d_resource *rsc, uint32_t height) 434{ 435 uint32_t utile_h = v3d_utile_height(rsc->cpp); 436 uint32_t uif_block_h = utile_h * 2; 437 uint32_t height_ub = height / uif_block_h; 438 439 uint32_t height_offset_in_pc = height_ub % PAGE_CACHE_UB_ROWS; 440 441 /* For the perfectly-aligned-for-UIF-XOR case, don't add any pad. */ 442 if (height_offset_in_pc == 0) 443 return 0; 444 445 /* Try padding up to where we're offset by at least half a page. */ 446 if (height_offset_in_pc < PAGE_UB_ROWS_TIMES_1_5) { 447 /* If we fit entirely in the page cache, don't pad. */ 448 if (height_ub < PAGE_CACHE_UB_ROWS) 449 return 0; 450 else 451 return PAGE_UB_ROWS_TIMES_1_5 - height_offset_in_pc; 452 } 453 454 /* If we're close to being aligned to page cache size, then round up 455 * and rely on XOR. 456 */ 457 if (height_offset_in_pc > PAGE_CACHE_MINUS_1_5_UB_ROWS) 458 return PAGE_CACHE_UB_ROWS - height_offset_in_pc; 459 460 /* Otherwise, we're far enough away (top and bottom) to not need any 461 * padding. 462 */ 463 return 0; 464} 465 466static void 467v3d_setup_slices(struct v3d_resource *rsc, uint32_t winsys_stride, 468 bool uif_top) 469{ 470 struct pipe_resource *prsc = &rsc->base; 471 uint32_t width = prsc->width0; 472 uint32_t height = prsc->height0; 473 uint32_t depth = prsc->depth0; 474 /* Note that power-of-two padding is based on level 1. These are not 475 * equivalent to just util_next_power_of_two(dimension), because at a 476 * level 0 dimension of 9, the level 1 power-of-two padded value is 4, 477 * not 8. 478 */ 479 uint32_t pot_width = 2 * util_next_power_of_two(u_minify(width, 1)); 480 uint32_t pot_height = 2 * util_next_power_of_two(u_minify(height, 1)); 481 uint32_t pot_depth = 2 * util_next_power_of_two(u_minify(depth, 1)); 482 uint32_t offset = 0; 483 uint32_t utile_w = v3d_utile_width(rsc->cpp); 484 uint32_t utile_h = v3d_utile_height(rsc->cpp); 485 uint32_t uif_block_w = utile_w * 2; 486 uint32_t uif_block_h = utile_h * 2; 487 uint32_t block_width = util_format_get_blockwidth(prsc->format); 488 uint32_t block_height = util_format_get_blockheight(prsc->format); 489 bool msaa = prsc->nr_samples > 1; 490 491 /* MSAA textures/renderbuffers are always laid out as single-level 492 * UIF. 493 */ 494 uif_top |= msaa; 495 496 /* Check some easy mistakes to make in a resource_create() call that 497 * will break our setup. 498 */ 499 assert(prsc->array_size != 0); 500 assert(prsc->depth0 != 0); 501 502 for (int i = prsc->last_level; i >= 0; i--) { 503 struct v3d_resource_slice *slice = &rsc->slices[i]; 504 505 uint32_t level_width, level_height, level_depth; 506 if (i < 2) { 507 level_width = u_minify(width, i); 508 level_height = u_minify(height, i); 509 } else { 510 level_width = u_minify(pot_width, i); 511 level_height = u_minify(pot_height, i); 512 } 513 if (i < 1) 514 level_depth = u_minify(depth, i); 515 else 516 level_depth = u_minify(pot_depth, i); 517 518 if (msaa) { 519 level_width *= 2; 520 level_height *= 2; 521 } 522 523 level_width = DIV_ROUND_UP(level_width, block_width); 524 level_height = DIV_ROUND_UP(level_height, block_height); 525 526 if (!rsc->tiled) { 527 slice->tiling = VC5_TILING_RASTER; 528 if (prsc->target == PIPE_TEXTURE_1D) 529 level_width = align(level_width, 64 / rsc->cpp); 530 } else { 531 if ((i != 0 || !uif_top) && 532 (level_width <= utile_w || 533 level_height <= utile_h)) { 534 slice->tiling = VC5_TILING_LINEARTILE; 535 level_width = align(level_width, utile_w); 536 level_height = align(level_height, utile_h); 537 } else if ((i != 0 || !uif_top) && 538 level_width <= uif_block_w) { 539 slice->tiling = VC5_TILING_UBLINEAR_1_COLUMN; 540 level_width = align(level_width, uif_block_w); 541 level_height = align(level_height, uif_block_h); 542 } else if ((i != 0 || !uif_top) && 543 level_width <= 2 * uif_block_w) { 544 slice->tiling = VC5_TILING_UBLINEAR_2_COLUMN; 545 level_width = align(level_width, 2 * uif_block_w); 546 level_height = align(level_height, uif_block_h); 547 } else { 548 /* We align the width to a 4-block column of 549 * UIF blocks, but we only align height to UIF 550 * blocks. 551 */ 552 level_width = align(level_width, 553 4 * uif_block_w); 554 level_height = align(level_height, 555 uif_block_h); 556 557 slice->ub_pad = v3d_get_ub_pad(rsc, 558 level_height); 559 level_height += slice->ub_pad * uif_block_h; 560 561 /* If the padding set us to to be aligned to 562 * the page cache size, then the HW will use 563 * the XOR bit on odd columns to get us 564 * perfectly misaligned 565 */ 566 if ((level_height / uif_block_h) % 567 (VC5_PAGE_CACHE_SIZE / 568 VC5_UIFBLOCK_ROW_SIZE) == 0) { 569 slice->tiling = VC5_TILING_UIF_XOR; 570 } else { 571 slice->tiling = VC5_TILING_UIF_NO_XOR; 572 } 573 } 574 } 575 576 slice->offset = offset; 577 if (winsys_stride) 578 slice->stride = winsys_stride; 579 else 580 slice->stride = level_width * rsc->cpp; 581 slice->padded_height = level_height; 582 slice->size = level_height * slice->stride; 583 584 uint32_t slice_total_size = slice->size * level_depth; 585 586 /* The HW aligns level 1's base to a page if any of level 1 or 587 * below could be UIF XOR. The lower levels then inherit the 588 * alignment for as long as necesary, thanks to being power of 589 * two aligned. 590 */ 591 if (i == 1 && 592 level_width > 4 * uif_block_w && 593 level_height > PAGE_CACHE_MINUS_1_5_UB_ROWS * uif_block_h) { 594 slice_total_size = align(slice_total_size, 595 VC5_UIFCFG_PAGE_SIZE); 596 } 597 598 offset += slice_total_size; 599 600 } 601 rsc->size = offset; 602 603 /* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only 604 * needs to be aligned to utile boundaries. Since tiles are laid out 605 * from small to big in memory, we need to align the later UIF slices 606 * to UIF blocks, if they were preceded by non-UIF-block-aligned LT 607 * slices. 608 * 609 * We additionally align to 4k, which improves UIF XOR performance. 610 */ 611 uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) - 612 rsc->slices[0].offset); 613 if (page_align_offset) { 614 rsc->size += page_align_offset; 615 for (int i = 0; i <= prsc->last_level; i++) 616 rsc->slices[i].offset += page_align_offset; 617 } 618 619 /* Arrays and cube textures have a stride which is the distance from 620 * one full mipmap tree to the next (64b aligned). For 3D textures, 621 * we need to program the stride between slices of miplevel 0. 622 */ 623 if (prsc->target != PIPE_TEXTURE_3D) { 624 rsc->cube_map_stride = align(rsc->slices[0].offset + 625 rsc->slices[0].size, 64); 626 rsc->size += rsc->cube_map_stride * (prsc->array_size - 1); 627 } else { 628 rsc->cube_map_stride = rsc->slices[0].size; 629 } 630} 631 632uint32_t 633v3d_layer_offset(struct pipe_resource *prsc, uint32_t level, uint32_t layer) 634{ 635 struct v3d_resource *rsc = v3d_resource(prsc); 636 struct v3d_resource_slice *slice = &rsc->slices[level]; 637 638 if (prsc->target == PIPE_TEXTURE_3D) 639 return slice->offset + layer * slice->size; 640 else 641 return slice->offset + layer * rsc->cube_map_stride; 642} 643 644static struct v3d_resource * 645v3d_resource_setup(struct pipe_screen *pscreen, 646 const struct pipe_resource *tmpl) 647{ 648 struct v3d_screen *screen = v3d_screen(pscreen); 649 struct v3d_resource *rsc = CALLOC_STRUCT(v3d_resource); 650 if (!rsc) 651 return NULL; 652 struct pipe_resource *prsc = &rsc->base; 653 654 *prsc = *tmpl; 655 656 pipe_reference_init(&prsc->reference, 1); 657 prsc->screen = pscreen; 658 659 if (prsc->nr_samples <= 1 || 660 screen->devinfo.ver >= 40 || 661 util_format_is_depth_or_stencil(prsc->format)) { 662 rsc->cpp = util_format_get_blocksize(prsc->format); 663 if (screen->devinfo.ver < 40 && prsc->nr_samples > 1) 664 rsc->cpp *= prsc->nr_samples; 665 } else { 666 assert(v3d_rt_format_supported(&screen->devinfo, prsc->format)); 667 uint32_t output_image_format = 668 v3d_get_rt_format(&screen->devinfo, prsc->format); 669 uint32_t internal_type; 670 uint32_t internal_bpp; 671 v3d_get_internal_type_bpp_for_output_format(&screen->devinfo, 672 output_image_format, 673 &internal_type, 674 &internal_bpp); 675 switch (internal_bpp) { 676 case V3D_INTERNAL_BPP_32: 677 rsc->cpp = 4; 678 break; 679 case V3D_INTERNAL_BPP_64: 680 rsc->cpp = 8; 681 break; 682 case V3D_INTERNAL_BPP_128: 683 rsc->cpp = 16; 684 break; 685 } 686 } 687 688 assert(rsc->cpp); 689 690 return rsc; 691} 692 693static struct pipe_resource * 694v3d_resource_create_with_modifiers(struct pipe_screen *pscreen, 695 const struct pipe_resource *tmpl, 696 const uint64_t *modifiers, 697 int count) 698{ 699 struct v3d_screen *screen = v3d_screen(pscreen); 700 701 bool linear_ok = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count); 702 struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl); 703 struct pipe_resource *prsc = &rsc->base; 704 /* Use a tiled layout if we can, for better 3D performance. */ 705 bool should_tile = true; 706 707 /* VBOs/PBOs are untiled (and 1 height). */ 708 if (tmpl->target == PIPE_BUFFER) 709 should_tile = false; 710 711 /* Cursors are always linear, and the user can request linear as well. 712 */ 713 if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR)) 714 should_tile = false; 715 716 /* 1D and 1D_ARRAY textures are always raster-order. */ 717 if (tmpl->target == PIPE_TEXTURE_1D || 718 tmpl->target == PIPE_TEXTURE_1D_ARRAY) 719 should_tile = false; 720 721 /* Scanout BOs for simulator need to be linear for interaction with 722 * i965. 723 */ 724 if (using_v3d_simulator && 725 tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT)) 726 should_tile = false; 727 728 /* If using the old-school SCANOUT flag, we don't know what the screen 729 * might support other than linear. Just force linear. 730 */ 731 if (tmpl->bind & PIPE_BIND_SCANOUT) 732 should_tile = false; 733 734 /* No user-specified modifier; determine our own. */ 735 if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) { 736 linear_ok = true; 737 rsc->tiled = should_tile; 738 } else if (should_tile && 739 drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_UIF, 740 modifiers, count)) { 741 rsc->tiled = true; 742 } else if (linear_ok) { 743 rsc->tiled = false; 744 } else { 745 fprintf(stderr, "Unsupported modifier requested\n"); 746 goto fail; 747 } 748 749 rsc->internal_format = prsc->format; 750 751 v3d_setup_slices(rsc, 0, tmpl->bind & PIPE_BIND_SHARED); 752 753 /* If we're in a renderonly setup, use the other device to perform our 754 * allocation and just import it to v3d. The other device may be 755 * using CMA, and V3D can import from CMA but doesn't do CMA 756 * allocations on its own. 757 * 758 * We always allocate this way for SHARED, because get_handle will 759 * need a resource on the display fd. 760 */ 761 if (screen->ro && (tmpl->bind & (PIPE_BIND_SCANOUT | 762 PIPE_BIND_SHARED))) { 763 struct winsys_handle handle; 764 struct pipe_resource scanout_tmpl = { 765 .target = prsc->target, 766 .format = PIPE_FORMAT_RGBA8888_UNORM, 767 .width0 = 1024, /* one page */ 768 .height0 = align(rsc->size, 4096) / 4096, 769 .depth0 = 1, 770 .array_size = 1, 771 }; 772 773 rsc->scanout = 774 renderonly_scanout_for_resource(&scanout_tmpl, 775 screen->ro, 776 &handle); 777 778 if (!rsc->scanout) { 779 fprintf(stderr, "Failed to create scanout resource\n"); 780 return NULL; 781 } 782 assert(handle.type == WINSYS_HANDLE_TYPE_FD); 783 rsc->bo = v3d_bo_open_dmabuf(screen, handle.handle); 784 close(handle.handle); 785 786 if (!rsc->bo) 787 goto fail; 788 789 v3d_debug_resource_layout(rsc, "renderonly"); 790 791 return prsc; 792 } else { 793 if (!v3d_resource_bo_alloc(rsc)) 794 goto fail; 795 } 796 797 return prsc; 798fail: 799 v3d_resource_destroy(pscreen, prsc); 800 return NULL; 801} 802 803struct pipe_resource * 804v3d_resource_create(struct pipe_screen *pscreen, 805 const struct pipe_resource *tmpl) 806{ 807 const uint64_t mod = DRM_FORMAT_MOD_INVALID; 808 return v3d_resource_create_with_modifiers(pscreen, tmpl, &mod, 1); 809} 810 811static struct pipe_resource * 812v3d_resource_from_handle(struct pipe_screen *pscreen, 813 const struct pipe_resource *tmpl, 814 struct winsys_handle *whandle, 815 unsigned usage) 816{ 817 struct v3d_screen *screen = v3d_screen(pscreen); 818 struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl); 819 struct pipe_resource *prsc = &rsc->base; 820 struct v3d_resource_slice *slice = &rsc->slices[0]; 821 822 if (!rsc) 823 return NULL; 824 825 switch (whandle->modifier) { 826 case DRM_FORMAT_MOD_LINEAR: 827 rsc->tiled = false; 828 break; 829 case DRM_FORMAT_MOD_BROADCOM_UIF: 830 rsc->tiled = true; 831 break; 832 case DRM_FORMAT_MOD_INVALID: 833 rsc->tiled = screen->ro == NULL; 834 break; 835 default: 836 fprintf(stderr, 837 "Attempt to import unsupported modifier 0x%llx\n", 838 (long long)whandle->modifier); 839 goto fail; 840 } 841 842 if (whandle->offset != 0) { 843 fprintf(stderr, 844 "Attempt to import unsupported winsys offset %u\n", 845 whandle->offset); 846 goto fail; 847 } 848 849 switch (whandle->type) { 850 case WINSYS_HANDLE_TYPE_SHARED: 851 rsc->bo = v3d_bo_open_name(screen, whandle->handle); 852 break; 853 case WINSYS_HANDLE_TYPE_FD: 854 rsc->bo = v3d_bo_open_dmabuf(screen, whandle->handle); 855 break; 856 default: 857 fprintf(stderr, 858 "Attempt to import unsupported handle type %d\n", 859 whandle->type); 860 goto fail; 861 } 862 863 if (!rsc->bo) 864 goto fail; 865 866 rsc->internal_format = prsc->format; 867 868 v3d_setup_slices(rsc, whandle->stride, true); 869 v3d_debug_resource_layout(rsc, "import"); 870 871 if (screen->ro) { 872 /* Make sure that renderonly has a handle to our buffer in the 873 * display's fd, so that a later renderonly_get_handle() 874 * returns correct handles or GEM names. 875 */ 876 rsc->scanout = 877 renderonly_create_gpu_import_for_resource(prsc, 878 screen->ro, 879 NULL); 880 if (!rsc->scanout) { 881 fprintf(stderr, "Failed to create scanout resource.\n"); 882 goto fail; 883 } 884 } 885 886 if (whandle->stride != slice->stride) { 887 static bool warned = false; 888 if (!warned) { 889 warned = true; 890 fprintf(stderr, 891 "Attempting to import %dx%d %s with " 892 "unsupported stride %d instead of %d\n", 893 prsc->width0, prsc->height0, 894 util_format_short_name(prsc->format), 895 whandle->stride, 896 slice->stride); 897 } 898 goto fail; 899 } 900 901 return prsc; 902 903fail: 904 v3d_resource_destroy(pscreen, prsc); 905 return NULL; 906} 907 908void 909v3d_update_shadow_texture(struct pipe_context *pctx, 910 struct pipe_sampler_view *pview) 911{ 912 struct v3d_context *v3d = v3d_context(pctx); 913 struct v3d_sampler_view *view = v3d_sampler_view(pview); 914 struct v3d_resource *shadow = v3d_resource(view->texture); 915 struct v3d_resource *orig = v3d_resource(pview->texture); 916 917 assert(view->texture != pview->texture); 918 919 if (shadow->writes == orig->writes && orig->bo->private) 920 return; 921 922 perf_debug("Updating %dx%d@%d shadow for linear texture\n", 923 orig->base.width0, orig->base.height0, 924 pview->u.tex.first_level); 925 926 for (int i = 0; i <= shadow->base.last_level; i++) { 927 unsigned width = u_minify(shadow->base.width0, i); 928 unsigned height = u_minify(shadow->base.height0, i); 929 struct pipe_blit_info info = { 930 .dst = { 931 .resource = &shadow->base, 932 .level = i, 933 .box = { 934 .x = 0, 935 .y = 0, 936 .z = 0, 937 .width = width, 938 .height = height, 939 .depth = 1, 940 }, 941 .format = shadow->base.format, 942 }, 943 .src = { 944 .resource = &orig->base, 945 .level = pview->u.tex.first_level + i, 946 .box = { 947 .x = 0, 948 .y = 0, 949 .z = 0, 950 .width = width, 951 .height = height, 952 .depth = 1, 953 }, 954 .format = orig->base.format, 955 }, 956 .mask = util_format_get_mask(orig->base.format), 957 }; 958 pctx->blit(pctx, &info); 959 } 960 961 shadow->writes = orig->writes; 962} 963 964static struct pipe_surface * 965v3d_create_surface(struct pipe_context *pctx, 966 struct pipe_resource *ptex, 967 const struct pipe_surface *surf_tmpl) 968{ 969 struct v3d_context *v3d = v3d_context(pctx); 970 struct v3d_screen *screen = v3d->screen; 971 struct v3d_surface *surface = CALLOC_STRUCT(v3d_surface); 972 struct v3d_resource *rsc = v3d_resource(ptex); 973 974 if (!surface) 975 return NULL; 976 977 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); 978 979 struct pipe_surface *psurf = &surface->base; 980 unsigned level = surf_tmpl->u.tex.level; 981 struct v3d_resource_slice *slice = &rsc->slices[level]; 982 983 pipe_reference_init(&psurf->reference, 1); 984 pipe_resource_reference(&psurf->texture, ptex); 985 986 psurf->context = pctx; 987 psurf->format = surf_tmpl->format; 988 psurf->width = u_minify(ptex->width0, level); 989 psurf->height = u_minify(ptex->height0, level); 990 psurf->u.tex.level = level; 991 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer; 992 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer; 993 994 surface->offset = v3d_layer_offset(ptex, level, 995 psurf->u.tex.first_layer); 996 surface->tiling = slice->tiling; 997 998 surface->format = v3d_get_rt_format(&screen->devinfo, psurf->format); 999 1000 const struct util_format_description *desc = 1001 util_format_description(psurf->format); 1002 1003 surface->swap_rb = (desc->swizzle[0] == PIPE_SWIZZLE_Z && 1004 psurf->format != PIPE_FORMAT_B5G6R5_UNORM); 1005 1006 if (util_format_is_depth_or_stencil(psurf->format)) { 1007 switch (psurf->format) { 1008 case PIPE_FORMAT_Z16_UNORM: 1009 surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_16; 1010 break; 1011 case PIPE_FORMAT_Z32_FLOAT: 1012 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 1013 surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_32F; 1014 break; 1015 default: 1016 surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_24; 1017 } 1018 } else { 1019 uint32_t bpp, type; 1020 v3d_get_internal_type_bpp_for_output_format(&screen->devinfo, 1021 surface->format, 1022 &type, &bpp); 1023 surface->internal_type = type; 1024 surface->internal_bpp = bpp; 1025 } 1026 1027 if (surface->tiling == VC5_TILING_UIF_NO_XOR || 1028 surface->tiling == VC5_TILING_UIF_XOR) { 1029 surface->padded_height_of_output_image_in_uif_blocks = 1030 (slice->padded_height / 1031 (2 * v3d_utile_height(rsc->cpp))); 1032 } 1033 1034 if (rsc->separate_stencil) { 1035 surface->separate_stencil = 1036 v3d_create_surface(pctx, &rsc->separate_stencil->base, 1037 surf_tmpl); 1038 } 1039 1040 return &surface->base; 1041} 1042 1043static void 1044v3d_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf) 1045{ 1046 struct v3d_surface *surf = v3d_surface(psurf); 1047 1048 if (surf->separate_stencil) 1049 pipe_surface_reference(&surf->separate_stencil, NULL); 1050 1051 pipe_resource_reference(&psurf->texture, NULL); 1052 FREE(psurf); 1053} 1054 1055static void 1056v3d_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource) 1057{ 1058 /* All calls to flush_resource are followed by a flush of the context, 1059 * so there's nothing to do. 1060 */ 1061} 1062 1063static enum pipe_format 1064v3d_resource_get_internal_format(struct pipe_resource *prsc) 1065{ 1066 return v3d_resource(prsc)->internal_format; 1067} 1068 1069static void 1070v3d_resource_set_stencil(struct pipe_resource *prsc, 1071 struct pipe_resource *stencil) 1072{ 1073 v3d_resource(prsc)->separate_stencil = v3d_resource(stencil); 1074} 1075 1076static struct pipe_resource * 1077v3d_resource_get_stencil(struct pipe_resource *prsc) 1078{ 1079 struct v3d_resource *rsc = v3d_resource(prsc); 1080 1081 return &rsc->separate_stencil->base; 1082} 1083 1084static const struct u_transfer_vtbl transfer_vtbl = { 1085 .resource_create = v3d_resource_create, 1086 .resource_destroy = v3d_resource_destroy, 1087 .transfer_map = v3d_resource_transfer_map, 1088 .transfer_unmap = v3d_resource_transfer_unmap, 1089 .transfer_flush_region = u_default_transfer_flush_region, 1090 .get_internal_format = v3d_resource_get_internal_format, 1091 .set_stencil = v3d_resource_set_stencil, 1092 .get_stencil = v3d_resource_get_stencil, 1093}; 1094 1095void 1096v3d_resource_screen_init(struct pipe_screen *pscreen) 1097{ 1098 pscreen->resource_create_with_modifiers = 1099 v3d_resource_create_with_modifiers; 1100 pscreen->resource_create = u_transfer_helper_resource_create; 1101 pscreen->resource_from_handle = v3d_resource_from_handle; 1102 pscreen->resource_get_handle = v3d_resource_get_handle; 1103 pscreen->resource_destroy = u_transfer_helper_resource_destroy; 1104 pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, 1105 true, false, 1106 true, true); 1107} 1108 1109void 1110v3d_resource_context_init(struct pipe_context *pctx) 1111{ 1112 pctx->transfer_map = u_transfer_helper_transfer_map; 1113 pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 1114 pctx->transfer_unmap = u_transfer_helper_transfer_unmap; 1115 pctx->buffer_subdata = u_default_buffer_subdata; 1116 pctx->texture_subdata = v3d_texture_subdata; 1117 pctx->create_surface = v3d_create_surface; 1118 pctx->surface_destroy = v3d_surface_destroy; 1119 pctx->resource_copy_region = util_resource_copy_region; 1120 pctx->blit = v3d_blit; 1121 pctx->generate_mipmap = v3d_generate_mipmap; 1122 pctx->flush_resource = v3d_flush_resource; 1123} 1124