Path: blob/21.2-virgl/src/gallium/drivers/freedreno/freedreno_resource.c
4570 views
/*1* Copyright (C) 2012 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include "util/format/u_format.h"27#include "util/format/u_format_rgtc.h"28#include "util/format/u_format_zs.h"29#include "util/set.h"30#include "util/u_drm.h"31#include "util/u_inlines.h"32#include "util/u_string.h"33#include "util/u_surface.h"34#include "util/u_transfer.h"3536#include "decode/util.h"3738#include "freedreno_batch_cache.h"39#include "freedreno_blitter.h"40#include "freedreno_context.h"41#include "freedreno_fence.h"42#include "freedreno_query_hw.h"43#include "freedreno_resource.h"44#include "freedreno_screen.h"45#include "freedreno_surface.h"46#include "freedreno_util.h"4748#include <errno.h>49#include "drm-uapi/drm_fourcc.h"5051/* XXX this should go away, needed for 'struct winsys_handle' */52#include "frontend/drm_driver.h"5354/* A private modifier for now, so we have a way to request tiled but not55* compressed. It would perhaps be good to get real modifiers for the56* tiled formats, but would probably need to do some work to figure out57* the layout(s) of the tiled modes, and whether they are the same58* across generations.59*/60#define FD_FORMAT_MOD_QCOM_TILED fourcc_mod_code(QCOM, 0xffffffff)6162/**63* Go through the entire state and see if the resource is bound64* anywhere. If it is, mark the relevant state as dirty. This is65* called on realloc_bo to ensure the necessary state is re-66* emitted so the GPU looks at the new backing bo.67*/68static void69rebind_resource_in_ctx(struct fd_context *ctx,70struct fd_resource *rsc) assert_dt71{72struct pipe_resource *prsc = &rsc->b.b;7374if (ctx->rebind_resource)75ctx->rebind_resource(ctx, rsc);7677/* VBOs */78if (rsc->dirty & FD_DIRTY_VTXBUF) {79struct fd_vertexbuf_stateobj *vb = &ctx->vtx.vertexbuf;80for (unsigned i = 0; i < vb->count && !(ctx->dirty & FD_DIRTY_VTXBUF);81i++) {82if (vb->vb[i].buffer.resource == prsc)83fd_context_dirty(ctx, FD_DIRTY_VTXBUF);84}85}8687const enum fd_dirty_3d_state per_stage_dirty =88FD_DIRTY_CONST | FD_DIRTY_TEX | FD_DIRTY_IMAGE | FD_DIRTY_SSBO;8990if (!(rsc->dirty & per_stage_dirty))91return;9293/* per-shader-stage resources: */94for (unsigned stage = 0; stage < PIPE_SHADER_TYPES; stage++) {95/* Constbufs.. note that constbuf[0] is normal uniforms emitted in96* cmdstream rather than by pointer..97*/98if ((rsc->dirty & FD_DIRTY_CONST) &&99!(ctx->dirty_shader[stage] & FD_DIRTY_CONST)) {100struct fd_constbuf_stateobj *cb = &ctx->constbuf[stage];101const unsigned num_ubos = util_last_bit(cb->enabled_mask);102for (unsigned i = 1; i < num_ubos; i++) {103if (cb->cb[i].buffer == prsc) {104fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_CONST);105break;106}107}108}109110/* Textures */111if ((rsc->dirty & FD_DIRTY_TEX) &&112!(ctx->dirty_shader[stage] & FD_DIRTY_TEX)) {113struct fd_texture_stateobj *tex = &ctx->tex[stage];114for (unsigned i = 0; i < tex->num_textures; i++) {115if (tex->textures[i] && (tex->textures[i]->texture == prsc)) {116fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_TEX);117break;118}119}120}121122/* Images */123if ((rsc->dirty & FD_DIRTY_IMAGE) &&124!(ctx->dirty_shader[stage] & FD_DIRTY_IMAGE)) {125struct fd_shaderimg_stateobj *si = &ctx->shaderimg[stage];126const unsigned num_images = util_last_bit(si->enabled_mask);127for (unsigned i = 0; i < num_images; i++) {128if (si->si[i].resource == prsc) {129fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_IMAGE);130break;131}132}133}134135/* SSBOs */136if ((rsc->dirty & FD_DIRTY_SSBO) &&137!(ctx->dirty_shader[stage] & FD_DIRTY_SSBO)) {138struct fd_shaderbuf_stateobj *sb = &ctx->shaderbuf[stage];139const unsigned num_ssbos = util_last_bit(sb->enabled_mask);140for (unsigned i = 0; i < num_ssbos; i++) {141if (sb->sb[i].buffer == prsc) {142fd_context_dirty_shader(ctx, stage, FD_DIRTY_SHADER_SSBO);143break;144}145}146}147}148}149150static void151rebind_resource(struct fd_resource *rsc) assert_dt152{153struct fd_screen *screen = fd_screen(rsc->b.b.screen);154155fd_screen_lock(screen);156fd_resource_lock(rsc);157158if (rsc->dirty)159list_for_each_entry (struct fd_context, ctx, &screen->context_list, node)160rebind_resource_in_ctx(ctx, rsc);161162fd_resource_unlock(rsc);163fd_screen_unlock(screen);164}165166static inline void167fd_resource_set_bo(struct fd_resource *rsc, struct fd_bo *bo)168{169struct fd_screen *screen = fd_screen(rsc->b.b.screen);170171rsc->bo = bo;172rsc->seqno = p_atomic_inc_return(&screen->rsc_seqno);173}174175int176__fd_resource_wait(struct fd_context *ctx, struct fd_resource *rsc, unsigned op,177const char *func)178{179if (op & FD_BO_PREP_NOSYNC)180return fd_bo_cpu_prep(rsc->bo, ctx->pipe, op);181182int ret;183184perf_time_ctx (ctx, 10000, "%s: a busy \"%" PRSC_FMT "\" BO stalled", func,185PRSC_ARGS(&rsc->b.b)) {186ret = fd_bo_cpu_prep(rsc->bo, ctx->pipe, op);187}188189return ret;190}191192static void193realloc_bo(struct fd_resource *rsc, uint32_t size)194{195struct pipe_resource *prsc = &rsc->b.b;196struct fd_screen *screen = fd_screen(rsc->b.b.screen);197uint32_t flags =198COND(prsc->bind & PIPE_BIND_SCANOUT, FD_BO_SCANOUT);199/* TODO other flags? */200201/* if we start using things other than write-combine,202* be sure to check for PIPE_RESOURCE_FLAG_MAP_COHERENT203*/204205if (rsc->bo)206fd_bo_del(rsc->bo);207208struct fd_bo *bo =209fd_bo_new(screen->dev, size, flags, "%ux%ux%u@%u:%x", prsc->width0,210prsc->height0, prsc->depth0, rsc->layout.cpp, prsc->bind);211fd_resource_set_bo(rsc, bo);212213/* Zero out the UBWC area on allocation. This fixes intermittent failures214* with UBWC, which I suspect are due to the HW having a hard time215* interpreting arbitrary values populating the flags buffer when the BO216* was recycled through the bo cache (instead of fresh allocations from217* the kernel, which are zeroed). sleep(1) in this spot didn't work218* around the issue, but any memset value seems to.219*/220if (rsc->layout.ubwc) {221rsc->needs_ubwc_clear = true;222}223224util_range_set_empty(&rsc->valid_buffer_range);225fd_bc_invalidate_resource(rsc, true);226}227228static void229do_blit(struct fd_context *ctx, const struct pipe_blit_info *blit,230bool fallback) assert_dt231{232struct pipe_context *pctx = &ctx->base;233234assert(!ctx->in_blit);235ctx->in_blit = true;236237/* TODO size threshold too?? */238if (fallback || !fd_blit(pctx, blit)) {239/* do blit on cpu: */240util_resource_copy_region(pctx, blit->dst.resource, blit->dst.level,241blit->dst.box.x, blit->dst.box.y,242blit->dst.box.z, blit->src.resource,243blit->src.level, &blit->src.box);244}245246ctx->in_blit = false;247}248249/**250* Replace the storage of dst with src. This is only used by TC in the251* DISCARD_WHOLE_RESOURCE path, and src is a freshly allocated buffer.252*/253void254fd_replace_buffer_storage(struct pipe_context *pctx, struct pipe_resource *pdst,255struct pipe_resource *psrc, unsigned num_rebinds, uint32_t rebind_mask,256uint32_t delete_buffer_id)257{258struct fd_context *ctx = fd_context(pctx);259struct fd_resource *dst = fd_resource(pdst);260struct fd_resource *src = fd_resource(psrc);261262DBG("pdst=%p, psrc=%p", pdst, psrc);263264/* This should only be called with buffers.. which side-steps some tricker265* cases, like a rsc that is in a batch-cache key...266*/267assert(pdst->target == PIPE_BUFFER);268assert(psrc->target == PIPE_BUFFER);269assert(dst->track->bc_batch_mask == 0);270assert(src->track->bc_batch_mask == 0);271assert(src->track->batch_mask == 0);272assert(src->track->write_batch == NULL);273assert(memcmp(&dst->layout, &src->layout, sizeof(dst->layout)) == 0);274275/* get rid of any references that batch-cache might have to us (which276* should empty/destroy rsc->batches hashset)277*278* Note that we aren't actually destroying dst, but we are replacing279* it's storage so we want to go thru the same motions of decoupling280* it's batch connections.281*/282fd_bc_invalidate_resource(dst, true);283rebind_resource(dst);284285util_idalloc_mt_free(&ctx->screen->buffer_ids, delete_buffer_id);286287fd_screen_lock(ctx->screen);288289fd_bo_del(dst->bo);290dst->bo = fd_bo_ref(src->bo);291292fd_resource_tracking_reference(&dst->track, src->track);293src->is_replacement = true;294295dst->seqno = p_atomic_inc_return(&ctx->screen->rsc_seqno);296297fd_screen_unlock(ctx->screen);298}299300static unsigned301translate_usage(unsigned usage)302{303uint32_t op = 0;304305if (usage & PIPE_MAP_READ)306op |= FD_BO_PREP_READ;307308if (usage & PIPE_MAP_WRITE)309op |= FD_BO_PREP_WRITE;310311return op;312}313314bool315fd_resource_busy(struct pipe_screen *pscreen, struct pipe_resource *prsc,316unsigned usage)317{318struct fd_resource *rsc = fd_resource(prsc);319320if (pending(rsc, !!(usage & PIPE_MAP_WRITE)))321return true;322323if (resource_busy(rsc, translate_usage(usage)))324return true;325326return false;327}328329static void flush_resource(struct fd_context *ctx, struct fd_resource *rsc,330unsigned usage);331332/**333* Helper to check if the format is something that we can blit/render334* to.. if the format is not renderable, there is no point in trying335* to do a staging blit (as it will still end up being a cpu copy)336*/337static bool338is_renderable(struct pipe_resource *prsc)339{340struct pipe_screen *pscreen = prsc->screen;341return pscreen->is_format_supported(342pscreen, prsc->format, prsc->target, prsc->nr_samples,343prsc->nr_storage_samples, PIPE_BIND_RENDER_TARGET);344}345346/**347* @rsc: the resource to shadow348* @level: the level to discard (if box != NULL, otherwise ignored)349* @box: the box to discard (or NULL if none)350* @modifier: the modifier for the new buffer state351*/352static bool353fd_try_shadow_resource(struct fd_context *ctx, struct fd_resource *rsc,354unsigned level, const struct pipe_box *box,355uint64_t modifier) assert_dt356{357struct pipe_context *pctx = &ctx->base;358struct pipe_resource *prsc = &rsc->b.b;359struct fd_screen *screen = fd_screen(pctx->screen);360struct fd_batch *batch;361bool fallback = false;362363if (prsc->next)364return false;365366/* Flush any pending batches writing the resource before we go mucking around367* in its insides. The blit would immediately cause the batch to be flushed,368* anyway.369*/370fd_bc_flush_writer(ctx, rsc);371372/* Because IB1 ("gmem") cmdstream is built only when we flush the373* batch, we need to flush any batches that reference this rsc as374* a render target. Otherwise the framebuffer state emitted in375* IB1 will reference the resources new state, and not the state376* at the point in time that the earlier draws referenced it.377*378* Note that being in the gmem key doesn't necessarily mean the379* batch was considered a writer!380*/381foreach_batch (batch, &screen->batch_cache, rsc->track->bc_batch_mask) {382fd_batch_flush(batch);383}384385/* TODO: somehow munge dimensions and format to copy unsupported386* render target format to something that is supported?387*/388if (!is_renderable(prsc))389fallback = true;390391/* do shadowing back-blits on the cpu for buffers -- requires about a page of392* DMA to make GPU copies worth it according to robclark. Note, if you393* decide to do it on the GPU then you'll need to update valid_buffer_range394* in the swap()s below.395*/396if (prsc->target == PIPE_BUFFER)397fallback = true;398399bool discard_whole_level = box && util_texrange_covers_whole_level(400prsc, level, box->x, box->y, box->z,401box->width, box->height, box->depth);402403/* TODO need to be more clever about current level */404if ((prsc->target >= PIPE_TEXTURE_2D) && box && !discard_whole_level)405return false;406407struct pipe_resource *pshadow = pctx->screen->resource_create_with_modifiers(408pctx->screen, prsc, &modifier, 1);409410if (!pshadow)411return false;412413assert(!ctx->in_shadow);414ctx->in_shadow = true;415416/* get rid of any references that batch-cache might have to us (which417* should empty/destroy rsc->batches hashset)418*/419fd_bc_invalidate_resource(rsc, false);420rebind_resource(rsc);421422fd_screen_lock(ctx->screen);423424/* Swap the backing bo's, so shadow becomes the old buffer,425* blit from shadow to new buffer. From here on out, we426* cannot fail.427*428* Note that we need to do it in this order, otherwise if429* we go down cpu blit path, the recursive transfer_map()430* sees the wrong status..431*/432struct fd_resource *shadow = fd_resource(pshadow);433434DBG("shadow: %p (%d, %p) -> %p (%d, %p)", rsc, rsc->b.b.reference.count,435rsc->track, shadow, shadow->b.b.reference.count, shadow->track);436437swap(rsc->bo, shadow->bo);438swap(rsc->valid, shadow->valid);439440/* swap() doesn't work because you can't typeof() the bitfield. */441bool temp = shadow->needs_ubwc_clear;442shadow->needs_ubwc_clear = rsc->needs_ubwc_clear;443rsc->needs_ubwc_clear = temp;444445swap(rsc->layout, shadow->layout);446rsc->seqno = p_atomic_inc_return(&ctx->screen->rsc_seqno);447448/* at this point, the newly created shadow buffer is not referenced449* by any batches, but the existing rsc (probably) is. We need to450* transfer those references over:451*/452debug_assert(shadow->track->batch_mask == 0);453foreach_batch (batch, &ctx->screen->batch_cache, rsc->track->batch_mask) {454struct set_entry *entry = _mesa_set_search(batch->resources, rsc);455_mesa_set_remove(batch->resources, entry);456_mesa_set_add(batch->resources, shadow);457}458swap(rsc->track, shadow->track);459460fd_screen_unlock(ctx->screen);461462struct pipe_blit_info blit = {};463blit.dst.resource = prsc;464blit.dst.format = prsc->format;465blit.src.resource = pshadow;466blit.src.format = pshadow->format;467blit.mask = util_format_get_mask(prsc->format);468blit.filter = PIPE_TEX_FILTER_NEAREST;469470#define set_box(field, val) \471do { \472blit.dst.field = (val); \473blit.src.field = (val); \474} while (0)475476/* Disable occlusion queries during shadow blits. */477bool saved_active_queries = ctx->active_queries;478pctx->set_active_query_state(pctx, false);479480/* blit the other levels in their entirety: */481for (unsigned l = 0; l <= prsc->last_level; l++) {482if (box && l == level)483continue;484485/* just blit whole level: */486set_box(level, l);487set_box(box.width, u_minify(prsc->width0, l));488set_box(box.height, u_minify(prsc->height0, l));489set_box(box.depth, u_minify(prsc->depth0, l));490491for (int i = 0; i < prsc->array_size; i++) {492set_box(box.z, i);493do_blit(ctx, &blit, fallback);494}495}496497/* deal w/ current level specially, since we might need to split498* it up into a couple blits:499*/500if (box && !discard_whole_level) {501set_box(level, level);502503switch (prsc->target) {504case PIPE_BUFFER:505case PIPE_TEXTURE_1D:506set_box(box.y, 0);507set_box(box.z, 0);508set_box(box.height, 1);509set_box(box.depth, 1);510511if (box->x > 0) {512set_box(box.x, 0);513set_box(box.width, box->x);514515do_blit(ctx, &blit, fallback);516}517if ((box->x + box->width) < u_minify(prsc->width0, level)) {518set_box(box.x, box->x + box->width);519set_box(box.width,520u_minify(prsc->width0, level) - (box->x + box->width));521522do_blit(ctx, &blit, fallback);523}524break;525case PIPE_TEXTURE_2D:526/* TODO */527default:528unreachable("TODO");529}530}531532pctx->set_active_query_state(pctx, saved_active_queries);533534ctx->in_shadow = false;535536pipe_resource_reference(&pshadow, NULL);537538return true;539}540541/**542* Uncompress an UBWC compressed buffer "in place". This works basically543* like resource shadowing, creating a new resource, and doing an uncompress544* blit, and swapping the state between shadow and original resource so it545* appears to the gallium frontends as if nothing changed.546*/547void548fd_resource_uncompress(struct fd_context *ctx, struct fd_resource *rsc, bool linear)549{550tc_assert_driver_thread(ctx->tc);551552uint64_t modifier = linear ? DRM_FORMAT_MOD_LINEAR : FD_FORMAT_MOD_QCOM_TILED;553554bool success = fd_try_shadow_resource(ctx, rsc, 0, NULL, modifier);555556/* shadow should not fail in any cases where we need to uncompress: */557debug_assert(success);558}559560/**561* Debug helper to hexdump a resource.562*/563void564fd_resource_dump(struct fd_resource *rsc, const char *name)565{566fd_bo_cpu_prep(rsc->bo, NULL, FD_BO_PREP_READ);567printf("%s: \n", name);568dump_hex(fd_bo_map(rsc->bo), fd_bo_size(rsc->bo));569}570571static struct fd_resource *572fd_alloc_staging(struct fd_context *ctx, struct fd_resource *rsc,573unsigned level, const struct pipe_box *box)574assert_dt575{576struct pipe_context *pctx = &ctx->base;577struct pipe_resource tmpl = rsc->b.b;578579/* We cannot currently do stencil export on earlier gens, and580* u_blitter cannot do blits involving stencil otherwise:581*/582if ((ctx->screen->gpu_id < 600) && !ctx->blit &&583(util_format_get_mask(tmpl.format) & PIPE_MASK_S))584return NULL;585586tmpl.width0 = box->width;587tmpl.height0 = box->height;588/* for array textures, box->depth is the array_size, otherwise589* for 3d textures, it is the depth:590*/591if (tmpl.array_size > 1) {592if (tmpl.target == PIPE_TEXTURE_CUBE)593tmpl.target = PIPE_TEXTURE_2D_ARRAY;594tmpl.array_size = box->depth;595tmpl.depth0 = 1;596} else {597tmpl.array_size = 1;598tmpl.depth0 = box->depth;599}600tmpl.last_level = 0;601tmpl.bind |= PIPE_BIND_LINEAR;602tmpl.usage = PIPE_USAGE_STAGING;603604struct pipe_resource *pstaging =605pctx->screen->resource_create(pctx->screen, &tmpl);606if (!pstaging)607return NULL;608609return fd_resource(pstaging);610}611612static void613fd_blit_from_staging(struct fd_context *ctx,614struct fd_transfer *trans) assert_dt615{616DBG("");617struct pipe_resource *dst = trans->b.b.resource;618struct pipe_blit_info blit = {};619620blit.dst.resource = dst;621blit.dst.format = dst->format;622blit.dst.level = trans->b.b.level;623blit.dst.box = trans->b.b.box;624blit.src.resource = trans->staging_prsc;625blit.src.format = trans->staging_prsc->format;626blit.src.level = 0;627blit.src.box = trans->staging_box;628blit.mask = util_format_get_mask(trans->staging_prsc->format);629blit.filter = PIPE_TEX_FILTER_NEAREST;630631do_blit(ctx, &blit, false);632}633634static void635fd_blit_to_staging(struct fd_context *ctx, struct fd_transfer *trans) assert_dt636{637DBG("");638struct pipe_resource *src = trans->b.b.resource;639struct pipe_blit_info blit = {};640641blit.src.resource = src;642blit.src.format = src->format;643blit.src.level = trans->b.b.level;644blit.src.box = trans->b.b.box;645blit.dst.resource = trans->staging_prsc;646blit.dst.format = trans->staging_prsc->format;647blit.dst.level = 0;648blit.dst.box = trans->staging_box;649blit.mask = util_format_get_mask(trans->staging_prsc->format);650blit.filter = PIPE_TEX_FILTER_NEAREST;651652do_blit(ctx, &blit, false);653}654655static void656fd_resource_transfer_flush_region(struct pipe_context *pctx,657struct pipe_transfer *ptrans,658const struct pipe_box *box)659{660struct fd_resource *rsc = fd_resource(ptrans->resource);661662if (ptrans->resource->target == PIPE_BUFFER)663util_range_add(&rsc->b.b, &rsc->valid_buffer_range,664ptrans->box.x + box->x,665ptrans->box.x + box->x + box->width);666}667668static void669flush_resource(struct fd_context *ctx, struct fd_resource *rsc,670unsigned usage) assert_dt671{672if (usage & PIPE_MAP_WRITE) {673fd_bc_flush_readers(ctx, rsc);674} else {675fd_bc_flush_writer(ctx, rsc);676}677}678679static void680fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)681in_dt682{683struct fd_context *ctx = fd_context(pctx);684struct fd_resource *rsc = fd_resource(prsc);685686flush_resource(ctx, rsc, PIPE_MAP_READ);687688/* If we had to flush a batch, make sure it makes it's way all the689* way to the kernel:690*/691fd_resource_wait(ctx, rsc, FD_BO_PREP_FLUSH);692}693694static void695fd_resource_transfer_unmap(struct pipe_context *pctx,696struct pipe_transfer *ptrans)697in_dt /* TODO for threaded-ctx we'll need to split out unsynchronized path */698{699struct fd_context *ctx = fd_context(pctx);700struct fd_resource *rsc = fd_resource(ptrans->resource);701struct fd_transfer *trans = fd_transfer(ptrans);702703if (trans->staging_prsc) {704if (ptrans->usage & PIPE_MAP_WRITE)705fd_blit_from_staging(ctx, trans);706pipe_resource_reference(&trans->staging_prsc, NULL);707}708709if (!(ptrans->usage & PIPE_MAP_UNSYNCHRONIZED)) {710fd_bo_cpu_fini(rsc->bo);711}712713util_range_add(&rsc->b.b, &rsc->valid_buffer_range, ptrans->box.x,714ptrans->box.x + ptrans->box.width);715716pipe_resource_reference(&ptrans->resource, NULL);717718assert(trans->b.staging == NULL); /* for threaded context only */719720/* Don't use pool_transfers_unsync. We are always in the driver721* thread. Freeing an object into a different pool is allowed.722*/723slab_free(&ctx->transfer_pool, ptrans);724}725726static void727invalidate_resource(struct fd_resource *rsc, unsigned usage) assert_dt728{729bool needs_flush = pending(rsc, !!(usage & PIPE_MAP_WRITE));730unsigned op = translate_usage(usage);731732if (needs_flush || resource_busy(rsc, op)) {733rebind_resource(rsc);734realloc_bo(rsc, fd_bo_size(rsc->bo));735} else {736util_range_set_empty(&rsc->valid_buffer_range);737}738}739740static void *741resource_transfer_map_unsync(struct pipe_context *pctx,742struct pipe_resource *prsc, unsigned level,743unsigned usage, const struct pipe_box *box,744struct fd_transfer *trans)745{746struct fd_resource *rsc = fd_resource(prsc);747enum pipe_format format = prsc->format;748uint32_t offset;749char *buf;750751buf = fd_bo_map(rsc->bo);752offset = box->y / util_format_get_blockheight(format) * trans->b.b.stride +753box->x / util_format_get_blockwidth(format) * rsc->layout.cpp +754fd_resource_offset(rsc, level, box->z);755756if (usage & PIPE_MAP_WRITE)757rsc->valid = true;758759return buf + offset;760}761762/**763* Note, with threaded_context, resource_transfer_map() is only called764* in driver thread, but resource_transfer_map_unsync() can be called in765* either driver or frontend thread.766*/767static void *768resource_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,769unsigned level, unsigned usage,770const struct pipe_box *box,771struct fd_transfer *trans) in_dt772{773struct fd_context *ctx = fd_context(pctx);774struct fd_resource *rsc = fd_resource(prsc);775char *buf;776int ret = 0;777778tc_assert_driver_thread(ctx->tc);779780/* Strip the read flag if the buffer has been invalidated (or is freshly781* created). Avoids extra staging blits of undefined data on glTexSubImage of782* a fresh DEPTH_COMPONENT or STENCIL_INDEX texture being stored as z24s8.783*/784if (!rsc->valid)785usage &= ~PIPE_MAP_READ;786787/* we always need a staging texture for tiled buffers:788*789* TODO we might sometimes want to *also* shadow the resource to avoid790* splitting a batch.. for ex, mid-frame texture uploads to a tiled791* texture.792*/793if (rsc->layout.tile_mode) {794struct fd_resource *staging_rsc;795796assert(prsc->target != PIPE_BUFFER);797798staging_rsc = fd_alloc_staging(ctx, rsc, level, box);799if (staging_rsc) {800trans->staging_prsc = &staging_rsc->b.b;801trans->b.b.stride = fd_resource_pitch(staging_rsc, 0);802trans->b.b.layer_stride = fd_resource_layer_stride(staging_rsc, 0);803trans->staging_box = *box;804trans->staging_box.x = 0;805trans->staging_box.y = 0;806trans->staging_box.z = 0;807808if (usage & PIPE_MAP_READ) {809fd_blit_to_staging(ctx, trans);810811fd_resource_wait(ctx, staging_rsc, FD_BO_PREP_READ);812}813814buf = fd_bo_map(staging_rsc->bo);815816ctx->stats.staging_uploads++;817818return buf;819}820}821822if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {823invalidate_resource(rsc, usage);824} else {825unsigned op = translate_usage(usage);826bool needs_flush = pending(rsc, !!(usage & PIPE_MAP_WRITE));827828/* If the GPU is writing to the resource, or if it is reading from the829* resource and we're trying to write to it, flush the renders.830*/831bool busy = needs_flush || resource_busy(rsc, op);832833/* if we need to flush/stall, see if we can make a shadow buffer834* to avoid this:835*836* TODO we could go down this path !reorder && !busy_for_read837* ie. we only *don't* want to go down this path if the blit838* will trigger a flush!839*/840if (ctx->screen->reorder && busy && !(usage & PIPE_MAP_READ) &&841(usage & PIPE_MAP_DISCARD_RANGE)) {842843/* try shadowing only if it avoids a flush, otherwise staging would844* be better:845*/846if (needs_flush && fd_try_shadow_resource(ctx, rsc, level, box,847DRM_FORMAT_MOD_LINEAR)) {848needs_flush = busy = false;849ctx->stats.shadow_uploads++;850} else {851struct fd_resource *staging_rsc = NULL;852853if (needs_flush) {854flush_resource(ctx, rsc, usage);855needs_flush = false;856}857858/* in this case, we don't need to shadow the whole resource,859* since any draw that references the previous contents has860* already had rendering flushed for all tiles. So we can861* use a staging buffer to do the upload.862*/863if (is_renderable(prsc))864staging_rsc = fd_alloc_staging(ctx, rsc, level, box);865if (staging_rsc) {866trans->staging_prsc = &staging_rsc->b.b;867trans->b.b.stride = fd_resource_pitch(staging_rsc, 0);868trans->b.b.layer_stride =869fd_resource_layer_stride(staging_rsc, 0);870trans->staging_box = *box;871trans->staging_box.x = 0;872trans->staging_box.y = 0;873trans->staging_box.z = 0;874buf = fd_bo_map(staging_rsc->bo);875876ctx->stats.staging_uploads++;877878return buf;879}880}881}882883if (needs_flush) {884flush_resource(ctx, rsc, usage);885needs_flush = false;886}887888/* The GPU keeps track of how the various bo's are being used, and889* will wait if necessary for the proper operation to have890* completed.891*/892if (busy) {893ret = fd_resource_wait(ctx, rsc, op);894if (ret)895return NULL;896}897}898899return resource_transfer_map_unsync(pctx, prsc, level, usage, box, trans);900}901902static unsigned903improve_transfer_map_usage(struct fd_context *ctx, struct fd_resource *rsc,904unsigned usage, const struct pipe_box *box)905/* Not *strictly* true, but the access to things that must only be in driver-906* thread are protected by !(usage & TC_TRANSFER_MAP_THREADED_UNSYNC):907*/908in_dt909{910if (usage & TC_TRANSFER_MAP_NO_INVALIDATE) {911usage &= ~PIPE_MAP_DISCARD_WHOLE_RESOURCE;912}913914if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC)915usage |= PIPE_MAP_UNSYNCHRONIZED;916917if (!(usage &918(TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED | PIPE_MAP_UNSYNCHRONIZED))) {919if (ctx->in_shadow && !(usage & PIPE_MAP_READ)) {920usage |= PIPE_MAP_UNSYNCHRONIZED;921} else if ((usage & PIPE_MAP_WRITE) && (rsc->b.b.target == PIPE_BUFFER) &&922!util_ranges_intersect(&rsc->valid_buffer_range, box->x,923box->x + box->width)) {924/* We are trying to write to a previously uninitialized range. No need925* to synchronize.926*/927usage |= PIPE_MAP_UNSYNCHRONIZED;928}929}930931return usage;932}933934static void *935fd_resource_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,936unsigned level, unsigned usage,937const struct pipe_box *box,938struct pipe_transfer **pptrans)939{940struct fd_context *ctx = fd_context(pctx);941struct fd_resource *rsc = fd_resource(prsc);942struct fd_transfer *trans;943struct pipe_transfer *ptrans;944945DBG("prsc=%p, level=%u, usage=%x, box=%dx%d+%d,%d", prsc, level, usage,946box->width, box->height, box->x, box->y);947948if ((usage & PIPE_MAP_DIRECTLY) && rsc->layout.tile_mode) {949DBG("CANNOT MAP DIRECTLY!\n");950return NULL;951}952953if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) {954ptrans = slab_alloc(&ctx->transfer_pool_unsync);955} else {956ptrans = slab_alloc(&ctx->transfer_pool);957}958959if (!ptrans)960return NULL;961962/* slab_alloc_st() doesn't zero: */963trans = fd_transfer(ptrans);964memset(trans, 0, sizeof(*trans));965966usage = improve_transfer_map_usage(ctx, rsc, usage, box);967968pipe_resource_reference(&ptrans->resource, prsc);969ptrans->level = level;970ptrans->usage = usage;971ptrans->box = *box;972ptrans->stride = fd_resource_pitch(rsc, level);973ptrans->layer_stride = fd_resource_layer_stride(rsc, level);974975void *ret;976if (usage & PIPE_MAP_UNSYNCHRONIZED) {977ret = resource_transfer_map_unsync(pctx, prsc, level, usage, box, trans);978} else {979ret = resource_transfer_map(pctx, prsc, level, usage, box, trans);980}981982if (ret) {983*pptrans = ptrans;984} else {985fd_resource_transfer_unmap(pctx, ptrans);986}987988return ret;989}990991static void992fd_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)993{994struct fd_screen *screen = fd_screen(prsc->screen);995struct fd_resource *rsc = fd_resource(prsc);996997if (!rsc->is_replacement)998fd_bc_invalidate_resource(rsc, true);999if (rsc->bo)1000fd_bo_del(rsc->bo);1001if (rsc->lrz)1002fd_bo_del(rsc->lrz);1003if (rsc->scanout)1004renderonly_scanout_destroy(rsc->scanout, fd_screen(pscreen)->ro);10051006if (prsc->target == PIPE_BUFFER)1007util_idalloc_mt_free(&screen->buffer_ids, rsc->b.buffer_id_unique);10081009threaded_resource_deinit(prsc);10101011util_range_destroy(&rsc->valid_buffer_range);1012simple_mtx_destroy(&rsc->lock);1013fd_resource_tracking_reference(&rsc->track, NULL);10141015FREE(rsc);1016}10171018static uint64_t1019fd_resource_modifier(struct fd_resource *rsc)1020{1021if (!rsc->layout.tile_mode)1022return DRM_FORMAT_MOD_LINEAR;10231024if (rsc->layout.ubwc_layer_size)1025return DRM_FORMAT_MOD_QCOM_COMPRESSED;10261027/* TODO invent a modifier for tiled but not UBWC buffers: */1028return DRM_FORMAT_MOD_INVALID;1029}10301031static bool1032fd_resource_get_handle(struct pipe_screen *pscreen, struct pipe_context *pctx,1033struct pipe_resource *prsc, struct winsys_handle *handle,1034unsigned usage)1035{1036struct fd_resource *rsc = fd_resource(prsc);10371038rsc->b.is_shared = true;10391040handle->modifier = fd_resource_modifier(rsc);10411042DBG("%" PRSC_FMT ", modifier=%" PRIx64, PRSC_ARGS(prsc), handle->modifier);10431044return fd_screen_bo_get_handle(pscreen, rsc->bo, rsc->scanout,1045fd_resource_pitch(rsc, 0), handle);1046}10471048/* special case to resize query buf after allocated.. */1049void1050fd_resource_resize(struct pipe_resource *prsc, uint32_t sz)1051{1052struct fd_resource *rsc = fd_resource(prsc);10531054debug_assert(prsc->width0 == 0);1055debug_assert(prsc->target == PIPE_BUFFER);1056debug_assert(prsc->bind == PIPE_BIND_QUERY_BUFFER);10571058prsc->width0 = sz;1059realloc_bo(rsc, fd_screen(prsc->screen)->setup_slices(rsc));1060}10611062static void1063fd_resource_layout_init(struct pipe_resource *prsc)1064{1065struct fd_resource *rsc = fd_resource(prsc);1066struct fdl_layout *layout = &rsc->layout;10671068layout->format = prsc->format;10691070layout->width0 = prsc->width0;1071layout->height0 = prsc->height0;1072layout->depth0 = prsc->depth0;10731074layout->cpp = util_format_get_blocksize(prsc->format);1075layout->cpp *= fd_resource_nr_samples(prsc);1076layout->cpp_shift = ffs(layout->cpp) - 1;1077}10781079static struct fd_resource *1080alloc_resource_struct(struct pipe_screen *pscreen,1081const struct pipe_resource *tmpl)1082{1083struct fd_screen *screen = fd_screen(pscreen);1084struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);10851086if (!rsc)1087return NULL;10881089struct pipe_resource *prsc = &rsc->b.b;1090*prsc = *tmpl;10911092pipe_reference_init(&prsc->reference, 1);1093prsc->screen = pscreen;10941095util_range_init(&rsc->valid_buffer_range);1096simple_mtx_init(&rsc->lock, mtx_plain);10971098rsc->track = CALLOC_STRUCT(fd_resource_tracking);1099if (!rsc->track) {1100free(rsc);1101return NULL;1102}11031104pipe_reference_init(&rsc->track->reference, 1);11051106threaded_resource_init(prsc);11071108if (tmpl->target == PIPE_BUFFER)1109rsc->b.buffer_id_unique = util_idalloc_mt_alloc(&screen->buffer_ids);11101111return rsc;1112}11131114/**1115* Helper that allocates a resource and resolves its layout (but doesn't1116* allocate its bo).1117*1118* It returns a pipe_resource (as fd_resource_create_with_modifiers()1119* would do), and also bo's minimum required size as an output argument.1120*/1121static struct pipe_resource *1122fd_resource_allocate_and_resolve(struct pipe_screen *pscreen,1123const struct pipe_resource *tmpl,1124const uint64_t *modifiers, int count,1125uint32_t *psize)1126{1127struct fd_screen *screen = fd_screen(pscreen);1128struct fd_resource *rsc;1129struct pipe_resource *prsc;1130enum pipe_format format = tmpl->format;1131uint32_t size;11321133rsc = alloc_resource_struct(pscreen, tmpl);1134if (!rsc)1135return NULL;11361137prsc = &rsc->b.b;11381139DBG("%" PRSC_FMT, PRSC_ARGS(prsc));11401141if (tmpl->bind & PIPE_BIND_SHARED)1142rsc->b.is_shared = true;11431144fd_resource_layout_init(prsc);11451146#define LINEAR (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR | PIPE_BIND_DISPLAY_TARGET)11471148bool linear = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);1149if (linear) {1150perf_debug("%" PRSC_FMT ": linear: DRM_FORMAT_MOD_LINEAR requested!",1151PRSC_ARGS(prsc));1152} else if (tmpl->bind & LINEAR) {1153if (tmpl->usage != PIPE_USAGE_STAGING)1154perf_debug("%" PRSC_FMT ": linear: LINEAR bind requested!",1155PRSC_ARGS(prsc));1156linear = true;1157}11581159if (FD_DBG(NOTILE))1160linear = true;11611162/* Normally, for non-shared buffers, allow buffer compression if1163* not shared, otherwise only allow if QCOM_COMPRESSED modifier1164* is requested:1165*1166* TODO we should probably also limit tiled in a similar way,1167* except we don't have a format modifier for tiled. (We probably1168* should.)1169*/1170bool allow_ubwc = false;1171if (!linear) {1172allow_ubwc = drm_find_modifier(DRM_FORMAT_MOD_INVALID, modifiers, count);1173if (!allow_ubwc) {1174perf_debug("%" PRSC_FMT1175": not UBWC: DRM_FORMAT_MOD_INVALID not requested!",1176PRSC_ARGS(prsc));1177}1178if (tmpl->bind & PIPE_BIND_SHARED) {1179allow_ubwc =1180drm_find_modifier(DRM_FORMAT_MOD_QCOM_COMPRESSED, modifiers, count);1181if (!allow_ubwc) {1182perf_debug("%" PRSC_FMT1183": not UBWC: shared and DRM_FORMAT_MOD_QCOM_COMPRESSED "1184"not requested!",1185PRSC_ARGS(prsc));1186linear = true;1187}1188}1189}11901191allow_ubwc &= !FD_DBG(NOUBWC);11921193if (screen->tile_mode && (tmpl->target != PIPE_BUFFER) && !linear) {1194rsc->layout.tile_mode = screen->tile_mode(prsc);1195}11961197rsc->internal_format = format;11981199rsc->layout.ubwc = rsc->layout.tile_mode && is_a6xx(screen) && allow_ubwc;12001201if (prsc->target == PIPE_BUFFER) {1202assert(prsc->format == PIPE_FORMAT_R8_UNORM);1203size = prsc->width0;1204fdl_layout_buffer(&rsc->layout, size);1205} else {1206size = screen->setup_slices(rsc);1207}12081209/* special case for hw-query buffer, which we need to allocate before we1210* know the size:1211*/1212if (size == 0) {1213/* note, semi-intention == instead of & */1214debug_assert(prsc->bind == PIPE_BIND_QUERY_BUFFER);1215*psize = 0;1216return prsc;1217}12181219/* Set the layer size if the (non-a6xx) backend hasn't done so. */1220if (rsc->layout.layer_first && !rsc->layout.layer_size) {1221rsc->layout.layer_size = align(size, 4096);1222size = rsc->layout.layer_size * prsc->array_size;1223}12241225if (FD_DBG(LAYOUT))1226fdl_dump_layout(&rsc->layout);12271228/* Hand out the resolved size. */1229if (psize)1230*psize = size;12311232return prsc;1233}12341235/**1236* Create a new texture object, using the given template info.1237*/1238static struct pipe_resource *1239fd_resource_create_with_modifiers(struct pipe_screen *pscreen,1240const struct pipe_resource *tmpl,1241const uint64_t *modifiers, int count)1242{1243struct fd_screen *screen = fd_screen(pscreen);1244struct fd_resource *rsc;1245struct pipe_resource *prsc;1246uint32_t size;12471248/* when using kmsro, scanout buffers are allocated on the display device1249* create_with_modifiers() doesn't give us usage flags, so we have to1250* assume that all calls with modifiers are scanout-possible1251*/1252if (screen->ro &&1253((tmpl->bind & PIPE_BIND_SCANOUT) ||1254!(count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID))) {1255struct pipe_resource scanout_templat = *tmpl;1256struct renderonly_scanout *scanout;1257struct winsys_handle handle;12581259/* note: alignment is wrong for a6xx */1260scanout_templat.width0 = align(tmpl->width0, screen->info->gmem_align_w);12611262scanout =1263renderonly_scanout_for_resource(&scanout_templat, screen->ro, &handle);1264if (!scanout)1265return NULL;12661267renderonly_scanout_destroy(scanout, screen->ro);12681269assert(handle.type == WINSYS_HANDLE_TYPE_FD);1270rsc = fd_resource(pscreen->resource_from_handle(1271pscreen, tmpl, &handle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));1272close(handle.handle);1273if (!rsc)1274return NULL;12751276return &rsc->b.b;1277}12781279prsc =1280fd_resource_allocate_and_resolve(pscreen, tmpl, modifiers, count, &size);1281if (!prsc)1282return NULL;1283rsc = fd_resource(prsc);12841285realloc_bo(rsc, size);1286if (!rsc->bo)1287goto fail;12881289return prsc;1290fail:1291fd_resource_destroy(pscreen, prsc);1292return NULL;1293}12941295static struct pipe_resource *1296fd_resource_create(struct pipe_screen *pscreen,1297const struct pipe_resource *tmpl)1298{1299const uint64_t mod = DRM_FORMAT_MOD_INVALID;1300return fd_resource_create_with_modifiers(pscreen, tmpl, &mod, 1);1301}13021303/**1304* Create a texture from a winsys_handle. The handle is often created in1305* another process by first creating a pipe texture and then calling1306* resource_get_handle.1307*/1308static struct pipe_resource *1309fd_resource_from_handle(struct pipe_screen *pscreen,1310const struct pipe_resource *tmpl,1311struct winsys_handle *handle, unsigned usage)1312{1313struct fd_screen *screen = fd_screen(pscreen);1314struct fd_resource *rsc = alloc_resource_struct(pscreen, tmpl);13151316if (!rsc)1317return NULL;13181319struct fdl_slice *slice = fd_resource_slice(rsc, 0);1320struct pipe_resource *prsc = &rsc->b.b;13211322DBG("%" PRSC_FMT ", modifier=%" PRIx64, PRSC_ARGS(prsc), handle->modifier);13231324rsc->b.is_shared = true;13251326fd_resource_layout_init(prsc);13271328struct fd_bo *bo = fd_screen_bo_from_handle(pscreen, handle);1329if (!bo)1330goto fail;13311332fd_resource_set_bo(rsc, bo);13331334rsc->internal_format = tmpl->format;1335rsc->layout.pitch0 = handle->stride;1336slice->offset = handle->offset;1337slice->size0 = handle->stride * prsc->height0;13381339/* use a pitchalign of gmem_align_w pixels, because GMEM resolve for1340* lower alignments is not implemented (but possible for a6xx at least)1341*1342* for UBWC-enabled resources, layout_resource_for_modifier will further1343* validate the pitch and set the right pitchalign1344*/1345rsc->layout.pitchalign =1346fdl_cpp_shift(&rsc->layout) + util_logbase2(screen->info->gmem_align_w);13471348/* apply the minimum pitchalign (note: actually 4 for a3xx but doesn't1349* matter) */1350if (is_a6xx(screen) || is_a5xx(screen))1351rsc->layout.pitchalign = MAX2(rsc->layout.pitchalign, 6);1352else1353rsc->layout.pitchalign = MAX2(rsc->layout.pitchalign, 5);13541355if (rsc->layout.pitch0 < (prsc->width0 * rsc->layout.cpp) ||1356fd_resource_pitch(rsc, 0) != rsc->layout.pitch0)1357goto fail;13581359assert(rsc->layout.cpp);13601361if (screen->layout_resource_for_modifier(rsc, handle->modifier) < 0)1362goto fail;13631364if (screen->ro) {1365rsc->scanout =1366renderonly_create_gpu_import_for_resource(prsc, screen->ro, NULL);1367/* failure is expected in some cases.. */1368}13691370rsc->valid = true;13711372return prsc;13731374fail:1375fd_resource_destroy(pscreen, prsc);1376return NULL;1377}13781379bool1380fd_render_condition_check(struct pipe_context *pctx)1381{1382struct fd_context *ctx = fd_context(pctx);13831384if (!ctx->cond_query)1385return true;13861387perf_debug("Implementing conditional rendering using a CPU read instaed of HW conditional rendering.");13881389union pipe_query_result res = {0};1390bool wait = ctx->cond_mode != PIPE_RENDER_COND_NO_WAIT &&1391ctx->cond_mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT;13921393if (pctx->get_query_result(pctx, ctx->cond_query, wait, &res))1394return (bool)res.u64 != ctx->cond_cond;13951396return true;1397}13981399static void1400fd_invalidate_resource(struct pipe_context *pctx,1401struct pipe_resource *prsc) in_dt1402{1403struct fd_context *ctx = fd_context(pctx);1404struct fd_resource *rsc = fd_resource(prsc);14051406if (prsc->target == PIPE_BUFFER) {1407/* Handle the glInvalidateBufferData() case:1408*/1409invalidate_resource(rsc, PIPE_MAP_READ | PIPE_MAP_WRITE);1410} else if (rsc->track->write_batch) {1411/* Handle the glInvalidateFramebuffer() case, telling us that1412* we can skip resolve.1413*/14141415struct fd_batch *batch = rsc->track->write_batch;1416struct pipe_framebuffer_state *pfb = &batch->framebuffer;14171418if (pfb->zsbuf && pfb->zsbuf->texture == prsc) {1419batch->resolve &= ~(FD_BUFFER_DEPTH | FD_BUFFER_STENCIL);1420fd_context_dirty(ctx, FD_DIRTY_ZSA);1421}14221423for (unsigned i = 0; i < pfb->nr_cbufs; i++) {1424if (pfb->cbufs[i] && pfb->cbufs[i]->texture == prsc) {1425batch->resolve &= ~(PIPE_CLEAR_COLOR0 << i);1426fd_context_dirty(ctx, FD_DIRTY_FRAMEBUFFER);1427}1428}1429}14301431rsc->valid = false;1432}14331434static enum pipe_format1435fd_resource_get_internal_format(struct pipe_resource *prsc)1436{1437return fd_resource(prsc)->internal_format;1438}14391440static void1441fd_resource_set_stencil(struct pipe_resource *prsc,1442struct pipe_resource *stencil)1443{1444fd_resource(prsc)->stencil = fd_resource(stencil);1445}14461447static struct pipe_resource *1448fd_resource_get_stencil(struct pipe_resource *prsc)1449{1450struct fd_resource *rsc = fd_resource(prsc);1451if (rsc->stencil)1452return &rsc->stencil->b.b;1453return NULL;1454}14551456static const struct u_transfer_vtbl transfer_vtbl = {1457.resource_create = fd_resource_create,1458.resource_destroy = fd_resource_destroy,1459.transfer_map = fd_resource_transfer_map,1460.transfer_flush_region = fd_resource_transfer_flush_region,1461.transfer_unmap = fd_resource_transfer_unmap,1462.get_internal_format = fd_resource_get_internal_format,1463.set_stencil = fd_resource_set_stencil,1464.get_stencil = fd_resource_get_stencil,1465};14661467static const uint64_t supported_modifiers[] = {1468DRM_FORMAT_MOD_LINEAR,1469};14701471static int1472fd_layout_resource_for_modifier(struct fd_resource *rsc, uint64_t modifier)1473{1474switch (modifier) {1475case DRM_FORMAT_MOD_LINEAR:1476/* The dri gallium frontend will pass DRM_FORMAT_MOD_INVALID to us1477* when it's called through any of the non-modifier BO create entry1478* points. Other drivers will determine tiling from the kernel or1479* other legacy backchannels, but for freedreno it just means1480* LINEAR. */1481case DRM_FORMAT_MOD_INVALID:1482return 0;1483default:1484return -1;1485}1486}14871488static struct pipe_resource *1489fd_resource_from_memobj(struct pipe_screen *pscreen,1490const struct pipe_resource *tmpl,1491struct pipe_memory_object *pmemobj, uint64_t offset)1492{1493struct fd_screen *screen = fd_screen(pscreen);1494struct fd_memory_object *memobj = fd_memory_object(pmemobj);1495struct pipe_resource *prsc;1496struct fd_resource *rsc;1497uint32_t size;1498assert(memobj->bo);14991500/* We shouldn't get a scanout buffer here. */1501assert(!(tmpl->bind & PIPE_BIND_SCANOUT));15021503uint64_t modifiers = DRM_FORMAT_MOD_INVALID;1504if (tmpl->bind & PIPE_BIND_LINEAR) {1505modifiers = DRM_FORMAT_MOD_LINEAR;1506} else if (is_a6xx(screen) && tmpl->width0 >= FDL_MIN_UBWC_WIDTH) {1507modifiers = DRM_FORMAT_MOD_QCOM_COMPRESSED;1508}15091510/* Allocate new pipe resource. */1511prsc = fd_resource_allocate_and_resolve(pscreen, tmpl, &modifiers, 1, &size);1512if (!prsc)1513return NULL;1514rsc = fd_resource(prsc);1515rsc->b.is_shared = true;15161517/* bo's size has to be large enough, otherwise cleanup resource and fail1518* gracefully.1519*/1520if (fd_bo_size(memobj->bo) < size) {1521fd_resource_destroy(pscreen, prsc);1522return NULL;1523}15241525/* Share the bo with the memory object. */1526fd_resource_set_bo(rsc, fd_bo_ref(memobj->bo));15271528return prsc;1529}15301531static struct pipe_memory_object *1532fd_memobj_create_from_handle(struct pipe_screen *pscreen,1533struct winsys_handle *whandle, bool dedicated)1534{1535struct fd_memory_object *memobj = CALLOC_STRUCT(fd_memory_object);1536if (!memobj)1537return NULL;15381539struct fd_bo *bo = fd_screen_bo_from_handle(pscreen, whandle);1540if (!bo) {1541free(memobj);1542return NULL;1543}15441545memobj->b.dedicated = dedicated;1546memobj->bo = bo;15471548return &memobj->b;1549}15501551static void1552fd_memobj_destroy(struct pipe_screen *pscreen,1553struct pipe_memory_object *pmemobj)1554{1555struct fd_memory_object *memobj = fd_memory_object(pmemobj);15561557assert(memobj->bo);1558fd_bo_del(memobj->bo);15591560free(pmemobj);1561}15621563void1564fd_resource_screen_init(struct pipe_screen *pscreen)1565{1566struct fd_screen *screen = fd_screen(pscreen);1567bool fake_rgtc = screen->gpu_id < 400;15681569pscreen->resource_create = u_transfer_helper_resource_create;1570/* NOTE: u_transfer_helper does not yet support the _with_modifiers()1571* variant:1572*/1573pscreen->resource_create_with_modifiers = fd_resource_create_with_modifiers;1574pscreen->resource_from_handle = fd_resource_from_handle;1575pscreen->resource_get_handle = fd_resource_get_handle;1576pscreen->resource_destroy = u_transfer_helper_resource_destroy;15771578pscreen->transfer_helper =1579u_transfer_helper_create(&transfer_vtbl, true, false, fake_rgtc, true);15801581if (!screen->layout_resource_for_modifier)1582screen->layout_resource_for_modifier = fd_layout_resource_for_modifier;1583if (!screen->supported_modifiers) {1584screen->supported_modifiers = supported_modifiers;1585screen->num_supported_modifiers = ARRAY_SIZE(supported_modifiers);1586}15871588/* GL_EXT_memory_object */1589pscreen->memobj_create_from_handle = fd_memobj_create_from_handle;1590pscreen->memobj_destroy = fd_memobj_destroy;1591pscreen->resource_from_memobj = fd_resource_from_memobj;1592}15931594static void1595fd_get_sample_position(struct pipe_context *context, unsigned sample_count,1596unsigned sample_index, float *pos_out)1597{1598/* The following is copied from nouveau/nv50 except for position1599* values, which are taken from blob driver */1600static const uint8_t pos1[1][2] = {{0x8, 0x8}};1601static const uint8_t pos2[2][2] = {{0xc, 0xc}, {0x4, 0x4}};1602static const uint8_t pos4[4][2] = {{0x6, 0x2},1603{0xe, 0x6},1604{0x2, 0xa},1605{0xa, 0xe}};1606/* TODO needs to be verified on supported hw */1607static const uint8_t pos8[8][2] = {{0x9, 0x5}, {0x7, 0xb}, {0xd, 0x9},1608{0x5, 0x3}, {0x3, 0xd}, {0x1, 0x7},1609{0xb, 0xf}, {0xf, 0x1}};16101611const uint8_t(*ptr)[2];16121613switch (sample_count) {1614case 1:1615ptr = pos1;1616break;1617case 2:1618ptr = pos2;1619break;1620case 4:1621ptr = pos4;1622break;1623case 8:1624ptr = pos8;1625break;1626default:1627assert(0);1628return;1629}16301631pos_out[0] = ptr[sample_index][0] / 16.0f;1632pos_out[1] = ptr[sample_index][1] / 16.0f;1633}16341635static void1636fd_blit_pipe(struct pipe_context *pctx,1637const struct pipe_blit_info *blit_info) in_dt1638{1639/* wrap fd_blit to return void */1640fd_blit(pctx, blit_info);1641}16421643void1644fd_resource_context_init(struct pipe_context *pctx)1645{1646pctx->buffer_map = u_transfer_helper_transfer_map;1647pctx->texture_map = u_transfer_helper_transfer_map;1648pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;1649pctx->buffer_unmap = u_transfer_helper_transfer_unmap;1650pctx->texture_unmap = u_transfer_helper_transfer_unmap;1651pctx->buffer_subdata = u_default_buffer_subdata;1652pctx->texture_subdata = u_default_texture_subdata;1653pctx->create_surface = fd_create_surface;1654pctx->surface_destroy = fd_surface_destroy;1655pctx->resource_copy_region = fd_resource_copy_region;1656pctx->blit = fd_blit_pipe;1657pctx->flush_resource = fd_flush_resource;1658pctx->invalidate_resource = fd_invalidate_resource;1659pctx->get_sample_position = fd_get_sample_position;1660}166116621663