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