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