101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2014-2017 Broadcom 301e04c3fSmrg * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 401e04c3fSmrg * 501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 601e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 701e04c3fSmrg * to deal in the Software without restriction, including without limitation 801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1101e04c3fSmrg * 1201e04c3fSmrg * The above copyright notice and this permission notice (including the next 1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1401e04c3fSmrg * Software. 1501e04c3fSmrg * 1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2201e04c3fSmrg * IN THE SOFTWARE. 2301e04c3fSmrg */ 2401e04c3fSmrg 2501e04c3fSmrg#include "pipe/p_defines.h" 2601e04c3fSmrg#include "util/u_memory.h" 277ec681f3Smrg#include "util/format/u_format.h" 2801e04c3fSmrg#include "util/u_inlines.h" 2901e04c3fSmrg#include "util/u_surface.h" 3001e04c3fSmrg#include "util/u_transfer_helper.h" 3101e04c3fSmrg#include "util/u_upload_mgr.h" 327ec681f3Smrg#include "util/format/u_format_zs.h" 339f464c52Smaya#include "util/u_drm.h" 3401e04c3fSmrg 359f464c52Smaya#include "drm-uapi/drm_fourcc.h" 3601e04c3fSmrg#include "v3d_screen.h" 3701e04c3fSmrg#include "v3d_context.h" 3801e04c3fSmrg#include "v3d_resource.h" 3901e04c3fSmrg#include "broadcom/cle/v3d_packet_v33_pack.h" 4001e04c3fSmrg 4101e04c3fSmrgstatic void 4201e04c3fSmrgv3d_debug_resource_layout(struct v3d_resource *rsc, const char *caller) 4301e04c3fSmrg{ 447ec681f3Smrg if (!(unlikely(V3D_DEBUG & V3D_DEBUG_SURFACE))) 4501e04c3fSmrg return; 4601e04c3fSmrg 4701e04c3fSmrg struct pipe_resource *prsc = &rsc->base; 4801e04c3fSmrg 4901e04c3fSmrg if (prsc->target == PIPE_BUFFER) { 5001e04c3fSmrg fprintf(stderr, 5101e04c3fSmrg "rsc %s %p (format %s), %dx%d buffer @0x%08x-0x%08x\n", 5201e04c3fSmrg caller, rsc, 5301e04c3fSmrg util_format_short_name(prsc->format), 5401e04c3fSmrg prsc->width0, prsc->height0, 5501e04c3fSmrg rsc->bo->offset, 5601e04c3fSmrg rsc->bo->offset + rsc->bo->size - 1); 5701e04c3fSmrg return; 5801e04c3fSmrg } 5901e04c3fSmrg 6001e04c3fSmrg static const char *const tiling_descriptions[] = { 617ec681f3Smrg [V3D_TILING_RASTER] = "R", 627ec681f3Smrg [V3D_TILING_LINEARTILE] = "LT", 637ec681f3Smrg [V3D_TILING_UBLINEAR_1_COLUMN] = "UB1", 647ec681f3Smrg [V3D_TILING_UBLINEAR_2_COLUMN] = "UB2", 657ec681f3Smrg [V3D_TILING_UIF_NO_XOR] = "UIF", 667ec681f3Smrg [V3D_TILING_UIF_XOR] = "UIF^", 6701e04c3fSmrg }; 6801e04c3fSmrg 6901e04c3fSmrg for (int i = 0; i <= prsc->last_level; i++) { 7001e04c3fSmrg struct v3d_resource_slice *slice = &rsc->slices[i]; 7101e04c3fSmrg 7201e04c3fSmrg int level_width = slice->stride / rsc->cpp; 7301e04c3fSmrg int level_height = slice->padded_height; 7401e04c3fSmrg int level_depth = 7501e04c3fSmrg u_minify(util_next_power_of_two(prsc->depth0), i); 7601e04c3fSmrg 7701e04c3fSmrg fprintf(stderr, 7801e04c3fSmrg "rsc %s %p (format %s), %dx%d: " 7901e04c3fSmrg "level %d (%s) %dx%dx%d -> %dx%dx%d, stride %d@0x%08x\n", 8001e04c3fSmrg caller, rsc, 8101e04c3fSmrg util_format_short_name(prsc->format), 8201e04c3fSmrg prsc->width0, prsc->height0, 8301e04c3fSmrg i, tiling_descriptions[slice->tiling], 8401e04c3fSmrg u_minify(prsc->width0, i), 8501e04c3fSmrg u_minify(prsc->height0, i), 8601e04c3fSmrg u_minify(prsc->depth0, i), 8701e04c3fSmrg level_width, 8801e04c3fSmrg level_height, 8901e04c3fSmrg level_depth, 9001e04c3fSmrg slice->stride, 9101e04c3fSmrg rsc->bo->offset + slice->offset); 9201e04c3fSmrg } 9301e04c3fSmrg} 9401e04c3fSmrg 9501e04c3fSmrgstatic bool 9601e04c3fSmrgv3d_resource_bo_alloc(struct v3d_resource *rsc) 9701e04c3fSmrg{ 9801e04c3fSmrg struct pipe_resource *prsc = &rsc->base; 9901e04c3fSmrg struct pipe_screen *pscreen = prsc->screen; 10001e04c3fSmrg struct v3d_bo *bo; 10101e04c3fSmrg 10201e04c3fSmrg bo = v3d_bo_alloc(v3d_screen(pscreen), rsc->size, "resource"); 10301e04c3fSmrg if (bo) { 10401e04c3fSmrg v3d_bo_unreference(&rsc->bo); 10501e04c3fSmrg rsc->bo = bo; 10601e04c3fSmrg v3d_debug_resource_layout(rsc, "alloc"); 10701e04c3fSmrg return true; 10801e04c3fSmrg } else { 10901e04c3fSmrg return false; 11001e04c3fSmrg } 11101e04c3fSmrg} 11201e04c3fSmrg 11301e04c3fSmrgstatic void 11401e04c3fSmrgv3d_resource_transfer_unmap(struct pipe_context *pctx, 11501e04c3fSmrg struct pipe_transfer *ptrans) 11601e04c3fSmrg{ 11701e04c3fSmrg struct v3d_context *v3d = v3d_context(pctx); 11801e04c3fSmrg struct v3d_transfer *trans = v3d_transfer(ptrans); 11901e04c3fSmrg 12001e04c3fSmrg if (trans->map) { 12101e04c3fSmrg struct v3d_resource *rsc = v3d_resource(ptrans->resource); 12201e04c3fSmrg struct v3d_resource_slice *slice = &rsc->slices[ptrans->level]; 12301e04c3fSmrg 1247ec681f3Smrg if (ptrans->usage & PIPE_MAP_WRITE) { 12501e04c3fSmrg for (int z = 0; z < ptrans->box.depth; z++) { 12601e04c3fSmrg void *dst = rsc->bo->map + 12701e04c3fSmrg v3d_layer_offset(&rsc->base, 12801e04c3fSmrg ptrans->level, 12901e04c3fSmrg ptrans->box.z + z); 13001e04c3fSmrg v3d_store_tiled_image(dst, 13101e04c3fSmrg slice->stride, 13201e04c3fSmrg (trans->map + 13301e04c3fSmrg ptrans->stride * 13401e04c3fSmrg ptrans->box.height * z), 13501e04c3fSmrg ptrans->stride, 13601e04c3fSmrg slice->tiling, rsc->cpp, 13701e04c3fSmrg slice->padded_height, 13801e04c3fSmrg &ptrans->box); 13901e04c3fSmrg } 14001e04c3fSmrg } 14101e04c3fSmrg free(trans->map); 14201e04c3fSmrg } 14301e04c3fSmrg 14401e04c3fSmrg pipe_resource_reference(&ptrans->resource, NULL); 14501e04c3fSmrg slab_free(&v3d->transfer_pool, ptrans); 14601e04c3fSmrg} 14701e04c3fSmrg 1487ec681f3Smrgstatic void 1497ec681f3Smrgrebind_sampler_views(struct v3d_context *v3d, 1507ec681f3Smrg struct v3d_resource *rsc) 1517ec681f3Smrg{ 1527ec681f3Smrg for (int st = 0; st < PIPE_SHADER_TYPES; st++) { 1537ec681f3Smrg struct v3d_texture_stateobj *tex = v3d->tex + st; 1547ec681f3Smrg 1557ec681f3Smrg for (unsigned i = 0; i < tex->num_textures; i++) { 1567ec681f3Smrg struct pipe_sampler_view *psview = tex->textures[i]; 1577ec681f3Smrg 1587ec681f3Smrg if (psview->texture != &rsc->base) 1597ec681f3Smrg continue; 1607ec681f3Smrg 1617ec681f3Smrg struct v3d_sampler_view *sview = 1627ec681f3Smrg v3d_sampler_view(psview); 1637ec681f3Smrg 1647ec681f3Smrg v3d_create_texture_shader_state_bo(v3d, sview); 1657ec681f3Smrg 1667ec681f3Smrg v3d_flag_dirty_sampler_state(v3d, st); 1677ec681f3Smrg } 1687ec681f3Smrg } 1697ec681f3Smrg} 1707ec681f3Smrg 1719f464c52Smayastatic void 1729f464c52Smayav3d_map_usage_prep(struct pipe_context *pctx, 1739f464c52Smaya struct pipe_resource *prsc, 1749f464c52Smaya unsigned usage) 17501e04c3fSmrg{ 17601e04c3fSmrg struct v3d_context *v3d = v3d_context(pctx); 17701e04c3fSmrg struct v3d_resource *rsc = v3d_resource(prsc); 17801e04c3fSmrg 1797ec681f3Smrg if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) { 18001e04c3fSmrg if (v3d_resource_bo_alloc(rsc)) { 18101e04c3fSmrg /* If it might be bound as one of our vertex buffers 18201e04c3fSmrg * or UBOs, make sure we re-emit vertex buffer state 18301e04c3fSmrg * or uniforms. 18401e04c3fSmrg */ 18501e04c3fSmrg if (prsc->bind & PIPE_BIND_VERTEX_BUFFER) 1867ec681f3Smrg v3d->dirty |= V3D_DIRTY_VTXBUF; 18701e04c3fSmrg if (prsc->bind & PIPE_BIND_CONSTANT_BUFFER) 1887ec681f3Smrg v3d->dirty |= V3D_DIRTY_CONSTBUF; 1897ec681f3Smrg if (prsc->bind & PIPE_BIND_SAMPLER_VIEW) 1907ec681f3Smrg rebind_sampler_views(v3d, rsc); 19101e04c3fSmrg } else { 19201e04c3fSmrg /* If we failed to reallocate, flush users so that we 19301e04c3fSmrg * don't violate any syncing requirements. 19401e04c3fSmrg */ 1957ec681f3Smrg v3d_flush_jobs_reading_resource(v3d, prsc, 1967ec681f3Smrg V3D_FLUSH_DEFAULT, 1977ec681f3Smrg false); 19801e04c3fSmrg } 1997ec681f3Smrg } else if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 20001e04c3fSmrg /* If we're writing and the buffer is being used by the CL, we 20101e04c3fSmrg * have to flush the CL first. If we're only reading, we need 20201e04c3fSmrg * to flush if the CL has written our buffer. 20301e04c3fSmrg */ 2047ec681f3Smrg if (usage & PIPE_MAP_WRITE) { 2057ec681f3Smrg v3d_flush_jobs_reading_resource(v3d, prsc, 2067ec681f3Smrg V3D_FLUSH_ALWAYS, 2077ec681f3Smrg false); 2087ec681f3Smrg } else { 2097ec681f3Smrg v3d_flush_jobs_writing_resource(v3d, prsc, 2107ec681f3Smrg V3D_FLUSH_ALWAYS, 2117ec681f3Smrg false); 2127ec681f3Smrg } 21301e04c3fSmrg } 21401e04c3fSmrg 2157ec681f3Smrg if (usage & PIPE_MAP_WRITE) { 21601e04c3fSmrg rsc->writes++; 21701e04c3fSmrg rsc->initialized_buffers = ~0; 21801e04c3fSmrg } 2199f464c52Smaya} 2209f464c52Smaya 2219f464c52Smayastatic void * 2229f464c52Smayav3d_resource_transfer_map(struct pipe_context *pctx, 2239f464c52Smaya struct pipe_resource *prsc, 2249f464c52Smaya unsigned level, unsigned usage, 2259f464c52Smaya const struct pipe_box *box, 2269f464c52Smaya struct pipe_transfer **pptrans) 2279f464c52Smaya{ 2289f464c52Smaya struct v3d_context *v3d = v3d_context(pctx); 2299f464c52Smaya struct v3d_resource *rsc = v3d_resource(prsc); 2309f464c52Smaya struct v3d_transfer *trans; 2319f464c52Smaya struct pipe_transfer *ptrans; 2329f464c52Smaya enum pipe_format format = prsc->format; 2339f464c52Smaya char *buf; 2349f464c52Smaya 2359f464c52Smaya /* MSAA maps should have been handled by u_transfer_helper. */ 2369f464c52Smaya assert(prsc->nr_samples <= 1); 2379f464c52Smaya 2389f464c52Smaya /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is 2399f464c52Smaya * being mapped. 2409f464c52Smaya */ 2417ec681f3Smrg if ((usage & PIPE_MAP_DISCARD_RANGE) && 2427ec681f3Smrg !(usage & PIPE_MAP_UNSYNCHRONIZED) && 2439f464c52Smaya !(prsc->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) && 2449f464c52Smaya prsc->last_level == 0 && 2459f464c52Smaya prsc->width0 == box->width && 2469f464c52Smaya prsc->height0 == box->height && 2479f464c52Smaya prsc->depth0 == box->depth && 2489f464c52Smaya prsc->array_size == 1 && 2499f464c52Smaya rsc->bo->private) { 2507ec681f3Smrg usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; 2519f464c52Smaya } 2529f464c52Smaya 2539f464c52Smaya v3d_map_usage_prep(pctx, prsc, usage); 25401e04c3fSmrg 25501e04c3fSmrg trans = slab_alloc(&v3d->transfer_pool); 25601e04c3fSmrg if (!trans) 25701e04c3fSmrg return NULL; 25801e04c3fSmrg 25901e04c3fSmrg /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */ 26001e04c3fSmrg 26101e04c3fSmrg /* slab_alloc_st() doesn't zero: */ 26201e04c3fSmrg memset(trans, 0, sizeof(*trans)); 26301e04c3fSmrg ptrans = &trans->base; 26401e04c3fSmrg 26501e04c3fSmrg pipe_resource_reference(&ptrans->resource, prsc); 26601e04c3fSmrg ptrans->level = level; 26701e04c3fSmrg ptrans->usage = usage; 26801e04c3fSmrg ptrans->box = *box; 26901e04c3fSmrg 27001e04c3fSmrg /* Note that the current kernel implementation is synchronous, so no 27101e04c3fSmrg * need to do syncing stuff here yet. 27201e04c3fSmrg */ 27301e04c3fSmrg 2747ec681f3Smrg if (usage & PIPE_MAP_UNSYNCHRONIZED) 27501e04c3fSmrg buf = v3d_bo_map_unsynchronized(rsc->bo); 27601e04c3fSmrg else 27701e04c3fSmrg buf = v3d_bo_map(rsc->bo); 27801e04c3fSmrg if (!buf) { 27901e04c3fSmrg fprintf(stderr, "Failed to map bo\n"); 28001e04c3fSmrg goto fail; 28101e04c3fSmrg } 28201e04c3fSmrg 28301e04c3fSmrg *pptrans = ptrans; 28401e04c3fSmrg 28501e04c3fSmrg /* Our load/store routines work on entire compressed blocks. */ 28601e04c3fSmrg ptrans->box.x /= util_format_get_blockwidth(format); 28701e04c3fSmrg ptrans->box.y /= util_format_get_blockheight(format); 28801e04c3fSmrg ptrans->box.width = DIV_ROUND_UP(ptrans->box.width, 28901e04c3fSmrg util_format_get_blockwidth(format)); 29001e04c3fSmrg ptrans->box.height = DIV_ROUND_UP(ptrans->box.height, 29101e04c3fSmrg util_format_get_blockheight(format)); 29201e04c3fSmrg 29301e04c3fSmrg struct v3d_resource_slice *slice = &rsc->slices[level]; 29401e04c3fSmrg if (rsc->tiled) { 29501e04c3fSmrg /* No direct mappings of tiled, since we need to manually 29601e04c3fSmrg * tile/untile. 29701e04c3fSmrg */ 2987ec681f3Smrg if (usage & PIPE_MAP_DIRECTLY) 29901e04c3fSmrg return NULL; 30001e04c3fSmrg 30101e04c3fSmrg ptrans->stride = ptrans->box.width * rsc->cpp; 30201e04c3fSmrg ptrans->layer_stride = ptrans->stride * ptrans->box.height; 30301e04c3fSmrg 30401e04c3fSmrg trans->map = malloc(ptrans->layer_stride * ptrans->box.depth); 30501e04c3fSmrg 3067ec681f3Smrg if (usage & PIPE_MAP_READ) { 30701e04c3fSmrg for (int z = 0; z < ptrans->box.depth; z++) { 30801e04c3fSmrg void *src = rsc->bo->map + 30901e04c3fSmrg v3d_layer_offset(&rsc->base, 31001e04c3fSmrg ptrans->level, 31101e04c3fSmrg ptrans->box.z + z); 31201e04c3fSmrg v3d_load_tiled_image((trans->map + 31301e04c3fSmrg ptrans->stride * 31401e04c3fSmrg ptrans->box.height * z), 31501e04c3fSmrg ptrans->stride, 31601e04c3fSmrg src, 31701e04c3fSmrg slice->stride, 31801e04c3fSmrg slice->tiling, rsc->cpp, 31901e04c3fSmrg slice->padded_height, 32001e04c3fSmrg &ptrans->box); 32101e04c3fSmrg } 32201e04c3fSmrg } 32301e04c3fSmrg return trans->map; 32401e04c3fSmrg } else { 32501e04c3fSmrg ptrans->stride = slice->stride; 32601e04c3fSmrg ptrans->layer_stride = rsc->cube_map_stride; 32701e04c3fSmrg 32801e04c3fSmrg return buf + slice->offset + 32901e04c3fSmrg ptrans->box.y * ptrans->stride + 33001e04c3fSmrg ptrans->box.x * rsc->cpp + 33101e04c3fSmrg ptrans->box.z * rsc->cube_map_stride; 33201e04c3fSmrg } 33301e04c3fSmrg 33401e04c3fSmrg 33501e04c3fSmrgfail: 33601e04c3fSmrg v3d_resource_transfer_unmap(pctx, ptrans); 33701e04c3fSmrg return NULL; 33801e04c3fSmrg} 33901e04c3fSmrg 3409f464c52Smayastatic void 3419f464c52Smayav3d_texture_subdata(struct pipe_context *pctx, 3429f464c52Smaya struct pipe_resource *prsc, 3439f464c52Smaya unsigned level, 3449f464c52Smaya unsigned usage, 3459f464c52Smaya const struct pipe_box *box, 3469f464c52Smaya const void *data, 3479f464c52Smaya unsigned stride, 3489f464c52Smaya unsigned layer_stride) 3499f464c52Smaya{ 3509f464c52Smaya struct v3d_resource *rsc = v3d_resource(prsc); 3519f464c52Smaya struct v3d_resource_slice *slice = &rsc->slices[level]; 3529f464c52Smaya 3539f464c52Smaya /* For a direct mapping, we can just take the u_transfer path. */ 3549f464c52Smaya if (!rsc->tiled) { 3559f464c52Smaya return u_default_texture_subdata(pctx, prsc, level, usage, box, 3569f464c52Smaya data, stride, layer_stride); 3579f464c52Smaya } 3589f464c52Smaya 3599f464c52Smaya /* Otherwise, map and store the texture data directly into the tiled 3609f464c52Smaya * texture. Note that gallium's texture_subdata may be called with 3619f464c52Smaya * obvious usage flags missing! 3629f464c52Smaya */ 3637ec681f3Smrg v3d_map_usage_prep(pctx, prsc, usage | (PIPE_MAP_WRITE | 3647ec681f3Smrg PIPE_MAP_DISCARD_RANGE)); 3659f464c52Smaya 3669f464c52Smaya void *buf; 3677ec681f3Smrg if (usage & PIPE_MAP_UNSYNCHRONIZED) 3689f464c52Smaya buf = v3d_bo_map_unsynchronized(rsc->bo); 3699f464c52Smaya else 3709f464c52Smaya buf = v3d_bo_map(rsc->bo); 3719f464c52Smaya 3729f464c52Smaya for (int i = 0; i < box->depth; i++) { 3739f464c52Smaya v3d_store_tiled_image(buf + 3749f464c52Smaya v3d_layer_offset(&rsc->base, 3759f464c52Smaya level, 3769f464c52Smaya box->z + i), 3779f464c52Smaya slice->stride, 3789f464c52Smaya (void *)data + layer_stride * i, 3799f464c52Smaya stride, 3809f464c52Smaya slice->tiling, rsc->cpp, slice->padded_height, 3819f464c52Smaya box); 3829f464c52Smaya } 3839f464c52Smaya} 3849f464c52Smaya 38501e04c3fSmrgstatic void 38601e04c3fSmrgv3d_resource_destroy(struct pipe_screen *pscreen, 38701e04c3fSmrg struct pipe_resource *prsc) 38801e04c3fSmrg{ 3899f464c52Smaya struct v3d_screen *screen = v3d_screen(pscreen); 39001e04c3fSmrg struct v3d_resource *rsc = v3d_resource(prsc); 39101e04c3fSmrg 3929f464c52Smaya if (rsc->scanout) 3939f464c52Smaya renderonly_scanout_destroy(rsc->scanout, screen->ro); 3949f464c52Smaya 39501e04c3fSmrg v3d_bo_unreference(&rsc->bo); 39601e04c3fSmrg free(rsc); 39701e04c3fSmrg} 39801e04c3fSmrg 3997ec681f3Smrgstatic uint64_t 4007ec681f3Smrgv3d_resource_modifier(struct v3d_resource *rsc) 4017ec681f3Smrg{ 4027ec681f3Smrg if (rsc->tiled) { 4037ec681f3Smrg /* A shared tiled buffer should always be allocated as UIF, 4047ec681f3Smrg * not UBLINEAR or LT. 4057ec681f3Smrg */ 4067ec681f3Smrg assert(rsc->slices[0].tiling == V3D_TILING_UIF_XOR || 4077ec681f3Smrg rsc->slices[0].tiling == V3D_TILING_UIF_NO_XOR); 4087ec681f3Smrg return DRM_FORMAT_MOD_BROADCOM_UIF; 4097ec681f3Smrg } else { 4107ec681f3Smrg return DRM_FORMAT_MOD_LINEAR; 4117ec681f3Smrg } 4127ec681f3Smrg} 4137ec681f3Smrg 4147ec681f3Smrgstatic bool 41501e04c3fSmrgv3d_resource_get_handle(struct pipe_screen *pscreen, 41601e04c3fSmrg struct pipe_context *pctx, 41701e04c3fSmrg struct pipe_resource *prsc, 41801e04c3fSmrg struct winsys_handle *whandle, 41901e04c3fSmrg unsigned usage) 42001e04c3fSmrg{ 4219f464c52Smaya struct v3d_screen *screen = v3d_screen(pscreen); 42201e04c3fSmrg struct v3d_resource *rsc = v3d_resource(prsc); 42301e04c3fSmrg struct v3d_bo *bo = rsc->bo; 42401e04c3fSmrg 42501e04c3fSmrg whandle->stride = rsc->slices[0].stride; 42601e04c3fSmrg whandle->offset = 0; 4277ec681f3Smrg whandle->modifier = v3d_resource_modifier(rsc); 42801e04c3fSmrg 42901e04c3fSmrg /* If we're passing some reference to our BO out to some other part of 43001e04c3fSmrg * the system, then we can't do any optimizations about only us being 43101e04c3fSmrg * the ones seeing it (like BO caching). 43201e04c3fSmrg */ 43301e04c3fSmrg bo->private = false; 43401e04c3fSmrg 43501e04c3fSmrg switch (whandle->type) { 43601e04c3fSmrg case WINSYS_HANDLE_TYPE_SHARED: 43701e04c3fSmrg return v3d_bo_flink(bo, &whandle->handle); 43801e04c3fSmrg case WINSYS_HANDLE_TYPE_KMS: 4399f464c52Smaya if (screen->ro) { 4407ec681f3Smrg if (renderonly_get_handle(rsc->scanout, whandle)) { 4417ec681f3Smrg whandle->stride = rsc->slices[0].stride; 4427ec681f3Smrg return true; 4437ec681f3Smrg } 4447ec681f3Smrg return false; 4459f464c52Smaya } 44601e04c3fSmrg whandle->handle = bo->handle; 4477ec681f3Smrg return true; 44801e04c3fSmrg case WINSYS_HANDLE_TYPE_FD: 44901e04c3fSmrg whandle->handle = v3d_bo_get_dmabuf(bo); 45001e04c3fSmrg return whandle->handle != -1; 45101e04c3fSmrg } 45201e04c3fSmrg 4537ec681f3Smrg return false; 45401e04c3fSmrg} 45501e04c3fSmrg 4567ec681f3Smrgstatic bool 4577ec681f3Smrgv3d_resource_get_param(struct pipe_screen *pscreen, 4587ec681f3Smrg struct pipe_context *pctx, struct pipe_resource *prsc, 4597ec681f3Smrg unsigned plane, unsigned layer, unsigned level, 4607ec681f3Smrg enum pipe_resource_param param, 4617ec681f3Smrg unsigned usage, uint64_t *value) 4627ec681f3Smrg{ 4637ec681f3Smrg struct v3d_resource *rsc = v3d_resource(prsc); 4647ec681f3Smrg 4657ec681f3Smrg switch (param) { 4667ec681f3Smrg case PIPE_RESOURCE_PARAM_STRIDE: 4677ec681f3Smrg *value = rsc->slices[level].stride; 4687ec681f3Smrg return true; 4697ec681f3Smrg case PIPE_RESOURCE_PARAM_OFFSET: 4707ec681f3Smrg *value = 0; 4717ec681f3Smrg return true; 4727ec681f3Smrg case PIPE_RESOURCE_PARAM_MODIFIER: 4737ec681f3Smrg *value = v3d_resource_modifier(rsc); 4747ec681f3Smrg return true; 4757ec681f3Smrg default: 4767ec681f3Smrg return false; 4777ec681f3Smrg } 4787ec681f3Smrg} 4797ec681f3Smrg 4807ec681f3Smrg#define PAGE_UB_ROWS (V3D_UIFCFG_PAGE_SIZE / V3D_UIFBLOCK_ROW_SIZE) 48101e04c3fSmrg#define PAGE_UB_ROWS_TIMES_1_5 ((PAGE_UB_ROWS * 3) >> 1) 4827ec681f3Smrg#define PAGE_CACHE_UB_ROWS (V3D_PAGE_CACHE_SIZE / V3D_UIFBLOCK_ROW_SIZE) 48301e04c3fSmrg#define PAGE_CACHE_MINUS_1_5_UB_ROWS (PAGE_CACHE_UB_ROWS - PAGE_UB_ROWS_TIMES_1_5) 48401e04c3fSmrg 48501e04c3fSmrg/** 48601e04c3fSmrg * Computes the HW's UIFblock padding for a given height/cpp. 48701e04c3fSmrg * 48801e04c3fSmrg * The goal of the padding is to keep pages of the same color (bank number) at 48901e04c3fSmrg * least half a page away from each other vertically when crossing between 49001e04c3fSmrg * between columns of UIF blocks. 49101e04c3fSmrg */ 49201e04c3fSmrgstatic uint32_t 49301e04c3fSmrgv3d_get_ub_pad(struct v3d_resource *rsc, uint32_t height) 49401e04c3fSmrg{ 49501e04c3fSmrg uint32_t utile_h = v3d_utile_height(rsc->cpp); 49601e04c3fSmrg uint32_t uif_block_h = utile_h * 2; 49701e04c3fSmrg uint32_t height_ub = height / uif_block_h; 49801e04c3fSmrg 49901e04c3fSmrg uint32_t height_offset_in_pc = height_ub % PAGE_CACHE_UB_ROWS; 50001e04c3fSmrg 50101e04c3fSmrg /* For the perfectly-aligned-for-UIF-XOR case, don't add any pad. */ 50201e04c3fSmrg if (height_offset_in_pc == 0) 50301e04c3fSmrg return 0; 50401e04c3fSmrg 50501e04c3fSmrg /* Try padding up to where we're offset by at least half a page. */ 50601e04c3fSmrg if (height_offset_in_pc < PAGE_UB_ROWS_TIMES_1_5) { 50701e04c3fSmrg /* If we fit entirely in the page cache, don't pad. */ 50801e04c3fSmrg if (height_ub < PAGE_CACHE_UB_ROWS) 50901e04c3fSmrg return 0; 51001e04c3fSmrg else 51101e04c3fSmrg return PAGE_UB_ROWS_TIMES_1_5 - height_offset_in_pc; 51201e04c3fSmrg } 51301e04c3fSmrg 51401e04c3fSmrg /* If we're close to being aligned to page cache size, then round up 51501e04c3fSmrg * and rely on XOR. 51601e04c3fSmrg */ 51701e04c3fSmrg if (height_offset_in_pc > PAGE_CACHE_MINUS_1_5_UB_ROWS) 51801e04c3fSmrg return PAGE_CACHE_UB_ROWS - height_offset_in_pc; 51901e04c3fSmrg 52001e04c3fSmrg /* Otherwise, we're far enough away (top and bottom) to not need any 52101e04c3fSmrg * padding. 52201e04c3fSmrg */ 52301e04c3fSmrg return 0; 52401e04c3fSmrg} 52501e04c3fSmrg 52601e04c3fSmrgstatic void 5279f464c52Smayav3d_setup_slices(struct v3d_resource *rsc, uint32_t winsys_stride, 5289f464c52Smaya bool uif_top) 52901e04c3fSmrg{ 53001e04c3fSmrg struct pipe_resource *prsc = &rsc->base; 53101e04c3fSmrg uint32_t width = prsc->width0; 53201e04c3fSmrg uint32_t height = prsc->height0; 53301e04c3fSmrg uint32_t depth = prsc->depth0; 53401e04c3fSmrg /* Note that power-of-two padding is based on level 1. These are not 53501e04c3fSmrg * equivalent to just util_next_power_of_two(dimension), because at a 53601e04c3fSmrg * level 0 dimension of 9, the level 1 power-of-two padded value is 4, 53701e04c3fSmrg * not 8. 53801e04c3fSmrg */ 53901e04c3fSmrg uint32_t pot_width = 2 * util_next_power_of_two(u_minify(width, 1)); 54001e04c3fSmrg uint32_t pot_height = 2 * util_next_power_of_two(u_minify(height, 1)); 54101e04c3fSmrg uint32_t pot_depth = 2 * util_next_power_of_two(u_minify(depth, 1)); 54201e04c3fSmrg uint32_t offset = 0; 54301e04c3fSmrg uint32_t utile_w = v3d_utile_width(rsc->cpp); 54401e04c3fSmrg uint32_t utile_h = v3d_utile_height(rsc->cpp); 54501e04c3fSmrg uint32_t uif_block_w = utile_w * 2; 54601e04c3fSmrg uint32_t uif_block_h = utile_h * 2; 54701e04c3fSmrg uint32_t block_width = util_format_get_blockwidth(prsc->format); 54801e04c3fSmrg uint32_t block_height = util_format_get_blockheight(prsc->format); 54901e04c3fSmrg bool msaa = prsc->nr_samples > 1; 5509f464c52Smaya 55101e04c3fSmrg /* MSAA textures/renderbuffers are always laid out as single-level 55201e04c3fSmrg * UIF. 55301e04c3fSmrg */ 5549f464c52Smaya uif_top |= msaa; 5559f464c52Smaya 5569f464c52Smaya /* Check some easy mistakes to make in a resource_create() call that 5579f464c52Smaya * will break our setup. 5589f464c52Smaya */ 5599f464c52Smaya assert(prsc->array_size != 0); 5609f464c52Smaya assert(prsc->depth0 != 0); 56101e04c3fSmrg 56201e04c3fSmrg for (int i = prsc->last_level; i >= 0; i--) { 56301e04c3fSmrg struct v3d_resource_slice *slice = &rsc->slices[i]; 56401e04c3fSmrg 56501e04c3fSmrg uint32_t level_width, level_height, level_depth; 56601e04c3fSmrg if (i < 2) { 56701e04c3fSmrg level_width = u_minify(width, i); 56801e04c3fSmrg level_height = u_minify(height, i); 56901e04c3fSmrg } else { 57001e04c3fSmrg level_width = u_minify(pot_width, i); 57101e04c3fSmrg level_height = u_minify(pot_height, i); 57201e04c3fSmrg } 57301e04c3fSmrg if (i < 1) 57401e04c3fSmrg level_depth = u_minify(depth, i); 57501e04c3fSmrg else 57601e04c3fSmrg level_depth = u_minify(pot_depth, i); 57701e04c3fSmrg 57801e04c3fSmrg if (msaa) { 57901e04c3fSmrg level_width *= 2; 58001e04c3fSmrg level_height *= 2; 58101e04c3fSmrg } 58201e04c3fSmrg 58301e04c3fSmrg level_width = DIV_ROUND_UP(level_width, block_width); 58401e04c3fSmrg level_height = DIV_ROUND_UP(level_height, block_height); 58501e04c3fSmrg 58601e04c3fSmrg if (!rsc->tiled) { 5877ec681f3Smrg slice->tiling = V3D_TILING_RASTER; 58801e04c3fSmrg if (prsc->target == PIPE_TEXTURE_1D) 58901e04c3fSmrg level_width = align(level_width, 64 / rsc->cpp); 59001e04c3fSmrg } else { 59101e04c3fSmrg if ((i != 0 || !uif_top) && 59201e04c3fSmrg (level_width <= utile_w || 59301e04c3fSmrg level_height <= utile_h)) { 5947ec681f3Smrg slice->tiling = V3D_TILING_LINEARTILE; 59501e04c3fSmrg level_width = align(level_width, utile_w); 59601e04c3fSmrg level_height = align(level_height, utile_h); 59701e04c3fSmrg } else if ((i != 0 || !uif_top) && 59801e04c3fSmrg level_width <= uif_block_w) { 5997ec681f3Smrg slice->tiling = V3D_TILING_UBLINEAR_1_COLUMN; 60001e04c3fSmrg level_width = align(level_width, uif_block_w); 60101e04c3fSmrg level_height = align(level_height, uif_block_h); 60201e04c3fSmrg } else if ((i != 0 || !uif_top) && 60301e04c3fSmrg level_width <= 2 * uif_block_w) { 6047ec681f3Smrg slice->tiling = V3D_TILING_UBLINEAR_2_COLUMN; 60501e04c3fSmrg level_width = align(level_width, 2 * uif_block_w); 60601e04c3fSmrg level_height = align(level_height, uif_block_h); 60701e04c3fSmrg } else { 60801e04c3fSmrg /* We align the width to a 4-block column of 60901e04c3fSmrg * UIF blocks, but we only align height to UIF 61001e04c3fSmrg * blocks. 61101e04c3fSmrg */ 61201e04c3fSmrg level_width = align(level_width, 61301e04c3fSmrg 4 * uif_block_w); 61401e04c3fSmrg level_height = align(level_height, 61501e04c3fSmrg uif_block_h); 61601e04c3fSmrg 61701e04c3fSmrg slice->ub_pad = v3d_get_ub_pad(rsc, 61801e04c3fSmrg level_height); 61901e04c3fSmrg level_height += slice->ub_pad * uif_block_h; 62001e04c3fSmrg 62101e04c3fSmrg /* If the padding set us to to be aligned to 62201e04c3fSmrg * the page cache size, then the HW will use 62301e04c3fSmrg * the XOR bit on odd columns to get us 62401e04c3fSmrg * perfectly misaligned 62501e04c3fSmrg */ 62601e04c3fSmrg if ((level_height / uif_block_h) % 6277ec681f3Smrg (V3D_PAGE_CACHE_SIZE / 6287ec681f3Smrg V3D_UIFBLOCK_ROW_SIZE) == 0) { 6297ec681f3Smrg slice->tiling = V3D_TILING_UIF_XOR; 63001e04c3fSmrg } else { 6317ec681f3Smrg slice->tiling = V3D_TILING_UIF_NO_XOR; 63201e04c3fSmrg } 63301e04c3fSmrg } 63401e04c3fSmrg } 63501e04c3fSmrg 63601e04c3fSmrg slice->offset = offset; 6379f464c52Smaya if (winsys_stride) 6389f464c52Smaya slice->stride = winsys_stride; 6399f464c52Smaya else 6409f464c52Smaya slice->stride = level_width * rsc->cpp; 64101e04c3fSmrg slice->padded_height = level_height; 64201e04c3fSmrg slice->size = level_height * slice->stride; 64301e04c3fSmrg 64401e04c3fSmrg uint32_t slice_total_size = slice->size * level_depth; 64501e04c3fSmrg 64601e04c3fSmrg /* The HW aligns level 1's base to a page if any of level 1 or 64701e04c3fSmrg * below could be UIF XOR. The lower levels then inherit the 6487ec681f3Smrg * alignment for as long as necessary, thanks to being power of 64901e04c3fSmrg * two aligned. 65001e04c3fSmrg */ 65101e04c3fSmrg if (i == 1 && 65201e04c3fSmrg level_width > 4 * uif_block_w && 65301e04c3fSmrg level_height > PAGE_CACHE_MINUS_1_5_UB_ROWS * uif_block_h) { 65401e04c3fSmrg slice_total_size = align(slice_total_size, 6557ec681f3Smrg V3D_UIFCFG_PAGE_SIZE); 65601e04c3fSmrg } 65701e04c3fSmrg 65801e04c3fSmrg offset += slice_total_size; 65901e04c3fSmrg 66001e04c3fSmrg } 66101e04c3fSmrg rsc->size = offset; 66201e04c3fSmrg 66301e04c3fSmrg /* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only 66401e04c3fSmrg * needs to be aligned to utile boundaries. Since tiles are laid out 66501e04c3fSmrg * from small to big in memory, we need to align the later UIF slices 66601e04c3fSmrg * to UIF blocks, if they were preceded by non-UIF-block-aligned LT 66701e04c3fSmrg * slices. 66801e04c3fSmrg * 66901e04c3fSmrg * We additionally align to 4k, which improves UIF XOR performance. 67001e04c3fSmrg */ 67101e04c3fSmrg uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) - 67201e04c3fSmrg rsc->slices[0].offset); 67301e04c3fSmrg if (page_align_offset) { 67401e04c3fSmrg rsc->size += page_align_offset; 67501e04c3fSmrg for (int i = 0; i <= prsc->last_level; i++) 67601e04c3fSmrg rsc->slices[i].offset += page_align_offset; 67701e04c3fSmrg } 67801e04c3fSmrg 67901e04c3fSmrg /* Arrays and cube textures have a stride which is the distance from 68001e04c3fSmrg * one full mipmap tree to the next (64b aligned). For 3D textures, 68101e04c3fSmrg * we need to program the stride between slices of miplevel 0. 68201e04c3fSmrg */ 68301e04c3fSmrg if (prsc->target != PIPE_TEXTURE_3D) { 68401e04c3fSmrg rsc->cube_map_stride = align(rsc->slices[0].offset + 68501e04c3fSmrg rsc->slices[0].size, 64); 68601e04c3fSmrg rsc->size += rsc->cube_map_stride * (prsc->array_size - 1); 68701e04c3fSmrg } else { 68801e04c3fSmrg rsc->cube_map_stride = rsc->slices[0].size; 68901e04c3fSmrg } 69001e04c3fSmrg} 69101e04c3fSmrg 69201e04c3fSmrguint32_t 69301e04c3fSmrgv3d_layer_offset(struct pipe_resource *prsc, uint32_t level, uint32_t layer) 69401e04c3fSmrg{ 69501e04c3fSmrg struct v3d_resource *rsc = v3d_resource(prsc); 69601e04c3fSmrg struct v3d_resource_slice *slice = &rsc->slices[level]; 69701e04c3fSmrg 69801e04c3fSmrg if (prsc->target == PIPE_TEXTURE_3D) 69901e04c3fSmrg return slice->offset + layer * slice->size; 70001e04c3fSmrg else 70101e04c3fSmrg return slice->offset + layer * rsc->cube_map_stride; 70201e04c3fSmrg} 70301e04c3fSmrg 70401e04c3fSmrgstatic struct v3d_resource * 70501e04c3fSmrgv3d_resource_setup(struct pipe_screen *pscreen, 70601e04c3fSmrg const struct pipe_resource *tmpl) 70701e04c3fSmrg{ 70801e04c3fSmrg struct v3d_screen *screen = v3d_screen(pscreen); 70901e04c3fSmrg struct v3d_resource *rsc = CALLOC_STRUCT(v3d_resource); 71001e04c3fSmrg if (!rsc) 71101e04c3fSmrg return NULL; 71201e04c3fSmrg struct pipe_resource *prsc = &rsc->base; 71301e04c3fSmrg 71401e04c3fSmrg *prsc = *tmpl; 71501e04c3fSmrg 71601e04c3fSmrg pipe_reference_init(&prsc->reference, 1); 71701e04c3fSmrg prsc->screen = pscreen; 71801e04c3fSmrg 71901e04c3fSmrg if (prsc->nr_samples <= 1 || 72001e04c3fSmrg screen->devinfo.ver >= 40 || 72101e04c3fSmrg util_format_is_depth_or_stencil(prsc->format)) { 72201e04c3fSmrg rsc->cpp = util_format_get_blocksize(prsc->format); 72301e04c3fSmrg if (screen->devinfo.ver < 40 && prsc->nr_samples > 1) 72401e04c3fSmrg rsc->cpp *= prsc->nr_samples; 72501e04c3fSmrg } else { 72601e04c3fSmrg assert(v3d_rt_format_supported(&screen->devinfo, prsc->format)); 72701e04c3fSmrg uint32_t output_image_format = 72801e04c3fSmrg v3d_get_rt_format(&screen->devinfo, prsc->format); 72901e04c3fSmrg uint32_t internal_type; 73001e04c3fSmrg uint32_t internal_bpp; 73101e04c3fSmrg v3d_get_internal_type_bpp_for_output_format(&screen->devinfo, 73201e04c3fSmrg output_image_format, 73301e04c3fSmrg &internal_type, 73401e04c3fSmrg &internal_bpp); 73501e04c3fSmrg switch (internal_bpp) { 73601e04c3fSmrg case V3D_INTERNAL_BPP_32: 73701e04c3fSmrg rsc->cpp = 4; 73801e04c3fSmrg break; 73901e04c3fSmrg case V3D_INTERNAL_BPP_64: 74001e04c3fSmrg rsc->cpp = 8; 74101e04c3fSmrg break; 74201e04c3fSmrg case V3D_INTERNAL_BPP_128: 74301e04c3fSmrg rsc->cpp = 16; 74401e04c3fSmrg break; 74501e04c3fSmrg } 74601e04c3fSmrg } 74701e04c3fSmrg 74801e04c3fSmrg assert(rsc->cpp); 74901e04c3fSmrg 75001e04c3fSmrg return rsc; 75101e04c3fSmrg} 75201e04c3fSmrg 75301e04c3fSmrgstatic struct pipe_resource * 75401e04c3fSmrgv3d_resource_create_with_modifiers(struct pipe_screen *pscreen, 75501e04c3fSmrg const struct pipe_resource *tmpl, 75601e04c3fSmrg const uint64_t *modifiers, 75701e04c3fSmrg int count) 75801e04c3fSmrg{ 7599f464c52Smaya struct v3d_screen *screen = v3d_screen(pscreen); 7609f464c52Smaya 7619f464c52Smaya bool linear_ok = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count); 76201e04c3fSmrg struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl); 76301e04c3fSmrg struct pipe_resource *prsc = &rsc->base; 76401e04c3fSmrg /* Use a tiled layout if we can, for better 3D performance. */ 76501e04c3fSmrg bool should_tile = true; 76601e04c3fSmrg 76701e04c3fSmrg /* VBOs/PBOs are untiled (and 1 height). */ 76801e04c3fSmrg if (tmpl->target == PIPE_BUFFER) 76901e04c3fSmrg should_tile = false; 77001e04c3fSmrg 77101e04c3fSmrg /* Cursors are always linear, and the user can request linear as well. 77201e04c3fSmrg */ 77301e04c3fSmrg if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR)) 77401e04c3fSmrg should_tile = false; 77501e04c3fSmrg 77601e04c3fSmrg /* 1D and 1D_ARRAY textures are always raster-order. */ 77701e04c3fSmrg if (tmpl->target == PIPE_TEXTURE_1D || 77801e04c3fSmrg tmpl->target == PIPE_TEXTURE_1D_ARRAY) 77901e04c3fSmrg should_tile = false; 78001e04c3fSmrg 78101e04c3fSmrg /* Scanout BOs for simulator need to be linear for interaction with 78201e04c3fSmrg * i965. 78301e04c3fSmrg */ 78401e04c3fSmrg if (using_v3d_simulator && 78501e04c3fSmrg tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT)) 78601e04c3fSmrg should_tile = false; 78701e04c3fSmrg 7889f464c52Smaya /* If using the old-school SCANOUT flag, we don't know what the screen 7899f464c52Smaya * might support other than linear. Just force linear. 7909f464c52Smaya */ 7919f464c52Smaya if (tmpl->bind & PIPE_BIND_SCANOUT) 7929f464c52Smaya should_tile = false; 7939f464c52Smaya 79401e04c3fSmrg /* No user-specified modifier; determine our own. */ 79501e04c3fSmrg if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) { 79601e04c3fSmrg linear_ok = true; 79701e04c3fSmrg rsc->tiled = should_tile; 79801e04c3fSmrg } else if (should_tile && 7999f464c52Smaya drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_UIF, 80001e04c3fSmrg modifiers, count)) { 80101e04c3fSmrg rsc->tiled = true; 80201e04c3fSmrg } else if (linear_ok) { 80301e04c3fSmrg rsc->tiled = false; 80401e04c3fSmrg } else { 80501e04c3fSmrg fprintf(stderr, "Unsupported modifier requested\n"); 80601e04c3fSmrg goto fail; 80701e04c3fSmrg } 80801e04c3fSmrg 80901e04c3fSmrg rsc->internal_format = prsc->format; 81001e04c3fSmrg 8119f464c52Smaya v3d_setup_slices(rsc, 0, tmpl->bind & PIPE_BIND_SHARED); 8129f464c52Smaya 8139f464c52Smaya /* If we're in a renderonly setup, use the other device to perform our 8149f464c52Smaya * allocation and just import it to v3d. The other device may be 8159f464c52Smaya * using CMA, and V3D can import from CMA but doesn't do CMA 8169f464c52Smaya * allocations on its own. 8179f464c52Smaya * 8189f464c52Smaya * We always allocate this way for SHARED, because get_handle will 8199f464c52Smaya * need a resource on the display fd. 8209f464c52Smaya */ 8219f464c52Smaya if (screen->ro && (tmpl->bind & (PIPE_BIND_SCANOUT | 8229f464c52Smaya PIPE_BIND_SHARED))) { 8239f464c52Smaya struct winsys_handle handle; 8249f464c52Smaya struct pipe_resource scanout_tmpl = { 8259f464c52Smaya .target = prsc->target, 8269f464c52Smaya .format = PIPE_FORMAT_RGBA8888_UNORM, 8279f464c52Smaya .width0 = 1024, /* one page */ 8289f464c52Smaya .height0 = align(rsc->size, 4096) / 4096, 8299f464c52Smaya .depth0 = 1, 8309f464c52Smaya .array_size = 1, 8319f464c52Smaya }; 8329f464c52Smaya 8339f464c52Smaya rsc->scanout = 8349f464c52Smaya renderonly_scanout_for_resource(&scanout_tmpl, 8359f464c52Smaya screen->ro, 8369f464c52Smaya &handle); 8379f464c52Smaya 8389f464c52Smaya if (!rsc->scanout) { 8399f464c52Smaya fprintf(stderr, "Failed to create scanout resource\n"); 8407ec681f3Smrg goto fail; 8419f464c52Smaya } 8429f464c52Smaya assert(handle.type == WINSYS_HANDLE_TYPE_FD); 8439f464c52Smaya rsc->bo = v3d_bo_open_dmabuf(screen, handle.handle); 8449f464c52Smaya close(handle.handle); 8459f464c52Smaya 8469f464c52Smaya if (!rsc->bo) 8479f464c52Smaya goto fail; 8489f464c52Smaya 8499f464c52Smaya v3d_debug_resource_layout(rsc, "renderonly"); 8509f464c52Smaya 8519f464c52Smaya return prsc; 8529f464c52Smaya } else { 8539f464c52Smaya if (!v3d_resource_bo_alloc(rsc)) 8549f464c52Smaya goto fail; 8559f464c52Smaya } 85601e04c3fSmrg 85701e04c3fSmrg return prsc; 85801e04c3fSmrgfail: 85901e04c3fSmrg v3d_resource_destroy(pscreen, prsc); 86001e04c3fSmrg return NULL; 86101e04c3fSmrg} 86201e04c3fSmrg 86301e04c3fSmrgstruct pipe_resource * 86401e04c3fSmrgv3d_resource_create(struct pipe_screen *pscreen, 86501e04c3fSmrg const struct pipe_resource *tmpl) 86601e04c3fSmrg{ 86701e04c3fSmrg const uint64_t mod = DRM_FORMAT_MOD_INVALID; 86801e04c3fSmrg return v3d_resource_create_with_modifiers(pscreen, tmpl, &mod, 1); 86901e04c3fSmrg} 87001e04c3fSmrg 87101e04c3fSmrgstatic struct pipe_resource * 87201e04c3fSmrgv3d_resource_from_handle(struct pipe_screen *pscreen, 87301e04c3fSmrg const struct pipe_resource *tmpl, 87401e04c3fSmrg struct winsys_handle *whandle, 87501e04c3fSmrg unsigned usage) 87601e04c3fSmrg{ 87701e04c3fSmrg struct v3d_screen *screen = v3d_screen(pscreen); 87801e04c3fSmrg struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl); 87901e04c3fSmrg struct pipe_resource *prsc = &rsc->base; 88001e04c3fSmrg struct v3d_resource_slice *slice = &rsc->slices[0]; 88101e04c3fSmrg 88201e04c3fSmrg if (!rsc) 88301e04c3fSmrg return NULL; 88401e04c3fSmrg 88501e04c3fSmrg switch (whandle->modifier) { 88601e04c3fSmrg case DRM_FORMAT_MOD_LINEAR: 88701e04c3fSmrg rsc->tiled = false; 88801e04c3fSmrg break; 88901e04c3fSmrg case DRM_FORMAT_MOD_BROADCOM_UIF: 89001e04c3fSmrg rsc->tiled = true; 89101e04c3fSmrg break; 8929f464c52Smaya case DRM_FORMAT_MOD_INVALID: 8939f464c52Smaya rsc->tiled = screen->ro == NULL; 8949f464c52Smaya break; 89501e04c3fSmrg default: 8967ec681f3Smrg switch(fourcc_mod_broadcom_mod(whandle->modifier)) { 8977ec681f3Smrg case DRM_FORMAT_MOD_BROADCOM_SAND128: 8987ec681f3Smrg rsc->tiled = false; 8997ec681f3Smrg rsc->sand_col128_stride = 9007ec681f3Smrg fourcc_mod_broadcom_param(whandle->modifier); 9017ec681f3Smrg break; 9027ec681f3Smrg default: 9037ec681f3Smrg fprintf(stderr, 9047ec681f3Smrg "Attempt to import unsupported modifier 0x%llx\n", 9057ec681f3Smrg (long long)whandle->modifier); 9067ec681f3Smrg goto fail; 9077ec681f3Smrg } 90801e04c3fSmrg } 90901e04c3fSmrg 91001e04c3fSmrg switch (whandle->type) { 91101e04c3fSmrg case WINSYS_HANDLE_TYPE_SHARED: 9129f464c52Smaya rsc->bo = v3d_bo_open_name(screen, whandle->handle); 91301e04c3fSmrg break; 91401e04c3fSmrg case WINSYS_HANDLE_TYPE_FD: 9159f464c52Smaya rsc->bo = v3d_bo_open_dmabuf(screen, whandle->handle); 91601e04c3fSmrg break; 91701e04c3fSmrg default: 91801e04c3fSmrg fprintf(stderr, 91901e04c3fSmrg "Attempt to import unsupported handle type %d\n", 92001e04c3fSmrg whandle->type); 92101e04c3fSmrg goto fail; 92201e04c3fSmrg } 92301e04c3fSmrg 92401e04c3fSmrg if (!rsc->bo) 92501e04c3fSmrg goto fail; 92601e04c3fSmrg 92701e04c3fSmrg rsc->internal_format = prsc->format; 92801e04c3fSmrg 9299f464c52Smaya v3d_setup_slices(rsc, whandle->stride, true); 93001e04c3fSmrg v3d_debug_resource_layout(rsc, "import"); 93101e04c3fSmrg 9327ec681f3Smrg if (whandle->offset != 0) { 9337ec681f3Smrg if (rsc->tiled) { 9347ec681f3Smrg fprintf(stderr, 9357ec681f3Smrg "Attempt to import unsupported winsys offset %u\n", 9367ec681f3Smrg whandle->offset); 9377ec681f3Smrg goto fail; 9387ec681f3Smrg } 9397ec681f3Smrg rsc->slices[0].offset += whandle->offset; 9407ec681f3Smrg 9417ec681f3Smrg if (rsc->slices[0].offset + rsc->slices[0].size > 9427ec681f3Smrg rsc->bo->size) { 9437ec681f3Smrg fprintf(stderr, "Attempt to import " 9447ec681f3Smrg "with overflowing offset (%d + %d > %d)\n", 9457ec681f3Smrg whandle->offset, 9467ec681f3Smrg rsc->slices[0].size, 9477ec681f3Smrg rsc->bo->size); 9487ec681f3Smrg goto fail; 9497ec681f3Smrg } 9507ec681f3Smrg } 9517ec681f3Smrg 9529f464c52Smaya if (screen->ro) { 9539f464c52Smaya /* Make sure that renderonly has a handle to our buffer in the 9549f464c52Smaya * display's fd, so that a later renderonly_get_handle() 9559f464c52Smaya * returns correct handles or GEM names. 9569f464c52Smaya */ 9579f464c52Smaya rsc->scanout = 9589f464c52Smaya renderonly_create_gpu_import_for_resource(prsc, 9599f464c52Smaya screen->ro, 9609f464c52Smaya NULL); 9619f464c52Smaya } 9629f464c52Smaya 9637ec681f3Smrg if (rsc->tiled && whandle->stride != slice->stride) { 96401e04c3fSmrg static bool warned = false; 96501e04c3fSmrg if (!warned) { 96601e04c3fSmrg warned = true; 96701e04c3fSmrg fprintf(stderr, 96801e04c3fSmrg "Attempting to import %dx%d %s with " 96901e04c3fSmrg "unsupported stride %d instead of %d\n", 97001e04c3fSmrg prsc->width0, prsc->height0, 97101e04c3fSmrg util_format_short_name(prsc->format), 97201e04c3fSmrg whandle->stride, 97301e04c3fSmrg slice->stride); 97401e04c3fSmrg } 97501e04c3fSmrg goto fail; 9767ec681f3Smrg } else if (!rsc->tiled) { 9777ec681f3Smrg slice->stride = whandle->stride; 97801e04c3fSmrg } 97901e04c3fSmrg 98001e04c3fSmrg return prsc; 98101e04c3fSmrg 98201e04c3fSmrgfail: 98301e04c3fSmrg v3d_resource_destroy(pscreen, prsc); 98401e04c3fSmrg return NULL; 98501e04c3fSmrg} 98601e04c3fSmrg 9879f464c52Smayavoid 9889f464c52Smayav3d_update_shadow_texture(struct pipe_context *pctx, 9899f464c52Smaya struct pipe_sampler_view *pview) 9909f464c52Smaya{ 9919f464c52Smaya struct v3d_context *v3d = v3d_context(pctx); 9929f464c52Smaya struct v3d_sampler_view *view = v3d_sampler_view(pview); 9939f464c52Smaya struct v3d_resource *shadow = v3d_resource(view->texture); 9949f464c52Smaya struct v3d_resource *orig = v3d_resource(pview->texture); 9959f464c52Smaya 9969f464c52Smaya assert(view->texture != pview->texture); 9979f464c52Smaya 9989f464c52Smaya if (shadow->writes == orig->writes && orig->bo->private) 9999f464c52Smaya return; 10009f464c52Smaya 10019f464c52Smaya perf_debug("Updating %dx%d@%d shadow for linear texture\n", 10029f464c52Smaya orig->base.width0, orig->base.height0, 10039f464c52Smaya pview->u.tex.first_level); 10049f464c52Smaya 10059f464c52Smaya for (int i = 0; i <= shadow->base.last_level; i++) { 10069f464c52Smaya unsigned width = u_minify(shadow->base.width0, i); 10079f464c52Smaya unsigned height = u_minify(shadow->base.height0, i); 10089f464c52Smaya struct pipe_blit_info info = { 10099f464c52Smaya .dst = { 10109f464c52Smaya .resource = &shadow->base, 10119f464c52Smaya .level = i, 10129f464c52Smaya .box = { 10139f464c52Smaya .x = 0, 10149f464c52Smaya .y = 0, 10159f464c52Smaya .z = 0, 10169f464c52Smaya .width = width, 10179f464c52Smaya .height = height, 10189f464c52Smaya .depth = 1, 10199f464c52Smaya }, 10209f464c52Smaya .format = shadow->base.format, 10219f464c52Smaya }, 10229f464c52Smaya .src = { 10239f464c52Smaya .resource = &orig->base, 10249f464c52Smaya .level = pview->u.tex.first_level + i, 10259f464c52Smaya .box = { 10269f464c52Smaya .x = 0, 10279f464c52Smaya .y = 0, 10289f464c52Smaya .z = 0, 10299f464c52Smaya .width = width, 10309f464c52Smaya .height = height, 10319f464c52Smaya .depth = 1, 10329f464c52Smaya }, 10339f464c52Smaya .format = orig->base.format, 10349f464c52Smaya }, 10359f464c52Smaya .mask = util_format_get_mask(orig->base.format), 10369f464c52Smaya }; 10379f464c52Smaya pctx->blit(pctx, &info); 10389f464c52Smaya } 10399f464c52Smaya 10409f464c52Smaya shadow->writes = orig->writes; 10419f464c52Smaya} 10429f464c52Smaya 104301e04c3fSmrgstatic struct pipe_surface * 104401e04c3fSmrgv3d_create_surface(struct pipe_context *pctx, 104501e04c3fSmrg struct pipe_resource *ptex, 104601e04c3fSmrg const struct pipe_surface *surf_tmpl) 104701e04c3fSmrg{ 104801e04c3fSmrg struct v3d_context *v3d = v3d_context(pctx); 104901e04c3fSmrg struct v3d_screen *screen = v3d->screen; 105001e04c3fSmrg struct v3d_surface *surface = CALLOC_STRUCT(v3d_surface); 105101e04c3fSmrg struct v3d_resource *rsc = v3d_resource(ptex); 105201e04c3fSmrg 105301e04c3fSmrg if (!surface) 105401e04c3fSmrg return NULL; 105501e04c3fSmrg 105601e04c3fSmrg struct pipe_surface *psurf = &surface->base; 105701e04c3fSmrg unsigned level = surf_tmpl->u.tex.level; 105801e04c3fSmrg struct v3d_resource_slice *slice = &rsc->slices[level]; 105901e04c3fSmrg 106001e04c3fSmrg pipe_reference_init(&psurf->reference, 1); 106101e04c3fSmrg pipe_resource_reference(&psurf->texture, ptex); 106201e04c3fSmrg 106301e04c3fSmrg psurf->context = pctx; 106401e04c3fSmrg psurf->format = surf_tmpl->format; 106501e04c3fSmrg psurf->width = u_minify(ptex->width0, level); 106601e04c3fSmrg psurf->height = u_minify(ptex->height0, level); 106701e04c3fSmrg psurf->u.tex.level = level; 106801e04c3fSmrg psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer; 106901e04c3fSmrg psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer; 107001e04c3fSmrg 107101e04c3fSmrg surface->offset = v3d_layer_offset(ptex, level, 107201e04c3fSmrg psurf->u.tex.first_layer); 107301e04c3fSmrg surface->tiling = slice->tiling; 107401e04c3fSmrg 107501e04c3fSmrg surface->format = v3d_get_rt_format(&screen->devinfo, psurf->format); 107601e04c3fSmrg 10779f464c52Smaya const struct util_format_description *desc = 10789f464c52Smaya util_format_description(psurf->format); 10799f464c52Smaya 10809f464c52Smaya surface->swap_rb = (desc->swizzle[0] == PIPE_SWIZZLE_Z && 10819f464c52Smaya psurf->format != PIPE_FORMAT_B5G6R5_UNORM); 10829f464c52Smaya 108301e04c3fSmrg if (util_format_is_depth_or_stencil(psurf->format)) { 108401e04c3fSmrg switch (psurf->format) { 108501e04c3fSmrg case PIPE_FORMAT_Z16_UNORM: 108601e04c3fSmrg surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_16; 108701e04c3fSmrg break; 108801e04c3fSmrg case PIPE_FORMAT_Z32_FLOAT: 108901e04c3fSmrg case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 109001e04c3fSmrg surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_32F; 109101e04c3fSmrg break; 109201e04c3fSmrg default: 109301e04c3fSmrg surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_24; 109401e04c3fSmrg } 109501e04c3fSmrg } else { 109601e04c3fSmrg uint32_t bpp, type; 109701e04c3fSmrg v3d_get_internal_type_bpp_for_output_format(&screen->devinfo, 109801e04c3fSmrg surface->format, 109901e04c3fSmrg &type, &bpp); 110001e04c3fSmrg surface->internal_type = type; 110101e04c3fSmrg surface->internal_bpp = bpp; 110201e04c3fSmrg } 110301e04c3fSmrg 11047ec681f3Smrg if (surface->tiling == V3D_TILING_UIF_NO_XOR || 11057ec681f3Smrg surface->tiling == V3D_TILING_UIF_XOR) { 110601e04c3fSmrg surface->padded_height_of_output_image_in_uif_blocks = 110701e04c3fSmrg (slice->padded_height / 110801e04c3fSmrg (2 * v3d_utile_height(rsc->cpp))); 110901e04c3fSmrg } 111001e04c3fSmrg 111101e04c3fSmrg if (rsc->separate_stencil) { 111201e04c3fSmrg surface->separate_stencil = 111301e04c3fSmrg v3d_create_surface(pctx, &rsc->separate_stencil->base, 111401e04c3fSmrg surf_tmpl); 111501e04c3fSmrg } 111601e04c3fSmrg 111701e04c3fSmrg return &surface->base; 111801e04c3fSmrg} 111901e04c3fSmrg 112001e04c3fSmrgstatic void 112101e04c3fSmrgv3d_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf) 112201e04c3fSmrg{ 112301e04c3fSmrg struct v3d_surface *surf = v3d_surface(psurf); 112401e04c3fSmrg 112501e04c3fSmrg if (surf->separate_stencil) 112601e04c3fSmrg pipe_surface_reference(&surf->separate_stencil, NULL); 112701e04c3fSmrg 112801e04c3fSmrg pipe_resource_reference(&psurf->texture, NULL); 112901e04c3fSmrg FREE(psurf); 113001e04c3fSmrg} 113101e04c3fSmrg 113201e04c3fSmrgstatic void 113301e04c3fSmrgv3d_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource) 113401e04c3fSmrg{ 113501e04c3fSmrg /* All calls to flush_resource are followed by a flush of the context, 113601e04c3fSmrg * so there's nothing to do. 113701e04c3fSmrg */ 113801e04c3fSmrg} 113901e04c3fSmrg 114001e04c3fSmrgstatic enum pipe_format 114101e04c3fSmrgv3d_resource_get_internal_format(struct pipe_resource *prsc) 114201e04c3fSmrg{ 114301e04c3fSmrg return v3d_resource(prsc)->internal_format; 114401e04c3fSmrg} 114501e04c3fSmrg 114601e04c3fSmrgstatic void 114701e04c3fSmrgv3d_resource_set_stencil(struct pipe_resource *prsc, 114801e04c3fSmrg struct pipe_resource *stencil) 114901e04c3fSmrg{ 115001e04c3fSmrg v3d_resource(prsc)->separate_stencil = v3d_resource(stencil); 115101e04c3fSmrg} 115201e04c3fSmrg 115301e04c3fSmrgstatic struct pipe_resource * 115401e04c3fSmrgv3d_resource_get_stencil(struct pipe_resource *prsc) 115501e04c3fSmrg{ 115601e04c3fSmrg struct v3d_resource *rsc = v3d_resource(prsc); 115701e04c3fSmrg 115801e04c3fSmrg return &rsc->separate_stencil->base; 115901e04c3fSmrg} 116001e04c3fSmrg 116101e04c3fSmrgstatic const struct u_transfer_vtbl transfer_vtbl = { 116201e04c3fSmrg .resource_create = v3d_resource_create, 116301e04c3fSmrg .resource_destroy = v3d_resource_destroy, 116401e04c3fSmrg .transfer_map = v3d_resource_transfer_map, 116501e04c3fSmrg .transfer_unmap = v3d_resource_transfer_unmap, 116601e04c3fSmrg .transfer_flush_region = u_default_transfer_flush_region, 116701e04c3fSmrg .get_internal_format = v3d_resource_get_internal_format, 116801e04c3fSmrg .set_stencil = v3d_resource_set_stencil, 116901e04c3fSmrg .get_stencil = v3d_resource_get_stencil, 117001e04c3fSmrg}; 117101e04c3fSmrg 117201e04c3fSmrgvoid 117301e04c3fSmrgv3d_resource_screen_init(struct pipe_screen *pscreen) 117401e04c3fSmrg{ 117501e04c3fSmrg pscreen->resource_create_with_modifiers = 117601e04c3fSmrg v3d_resource_create_with_modifiers; 117701e04c3fSmrg pscreen->resource_create = u_transfer_helper_resource_create; 117801e04c3fSmrg pscreen->resource_from_handle = v3d_resource_from_handle; 117901e04c3fSmrg pscreen->resource_get_handle = v3d_resource_get_handle; 11807ec681f3Smrg pscreen->resource_get_param = v3d_resource_get_param; 118101e04c3fSmrg pscreen->resource_destroy = u_transfer_helper_resource_destroy; 118201e04c3fSmrg pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, 118301e04c3fSmrg true, false, 118401e04c3fSmrg true, true); 118501e04c3fSmrg} 118601e04c3fSmrg 118701e04c3fSmrgvoid 118801e04c3fSmrgv3d_resource_context_init(struct pipe_context *pctx) 118901e04c3fSmrg{ 11907ec681f3Smrg pctx->buffer_map = u_transfer_helper_transfer_map; 11917ec681f3Smrg pctx->texture_map = u_transfer_helper_transfer_map; 119201e04c3fSmrg pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 11937ec681f3Smrg pctx->buffer_unmap = u_transfer_helper_transfer_unmap; 11947ec681f3Smrg pctx->texture_unmap = u_transfer_helper_transfer_unmap; 119501e04c3fSmrg pctx->buffer_subdata = u_default_buffer_subdata; 11969f464c52Smaya pctx->texture_subdata = v3d_texture_subdata; 119701e04c3fSmrg pctx->create_surface = v3d_create_surface; 119801e04c3fSmrg pctx->surface_destroy = v3d_surface_destroy; 119901e04c3fSmrg pctx->resource_copy_region = util_resource_copy_region; 120001e04c3fSmrg pctx->blit = v3d_blit; 12019f464c52Smaya pctx->generate_mipmap = v3d_generate_mipmap; 120201e04c3fSmrg pctx->flush_resource = v3d_flush_resource; 120301e04c3fSmrg} 1204