Path: blob/21.2-virgl/src/gallium/drivers/v3d/v3d_resource.c
4570 views
/*1* Copyright © 2014-2017 Broadcom2* Copyright (C) 2012 Rob Clark <[email protected]>3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING20* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS21* IN THE SOFTWARE.22*/2324#include "pipe/p_defines.h"25#include "util/u_memory.h"26#include "util/format/u_format.h"27#include "util/u_inlines.h"28#include "util/u_surface.h"29#include "util/u_transfer_helper.h"30#include "util/u_upload_mgr.h"31#include "util/format/u_format_zs.h"32#include "util/u_drm.h"3334#include "drm-uapi/drm_fourcc.h"35#include "v3d_screen.h"36#include "v3d_context.h"37#include "v3d_resource.h"38#include "broadcom/cle/v3d_packet_v33_pack.h"3940static void41v3d_debug_resource_layout(struct v3d_resource *rsc, const char *caller)42{43if (!(V3D_DEBUG & V3D_DEBUG_SURFACE))44return;4546struct pipe_resource *prsc = &rsc->base;4748if (prsc->target == PIPE_BUFFER) {49fprintf(stderr,50"rsc %s %p (format %s), %dx%d buffer @0x%08x-0x%08x\n",51caller, rsc,52util_format_short_name(prsc->format),53prsc->width0, prsc->height0,54rsc->bo->offset,55rsc->bo->offset + rsc->bo->size - 1);56return;57}5859static const char *const tiling_descriptions[] = {60[V3D_TILING_RASTER] = "R",61[V3D_TILING_LINEARTILE] = "LT",62[V3D_TILING_UBLINEAR_1_COLUMN] = "UB1",63[V3D_TILING_UBLINEAR_2_COLUMN] = "UB2",64[V3D_TILING_UIF_NO_XOR] = "UIF",65[V3D_TILING_UIF_XOR] = "UIF^",66};6768for (int i = 0; i <= prsc->last_level; i++) {69struct v3d_resource_slice *slice = &rsc->slices[i];7071int level_width = slice->stride / rsc->cpp;72int level_height = slice->padded_height;73int level_depth =74u_minify(util_next_power_of_two(prsc->depth0), i);7576fprintf(stderr,77"rsc %s %p (format %s), %dx%d: "78"level %d (%s) %dx%dx%d -> %dx%dx%d, stride %d@0x%08x\n",79caller, rsc,80util_format_short_name(prsc->format),81prsc->width0, prsc->height0,82i, tiling_descriptions[slice->tiling],83u_minify(prsc->width0, i),84u_minify(prsc->height0, i),85u_minify(prsc->depth0, i),86level_width,87level_height,88level_depth,89slice->stride,90rsc->bo->offset + slice->offset);91}92}9394static bool95v3d_resource_bo_alloc(struct v3d_resource *rsc)96{97struct pipe_resource *prsc = &rsc->base;98struct pipe_screen *pscreen = prsc->screen;99struct v3d_bo *bo;100101bo = v3d_bo_alloc(v3d_screen(pscreen), rsc->size, "resource");102if (bo) {103v3d_bo_unreference(&rsc->bo);104rsc->bo = bo;105v3d_debug_resource_layout(rsc, "alloc");106return true;107} else {108return false;109}110}111112static void113v3d_resource_transfer_unmap(struct pipe_context *pctx,114struct pipe_transfer *ptrans)115{116struct v3d_context *v3d = v3d_context(pctx);117struct v3d_transfer *trans = v3d_transfer(ptrans);118119if (trans->map) {120struct v3d_resource *rsc = v3d_resource(ptrans->resource);121struct v3d_resource_slice *slice = &rsc->slices[ptrans->level];122123if (ptrans->usage & PIPE_MAP_WRITE) {124for (int z = 0; z < ptrans->box.depth; z++) {125void *dst = rsc->bo->map +126v3d_layer_offset(&rsc->base,127ptrans->level,128ptrans->box.z + z);129v3d_store_tiled_image(dst,130slice->stride,131(trans->map +132ptrans->stride *133ptrans->box.height * z),134ptrans->stride,135slice->tiling, rsc->cpp,136slice->padded_height,137&ptrans->box);138}139}140free(trans->map);141}142143pipe_resource_reference(&ptrans->resource, NULL);144slab_free(&v3d->transfer_pool, ptrans);145}146147static void148rebind_sampler_views(struct v3d_context *v3d,149struct v3d_resource *rsc)150{151for (int st = 0; st < PIPE_SHADER_TYPES; st++) {152struct v3d_texture_stateobj *tex = v3d->tex + st;153154for (unsigned i = 0; i < tex->num_textures; i++) {155struct pipe_sampler_view *psview = tex->textures[i];156157if (psview->texture != &rsc->base)158continue;159160struct v3d_sampler_view *sview =161v3d_sampler_view(psview);162163v3d_create_texture_shader_state_bo(v3d, sview);164165v3d_flag_dirty_sampler_state(v3d, st);166}167}168}169170static void171v3d_map_usage_prep(struct pipe_context *pctx,172struct pipe_resource *prsc,173unsigned usage)174{175struct v3d_context *v3d = v3d_context(pctx);176struct v3d_resource *rsc = v3d_resource(prsc);177178if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {179if (v3d_resource_bo_alloc(rsc)) {180/* If it might be bound as one of our vertex buffers181* or UBOs, make sure we re-emit vertex buffer state182* or uniforms.183*/184if (prsc->bind & PIPE_BIND_VERTEX_BUFFER)185v3d->dirty |= V3D_DIRTY_VTXBUF;186if (prsc->bind & PIPE_BIND_CONSTANT_BUFFER)187v3d->dirty |= V3D_DIRTY_CONSTBUF;188if (prsc->bind & PIPE_BIND_SAMPLER_VIEW)189rebind_sampler_views(v3d, rsc);190} else {191/* If we failed to reallocate, flush users so that we192* don't violate any syncing requirements.193*/194v3d_flush_jobs_reading_resource(v3d, prsc,195V3D_FLUSH_DEFAULT,196false);197}198} else if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {199/* If we're writing and the buffer is being used by the CL, we200* have to flush the CL first. If we're only reading, we need201* to flush if the CL has written our buffer.202*/203if (usage & PIPE_MAP_WRITE) {204v3d_flush_jobs_reading_resource(v3d, prsc,205V3D_FLUSH_ALWAYS,206false);207} else {208v3d_flush_jobs_writing_resource(v3d, prsc,209V3D_FLUSH_ALWAYS,210false);211}212}213214if (usage & PIPE_MAP_WRITE) {215rsc->writes++;216rsc->initialized_buffers = ~0;217}218}219220static void *221v3d_resource_transfer_map(struct pipe_context *pctx,222struct pipe_resource *prsc,223unsigned level, unsigned usage,224const struct pipe_box *box,225struct pipe_transfer **pptrans)226{227struct v3d_context *v3d = v3d_context(pctx);228struct v3d_resource *rsc = v3d_resource(prsc);229struct v3d_transfer *trans;230struct pipe_transfer *ptrans;231enum pipe_format format = prsc->format;232char *buf;233234/* MSAA maps should have been handled by u_transfer_helper. */235assert(prsc->nr_samples <= 1);236237/* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is238* being mapped.239*/240if ((usage & PIPE_MAP_DISCARD_RANGE) &&241!(usage & PIPE_MAP_UNSYNCHRONIZED) &&242!(prsc->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) &&243prsc->last_level == 0 &&244prsc->width0 == box->width &&245prsc->height0 == box->height &&246prsc->depth0 == box->depth &&247prsc->array_size == 1 &&248rsc->bo->private) {249usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;250}251252v3d_map_usage_prep(pctx, prsc, usage);253254trans = slab_alloc(&v3d->transfer_pool);255if (!trans)256return NULL;257258/* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */259260/* slab_alloc_st() doesn't zero: */261memset(trans, 0, sizeof(*trans));262ptrans = &trans->base;263264pipe_resource_reference(&ptrans->resource, prsc);265ptrans->level = level;266ptrans->usage = usage;267ptrans->box = *box;268269/* Note that the current kernel implementation is synchronous, so no270* need to do syncing stuff here yet.271*/272273if (usage & PIPE_MAP_UNSYNCHRONIZED)274buf = v3d_bo_map_unsynchronized(rsc->bo);275else276buf = v3d_bo_map(rsc->bo);277if (!buf) {278fprintf(stderr, "Failed to map bo\n");279goto fail;280}281282*pptrans = ptrans;283284/* Our load/store routines work on entire compressed blocks. */285ptrans->box.x /= util_format_get_blockwidth(format);286ptrans->box.y /= util_format_get_blockheight(format);287ptrans->box.width = DIV_ROUND_UP(ptrans->box.width,288util_format_get_blockwidth(format));289ptrans->box.height = DIV_ROUND_UP(ptrans->box.height,290util_format_get_blockheight(format));291292struct v3d_resource_slice *slice = &rsc->slices[level];293if (rsc->tiled) {294/* No direct mappings of tiled, since we need to manually295* tile/untile.296*/297if (usage & PIPE_MAP_DIRECTLY)298return NULL;299300ptrans->stride = ptrans->box.width * rsc->cpp;301ptrans->layer_stride = ptrans->stride * ptrans->box.height;302303trans->map = malloc(ptrans->layer_stride * ptrans->box.depth);304305if (usage & PIPE_MAP_READ) {306for (int z = 0; z < ptrans->box.depth; z++) {307void *src = rsc->bo->map +308v3d_layer_offset(&rsc->base,309ptrans->level,310ptrans->box.z + z);311v3d_load_tiled_image((trans->map +312ptrans->stride *313ptrans->box.height * z),314ptrans->stride,315src,316slice->stride,317slice->tiling, rsc->cpp,318slice->padded_height,319&ptrans->box);320}321}322return trans->map;323} else {324ptrans->stride = slice->stride;325ptrans->layer_stride = rsc->cube_map_stride;326327return buf + slice->offset +328ptrans->box.y * ptrans->stride +329ptrans->box.x * rsc->cpp +330ptrans->box.z * rsc->cube_map_stride;331}332333334fail:335v3d_resource_transfer_unmap(pctx, ptrans);336return NULL;337}338339static void340v3d_texture_subdata(struct pipe_context *pctx,341struct pipe_resource *prsc,342unsigned level,343unsigned usage,344const struct pipe_box *box,345const void *data,346unsigned stride,347unsigned layer_stride)348{349struct v3d_resource *rsc = v3d_resource(prsc);350struct v3d_resource_slice *slice = &rsc->slices[level];351352/* For a direct mapping, we can just take the u_transfer path. */353if (!rsc->tiled) {354return u_default_texture_subdata(pctx, prsc, level, usage, box,355data, stride, layer_stride);356}357358/* Otherwise, map and store the texture data directly into the tiled359* texture. Note that gallium's texture_subdata may be called with360* obvious usage flags missing!361*/362v3d_map_usage_prep(pctx, prsc, usage | (PIPE_MAP_WRITE |363PIPE_MAP_DISCARD_RANGE));364365void *buf;366if (usage & PIPE_MAP_UNSYNCHRONIZED)367buf = v3d_bo_map_unsynchronized(rsc->bo);368else369buf = v3d_bo_map(rsc->bo);370371for (int i = 0; i < box->depth; i++) {372v3d_store_tiled_image(buf +373v3d_layer_offset(&rsc->base,374level,375box->z + i),376slice->stride,377(void *)data + layer_stride * i,378stride,379slice->tiling, rsc->cpp, slice->padded_height,380box);381}382}383384static void385v3d_resource_destroy(struct pipe_screen *pscreen,386struct pipe_resource *prsc)387{388struct v3d_screen *screen = v3d_screen(pscreen);389struct v3d_resource *rsc = v3d_resource(prsc);390391if (rsc->scanout)392renderonly_scanout_destroy(rsc->scanout, screen->ro);393394v3d_bo_unreference(&rsc->bo);395free(rsc);396}397398static bool399v3d_resource_get_handle(struct pipe_screen *pscreen,400struct pipe_context *pctx,401struct pipe_resource *prsc,402struct winsys_handle *whandle,403unsigned usage)404{405struct v3d_screen *screen = v3d_screen(pscreen);406struct v3d_resource *rsc = v3d_resource(prsc);407struct v3d_bo *bo = rsc->bo;408409whandle->stride = rsc->slices[0].stride;410whandle->offset = 0;411412/* If we're passing some reference to our BO out to some other part of413* the system, then we can't do any optimizations about only us being414* the ones seeing it (like BO caching).415*/416bo->private = false;417418if (rsc->tiled) {419/* A shared tiled buffer should always be allocated as UIF,420* not UBLINEAR or LT.421*/422assert(rsc->slices[0].tiling == V3D_TILING_UIF_XOR ||423rsc->slices[0].tiling == V3D_TILING_UIF_NO_XOR);424whandle->modifier = DRM_FORMAT_MOD_BROADCOM_UIF;425} else {426whandle->modifier = DRM_FORMAT_MOD_LINEAR;427}428429switch (whandle->type) {430case WINSYS_HANDLE_TYPE_SHARED:431return v3d_bo_flink(bo, &whandle->handle);432case WINSYS_HANDLE_TYPE_KMS:433if (screen->ro) {434if (renderonly_get_handle(rsc->scanout, whandle)) {435whandle->stride = rsc->slices[0].stride;436return true;437}438return false;439}440whandle->handle = bo->handle;441return true;442case WINSYS_HANDLE_TYPE_FD:443whandle->handle = v3d_bo_get_dmabuf(bo);444return whandle->handle != -1;445}446447return false;448}449450#define PAGE_UB_ROWS (V3D_UIFCFG_PAGE_SIZE / V3D_UIFBLOCK_ROW_SIZE)451#define PAGE_UB_ROWS_TIMES_1_5 ((PAGE_UB_ROWS * 3) >> 1)452#define PAGE_CACHE_UB_ROWS (V3D_PAGE_CACHE_SIZE / V3D_UIFBLOCK_ROW_SIZE)453#define PAGE_CACHE_MINUS_1_5_UB_ROWS (PAGE_CACHE_UB_ROWS - PAGE_UB_ROWS_TIMES_1_5)454455/**456* Computes the HW's UIFblock padding for a given height/cpp.457*458* The goal of the padding is to keep pages of the same color (bank number) at459* least half a page away from each other vertically when crossing between460* between columns of UIF blocks.461*/462static uint32_t463v3d_get_ub_pad(struct v3d_resource *rsc, uint32_t height)464{465uint32_t utile_h = v3d_utile_height(rsc->cpp);466uint32_t uif_block_h = utile_h * 2;467uint32_t height_ub = height / uif_block_h;468469uint32_t height_offset_in_pc = height_ub % PAGE_CACHE_UB_ROWS;470471/* For the perfectly-aligned-for-UIF-XOR case, don't add any pad. */472if (height_offset_in_pc == 0)473return 0;474475/* Try padding up to where we're offset by at least half a page. */476if (height_offset_in_pc < PAGE_UB_ROWS_TIMES_1_5) {477/* If we fit entirely in the page cache, don't pad. */478if (height_ub < PAGE_CACHE_UB_ROWS)479return 0;480else481return PAGE_UB_ROWS_TIMES_1_5 - height_offset_in_pc;482}483484/* If we're close to being aligned to page cache size, then round up485* and rely on XOR.486*/487if (height_offset_in_pc > PAGE_CACHE_MINUS_1_5_UB_ROWS)488return PAGE_CACHE_UB_ROWS - height_offset_in_pc;489490/* Otherwise, we're far enough away (top and bottom) to not need any491* padding.492*/493return 0;494}495496static void497v3d_setup_slices(struct v3d_resource *rsc, uint32_t winsys_stride,498bool uif_top)499{500struct pipe_resource *prsc = &rsc->base;501uint32_t width = prsc->width0;502uint32_t height = prsc->height0;503uint32_t depth = prsc->depth0;504/* Note that power-of-two padding is based on level 1. These are not505* equivalent to just util_next_power_of_two(dimension), because at a506* level 0 dimension of 9, the level 1 power-of-two padded value is 4,507* not 8.508*/509uint32_t pot_width = 2 * util_next_power_of_two(u_minify(width, 1));510uint32_t pot_height = 2 * util_next_power_of_two(u_minify(height, 1));511uint32_t pot_depth = 2 * util_next_power_of_two(u_minify(depth, 1));512uint32_t offset = 0;513uint32_t utile_w = v3d_utile_width(rsc->cpp);514uint32_t utile_h = v3d_utile_height(rsc->cpp);515uint32_t uif_block_w = utile_w * 2;516uint32_t uif_block_h = utile_h * 2;517uint32_t block_width = util_format_get_blockwidth(prsc->format);518uint32_t block_height = util_format_get_blockheight(prsc->format);519bool msaa = prsc->nr_samples > 1;520521/* MSAA textures/renderbuffers are always laid out as single-level522* UIF.523*/524uif_top |= msaa;525526/* Check some easy mistakes to make in a resource_create() call that527* will break our setup.528*/529assert(prsc->array_size != 0);530assert(prsc->depth0 != 0);531532for (int i = prsc->last_level; i >= 0; i--) {533struct v3d_resource_slice *slice = &rsc->slices[i];534535uint32_t level_width, level_height, level_depth;536if (i < 2) {537level_width = u_minify(width, i);538level_height = u_minify(height, i);539} else {540level_width = u_minify(pot_width, i);541level_height = u_minify(pot_height, i);542}543if (i < 1)544level_depth = u_minify(depth, i);545else546level_depth = u_minify(pot_depth, i);547548if (msaa) {549level_width *= 2;550level_height *= 2;551}552553level_width = DIV_ROUND_UP(level_width, block_width);554level_height = DIV_ROUND_UP(level_height, block_height);555556if (!rsc->tiled) {557slice->tiling = V3D_TILING_RASTER;558if (prsc->target == PIPE_TEXTURE_1D)559level_width = align(level_width, 64 / rsc->cpp);560} else {561if ((i != 0 || !uif_top) &&562(level_width <= utile_w ||563level_height <= utile_h)) {564slice->tiling = V3D_TILING_LINEARTILE;565level_width = align(level_width, utile_w);566level_height = align(level_height, utile_h);567} else if ((i != 0 || !uif_top) &&568level_width <= uif_block_w) {569slice->tiling = V3D_TILING_UBLINEAR_1_COLUMN;570level_width = align(level_width, uif_block_w);571level_height = align(level_height, uif_block_h);572} else if ((i != 0 || !uif_top) &&573level_width <= 2 * uif_block_w) {574slice->tiling = V3D_TILING_UBLINEAR_2_COLUMN;575level_width = align(level_width, 2 * uif_block_w);576level_height = align(level_height, uif_block_h);577} else {578/* We align the width to a 4-block column of579* UIF blocks, but we only align height to UIF580* blocks.581*/582level_width = align(level_width,5834 * uif_block_w);584level_height = align(level_height,585uif_block_h);586587slice->ub_pad = v3d_get_ub_pad(rsc,588level_height);589level_height += slice->ub_pad * uif_block_h;590591/* If the padding set us to to be aligned to592* the page cache size, then the HW will use593* the XOR bit on odd columns to get us594* perfectly misaligned595*/596if ((level_height / uif_block_h) %597(V3D_PAGE_CACHE_SIZE /598V3D_UIFBLOCK_ROW_SIZE) == 0) {599slice->tiling = V3D_TILING_UIF_XOR;600} else {601slice->tiling = V3D_TILING_UIF_NO_XOR;602}603}604}605606slice->offset = offset;607if (winsys_stride)608slice->stride = winsys_stride;609else610slice->stride = level_width * rsc->cpp;611slice->padded_height = level_height;612slice->size = level_height * slice->stride;613614uint32_t slice_total_size = slice->size * level_depth;615616/* The HW aligns level 1's base to a page if any of level 1 or617* below could be UIF XOR. The lower levels then inherit the618* alignment for as long as necessary, thanks to being power of619* two aligned.620*/621if (i == 1 &&622level_width > 4 * uif_block_w &&623level_height > PAGE_CACHE_MINUS_1_5_UB_ROWS * uif_block_h) {624slice_total_size = align(slice_total_size,625V3D_UIFCFG_PAGE_SIZE);626}627628offset += slice_total_size;629630}631rsc->size = offset;632633/* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only634* needs to be aligned to utile boundaries. Since tiles are laid out635* from small to big in memory, we need to align the later UIF slices636* to UIF blocks, if they were preceded by non-UIF-block-aligned LT637* slices.638*639* We additionally align to 4k, which improves UIF XOR performance.640*/641uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -642rsc->slices[0].offset);643if (page_align_offset) {644rsc->size += page_align_offset;645for (int i = 0; i <= prsc->last_level; i++)646rsc->slices[i].offset += page_align_offset;647}648649/* Arrays and cube textures have a stride which is the distance from650* one full mipmap tree to the next (64b aligned). For 3D textures,651* we need to program the stride between slices of miplevel 0.652*/653if (prsc->target != PIPE_TEXTURE_3D) {654rsc->cube_map_stride = align(rsc->slices[0].offset +655rsc->slices[0].size, 64);656rsc->size += rsc->cube_map_stride * (prsc->array_size - 1);657} else {658rsc->cube_map_stride = rsc->slices[0].size;659}660}661662uint32_t663v3d_layer_offset(struct pipe_resource *prsc, uint32_t level, uint32_t layer)664{665struct v3d_resource *rsc = v3d_resource(prsc);666struct v3d_resource_slice *slice = &rsc->slices[level];667668if (prsc->target == PIPE_TEXTURE_3D)669return slice->offset + layer * slice->size;670else671return slice->offset + layer * rsc->cube_map_stride;672}673674static struct v3d_resource *675v3d_resource_setup(struct pipe_screen *pscreen,676const struct pipe_resource *tmpl)677{678struct v3d_screen *screen = v3d_screen(pscreen);679struct v3d_resource *rsc = CALLOC_STRUCT(v3d_resource);680if (!rsc)681return NULL;682struct pipe_resource *prsc = &rsc->base;683684*prsc = *tmpl;685686pipe_reference_init(&prsc->reference, 1);687prsc->screen = pscreen;688689if (prsc->nr_samples <= 1 ||690screen->devinfo.ver >= 40 ||691util_format_is_depth_or_stencil(prsc->format)) {692rsc->cpp = util_format_get_blocksize(prsc->format);693if (screen->devinfo.ver < 40 && prsc->nr_samples > 1)694rsc->cpp *= prsc->nr_samples;695} else {696assert(v3d_rt_format_supported(&screen->devinfo, prsc->format));697uint32_t output_image_format =698v3d_get_rt_format(&screen->devinfo, prsc->format);699uint32_t internal_type;700uint32_t internal_bpp;701v3d_get_internal_type_bpp_for_output_format(&screen->devinfo,702output_image_format,703&internal_type,704&internal_bpp);705switch (internal_bpp) {706case V3D_INTERNAL_BPP_32:707rsc->cpp = 4;708break;709case V3D_INTERNAL_BPP_64:710rsc->cpp = 8;711break;712case V3D_INTERNAL_BPP_128:713rsc->cpp = 16;714break;715}716}717718assert(rsc->cpp);719720return rsc;721}722723static struct pipe_resource *724v3d_resource_create_with_modifiers(struct pipe_screen *pscreen,725const struct pipe_resource *tmpl,726const uint64_t *modifiers,727int count)728{729struct v3d_screen *screen = v3d_screen(pscreen);730731bool linear_ok = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);732struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl);733struct pipe_resource *prsc = &rsc->base;734/* Use a tiled layout if we can, for better 3D performance. */735bool should_tile = true;736737/* VBOs/PBOs are untiled (and 1 height). */738if (tmpl->target == PIPE_BUFFER)739should_tile = false;740741/* Cursors are always linear, and the user can request linear as well.742*/743if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))744should_tile = false;745746/* 1D and 1D_ARRAY textures are always raster-order. */747if (tmpl->target == PIPE_TEXTURE_1D ||748tmpl->target == PIPE_TEXTURE_1D_ARRAY)749should_tile = false;750751/* Scanout BOs for simulator need to be linear for interaction with752* i965.753*/754if (using_v3d_simulator &&755tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT))756should_tile = false;757758/* If using the old-school SCANOUT flag, we don't know what the screen759* might support other than linear. Just force linear.760*/761if (tmpl->bind & PIPE_BIND_SCANOUT)762should_tile = false;763764/* No user-specified modifier; determine our own. */765if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {766linear_ok = true;767rsc->tiled = should_tile;768} else if (should_tile &&769drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_UIF,770modifiers, count)) {771rsc->tiled = true;772} else if (linear_ok) {773rsc->tiled = false;774} else {775fprintf(stderr, "Unsupported modifier requested\n");776goto fail;777}778779rsc->internal_format = prsc->format;780781v3d_setup_slices(rsc, 0, tmpl->bind & PIPE_BIND_SHARED);782783/* If we're in a renderonly setup, use the other device to perform our784* allocation and just import it to v3d. The other device may be785* using CMA, and V3D can import from CMA but doesn't do CMA786* allocations on its own.787*788* We always allocate this way for SHARED, because get_handle will789* need a resource on the display fd.790*/791if (screen->ro && (tmpl->bind & (PIPE_BIND_SCANOUT |792PIPE_BIND_SHARED))) {793struct winsys_handle handle;794struct pipe_resource scanout_tmpl = {795.target = prsc->target,796.format = PIPE_FORMAT_RGBA8888_UNORM,797.width0 = 1024, /* one page */798.height0 = align(rsc->size, 4096) / 4096,799.depth0 = 1,800.array_size = 1,801};802803rsc->scanout =804renderonly_scanout_for_resource(&scanout_tmpl,805screen->ro,806&handle);807808if (!rsc->scanout) {809fprintf(stderr, "Failed to create scanout resource\n");810goto fail;811}812assert(handle.type == WINSYS_HANDLE_TYPE_FD);813rsc->bo = v3d_bo_open_dmabuf(screen, handle.handle);814close(handle.handle);815816if (!rsc->bo)817goto fail;818819v3d_debug_resource_layout(rsc, "renderonly");820821return prsc;822} else {823if (!v3d_resource_bo_alloc(rsc))824goto fail;825}826827return prsc;828fail:829v3d_resource_destroy(pscreen, prsc);830return NULL;831}832833struct pipe_resource *834v3d_resource_create(struct pipe_screen *pscreen,835const struct pipe_resource *tmpl)836{837const uint64_t mod = DRM_FORMAT_MOD_INVALID;838return v3d_resource_create_with_modifiers(pscreen, tmpl, &mod, 1);839}840841static struct pipe_resource *842v3d_resource_from_handle(struct pipe_screen *pscreen,843const struct pipe_resource *tmpl,844struct winsys_handle *whandle,845unsigned usage)846{847struct v3d_screen *screen = v3d_screen(pscreen);848struct v3d_resource *rsc = v3d_resource_setup(pscreen, tmpl);849struct pipe_resource *prsc = &rsc->base;850struct v3d_resource_slice *slice = &rsc->slices[0];851852if (!rsc)853return NULL;854855switch (whandle->modifier) {856case DRM_FORMAT_MOD_LINEAR:857rsc->tiled = false;858break;859case DRM_FORMAT_MOD_BROADCOM_UIF:860rsc->tiled = true;861break;862case DRM_FORMAT_MOD_INVALID:863rsc->tiled = screen->ro == NULL;864break;865default:866switch(fourcc_mod_broadcom_mod(whandle->modifier)) {867case DRM_FORMAT_MOD_BROADCOM_SAND128:868rsc->tiled = false;869rsc->sand_col128_stride =870fourcc_mod_broadcom_param(whandle->modifier);871break;872default:873fprintf(stderr,874"Attempt to import unsupported modifier 0x%llx\n",875(long long)whandle->modifier);876goto fail;877}878}879880switch (whandle->type) {881case WINSYS_HANDLE_TYPE_SHARED:882rsc->bo = v3d_bo_open_name(screen, whandle->handle);883break;884case WINSYS_HANDLE_TYPE_FD:885rsc->bo = v3d_bo_open_dmabuf(screen, whandle->handle);886break;887default:888fprintf(stderr,889"Attempt to import unsupported handle type %d\n",890whandle->type);891goto fail;892}893894if (!rsc->bo)895goto fail;896897rsc->internal_format = prsc->format;898899v3d_setup_slices(rsc, whandle->stride, true);900v3d_debug_resource_layout(rsc, "import");901902if (whandle->offset != 0) {903if (rsc->tiled) {904fprintf(stderr,905"Attempt to import unsupported winsys offset %u\n",906whandle->offset);907goto fail;908}909rsc->slices[0].offset += whandle->offset;910911if (rsc->slices[0].offset + rsc->slices[0].size >912rsc->bo->size) {913fprintf(stderr, "Attempt to import "914"with overflowing offset (%d + %d > %d)\n",915whandle->offset,916rsc->slices[0].size,917rsc->bo->size);918goto fail;919}920}921922if (screen->ro) {923/* Make sure that renderonly has a handle to our buffer in the924* display's fd, so that a later renderonly_get_handle()925* returns correct handles or GEM names.926*/927rsc->scanout =928renderonly_create_gpu_import_for_resource(prsc,929screen->ro,930NULL);931}932933if (rsc->tiled && whandle->stride != slice->stride) {934static bool warned = false;935if (!warned) {936warned = true;937fprintf(stderr,938"Attempting to import %dx%d %s with "939"unsupported stride %d instead of %d\n",940prsc->width0, prsc->height0,941util_format_short_name(prsc->format),942whandle->stride,943slice->stride);944}945goto fail;946} else if (!rsc->tiled) {947slice->stride = whandle->stride;948}949950return prsc;951952fail:953v3d_resource_destroy(pscreen, prsc);954return NULL;955}956957void958v3d_update_shadow_texture(struct pipe_context *pctx,959struct pipe_sampler_view *pview)960{961struct v3d_context *v3d = v3d_context(pctx);962struct v3d_sampler_view *view = v3d_sampler_view(pview);963struct v3d_resource *shadow = v3d_resource(view->texture);964struct v3d_resource *orig = v3d_resource(pview->texture);965966assert(view->texture != pview->texture);967968if (shadow->writes == orig->writes && orig->bo->private)969return;970971perf_debug("Updating %dx%d@%d shadow for linear texture\n",972orig->base.width0, orig->base.height0,973pview->u.tex.first_level);974975for (int i = 0; i <= shadow->base.last_level; i++) {976unsigned width = u_minify(shadow->base.width0, i);977unsigned height = u_minify(shadow->base.height0, i);978struct pipe_blit_info info = {979.dst = {980.resource = &shadow->base,981.level = i,982.box = {983.x = 0,984.y = 0,985.z = 0,986.width = width,987.height = height,988.depth = 1,989},990.format = shadow->base.format,991},992.src = {993.resource = &orig->base,994.level = pview->u.tex.first_level + i,995.box = {996.x = 0,997.y = 0,998.z = 0,999.width = width,1000.height = height,1001.depth = 1,1002},1003.format = orig->base.format,1004},1005.mask = util_format_get_mask(orig->base.format),1006};1007pctx->blit(pctx, &info);1008}10091010shadow->writes = orig->writes;1011}10121013static struct pipe_surface *1014v3d_create_surface(struct pipe_context *pctx,1015struct pipe_resource *ptex,1016const struct pipe_surface *surf_tmpl)1017{1018struct v3d_context *v3d = v3d_context(pctx);1019struct v3d_screen *screen = v3d->screen;1020struct v3d_surface *surface = CALLOC_STRUCT(v3d_surface);1021struct v3d_resource *rsc = v3d_resource(ptex);10221023if (!surface)1024return NULL;10251026struct pipe_surface *psurf = &surface->base;1027unsigned level = surf_tmpl->u.tex.level;1028struct v3d_resource_slice *slice = &rsc->slices[level];10291030pipe_reference_init(&psurf->reference, 1);1031pipe_resource_reference(&psurf->texture, ptex);10321033psurf->context = pctx;1034psurf->format = surf_tmpl->format;1035psurf->width = u_minify(ptex->width0, level);1036psurf->height = u_minify(ptex->height0, level);1037psurf->u.tex.level = level;1038psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;1039psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;10401041surface->offset = v3d_layer_offset(ptex, level,1042psurf->u.tex.first_layer);1043surface->tiling = slice->tiling;10441045surface->format = v3d_get_rt_format(&screen->devinfo, psurf->format);10461047const struct util_format_description *desc =1048util_format_description(psurf->format);10491050surface->swap_rb = (desc->swizzle[0] == PIPE_SWIZZLE_Z &&1051psurf->format != PIPE_FORMAT_B5G6R5_UNORM);10521053if (util_format_is_depth_or_stencil(psurf->format)) {1054switch (psurf->format) {1055case PIPE_FORMAT_Z16_UNORM:1056surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_16;1057break;1058case PIPE_FORMAT_Z32_FLOAT:1059case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:1060surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_32F;1061break;1062default:1063surface->internal_type = V3D_INTERNAL_TYPE_DEPTH_24;1064}1065} else {1066uint32_t bpp, type;1067v3d_get_internal_type_bpp_for_output_format(&screen->devinfo,1068surface->format,1069&type, &bpp);1070surface->internal_type = type;1071surface->internal_bpp = bpp;1072}10731074if (surface->tiling == V3D_TILING_UIF_NO_XOR ||1075surface->tiling == V3D_TILING_UIF_XOR) {1076surface->padded_height_of_output_image_in_uif_blocks =1077(slice->padded_height /1078(2 * v3d_utile_height(rsc->cpp)));1079}10801081if (rsc->separate_stencil) {1082surface->separate_stencil =1083v3d_create_surface(pctx, &rsc->separate_stencil->base,1084surf_tmpl);1085}10861087return &surface->base;1088}10891090static void1091v3d_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)1092{1093struct v3d_surface *surf = v3d_surface(psurf);10941095if (surf->separate_stencil)1096pipe_surface_reference(&surf->separate_stencil, NULL);10971098pipe_resource_reference(&psurf->texture, NULL);1099FREE(psurf);1100}11011102static void1103v3d_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)1104{1105/* All calls to flush_resource are followed by a flush of the context,1106* so there's nothing to do.1107*/1108}11091110static enum pipe_format1111v3d_resource_get_internal_format(struct pipe_resource *prsc)1112{1113return v3d_resource(prsc)->internal_format;1114}11151116static void1117v3d_resource_set_stencil(struct pipe_resource *prsc,1118struct pipe_resource *stencil)1119{1120v3d_resource(prsc)->separate_stencil = v3d_resource(stencil);1121}11221123static struct pipe_resource *1124v3d_resource_get_stencil(struct pipe_resource *prsc)1125{1126struct v3d_resource *rsc = v3d_resource(prsc);11271128return &rsc->separate_stencil->base;1129}11301131static const struct u_transfer_vtbl transfer_vtbl = {1132.resource_create = v3d_resource_create,1133.resource_destroy = v3d_resource_destroy,1134.transfer_map = v3d_resource_transfer_map,1135.transfer_unmap = v3d_resource_transfer_unmap,1136.transfer_flush_region = u_default_transfer_flush_region,1137.get_internal_format = v3d_resource_get_internal_format,1138.set_stencil = v3d_resource_set_stencil,1139.get_stencil = v3d_resource_get_stencil,1140};11411142void1143v3d_resource_screen_init(struct pipe_screen *pscreen)1144{1145pscreen->resource_create_with_modifiers =1146v3d_resource_create_with_modifiers;1147pscreen->resource_create = u_transfer_helper_resource_create;1148pscreen->resource_from_handle = v3d_resource_from_handle;1149pscreen->resource_get_handle = v3d_resource_get_handle;1150pscreen->resource_destroy = u_transfer_helper_resource_destroy;1151pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl,1152true, false,1153true, true);1154}11551156void1157v3d_resource_context_init(struct pipe_context *pctx)1158{1159pctx->buffer_map = u_transfer_helper_transfer_map;1160pctx->texture_map = u_transfer_helper_transfer_map;1161pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;1162pctx->buffer_unmap = u_transfer_helper_transfer_unmap;1163pctx->texture_unmap = u_transfer_helper_transfer_unmap;1164pctx->buffer_subdata = u_default_buffer_subdata;1165pctx->texture_subdata = v3d_texture_subdata;1166pctx->create_surface = v3d_create_surface;1167pctx->surface_destroy = v3d_surface_destroy;1168pctx->resource_copy_region = util_resource_copy_region;1169pctx->blit = v3d_blit;1170pctx->generate_mipmap = v3d_generate_mipmap;1171pctx->flush_resource = v3d_flush_resource;1172}117311741175