Path: blob/21.2-virgl/src/gallium/drivers/lima/lima_resource.c
4565 views
/*1* Copyright (c) 2017-2019 Lima Project2*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, sub license,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 the11* next paragraph) shall be included in all copies or substantial portions12* of the 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 NON-INFRINGEMENT. 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, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*22*/2324#include "util/u_memory.h"25#include "util/u_blitter.h"26#include "util/format/u_format.h"27#include "util/u_inlines.h"28#include "util/u_math.h"29#include "util/u_debug.h"30#include "util/u_transfer.h"31#include "util/u_surface.h"32#include "util/hash_table.h"33#include "util/ralloc.h"34#include "util/u_drm.h"35#include "renderonly/renderonly.h"3637#include "frontend/drm_driver.h"3839#include "drm-uapi/drm_fourcc.h"40#include "drm-uapi/lima_drm.h"4142#include "lima_screen.h"43#include "lima_context.h"44#include "lima_resource.h"45#include "lima_bo.h"46#include "lima_util.h"4748#include "pan_minmax_cache.h"49#include "pan_tiling.h"5051static struct pipe_resource *52lima_resource_create_scanout(struct pipe_screen *pscreen,53const struct pipe_resource *templat,54unsigned width, unsigned height)55{56struct lima_screen *screen = lima_screen(pscreen);57struct renderonly_scanout *scanout;58struct winsys_handle handle;59struct pipe_resource *pres;6061struct pipe_resource scanout_templat = *templat;62scanout_templat.width0 = width;63scanout_templat.height0 = height;64scanout_templat.screen = pscreen;6566scanout = renderonly_scanout_for_resource(&scanout_templat,67screen->ro, &handle);68if (!scanout)69return NULL;7071assert(handle.type == WINSYS_HANDLE_TYPE_FD);72pres = pscreen->resource_from_handle(pscreen, templat, &handle,73PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);7475close(handle.handle);76if (!pres) {77renderonly_scanout_destroy(scanout, screen->ro);78return NULL;79}8081struct lima_resource *res = lima_resource(pres);82res->scanout = scanout;8384return pres;85}8687static uint32_t88setup_miptree(struct lima_resource *res,89unsigned width0, unsigned height0,90bool should_align_dimensions)91{92struct pipe_resource *pres = &res->base;93unsigned level;94unsigned width = width0;95unsigned height = height0;96unsigned depth = pres->depth0;97uint32_t size = 0;9899for (level = 0; level <= pres->last_level; level++) {100uint32_t actual_level_size;101uint32_t stride;102unsigned aligned_width;103unsigned aligned_height;104105if (should_align_dimensions) {106aligned_width = align(width, 16);107aligned_height = align(height, 16);108} else {109aligned_width = width;110aligned_height = height;111}112113stride = util_format_get_stride(pres->format, aligned_width);114actual_level_size = stride *115util_format_get_nblocksy(pres->format, aligned_height) *116pres->array_size * depth;117118res->levels[level].width = aligned_width;119res->levels[level].stride = stride;120res->levels[level].offset = size;121res->levels[level].layer_stride = util_format_get_stride(pres->format, align(width, 16)) * align(height, 16);122123if (util_format_is_compressed(pres->format))124res->levels[level].layer_stride /= 4;125126/* The start address of each level except the last level127* must be 64-aligned in order to be able to pass the128* addresses to the hardware. */129if (level != pres->last_level)130size += align(actual_level_size, 64);131else132size += actual_level_size; /* Save some memory */133134width = u_minify(width, 1);135height = u_minify(height, 1);136depth = u_minify(depth, 1);137}138139return size;140}141142static struct pipe_resource *143lima_resource_create_bo(struct pipe_screen *pscreen,144const struct pipe_resource *templat,145unsigned width, unsigned height,146bool should_align_dimensions)147{148struct lima_screen *screen = lima_screen(pscreen);149struct lima_resource *res;150struct pipe_resource *pres;151152res = CALLOC_STRUCT(lima_resource);153if (!res)154return NULL;155156res->base = *templat;157res->base.screen = pscreen;158pipe_reference_init(&res->base.reference, 1);159160pres = &res->base;161162uint32_t size = setup_miptree(res, width, height, should_align_dimensions);163size = align(size, LIMA_PAGE_SIZE);164165res->bo = lima_bo_create(screen, size, 0);166if (!res->bo) {167FREE(res);168return NULL;169}170171return pres;172}173174static struct pipe_resource *175_lima_resource_create_with_modifiers(struct pipe_screen *pscreen,176const struct pipe_resource *templat,177const uint64_t *modifiers,178int count)179{180struct lima_screen *screen = lima_screen(pscreen);181bool should_tile = lima_debug & LIMA_DEBUG_NO_TILING ? false : true;182unsigned width, height;183bool should_align_dimensions;184bool has_user_modifiers = true;185186if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)187has_user_modifiers = false;188189/* VBOs/PBOs are untiled (and 1 height). */190if (templat->target == PIPE_BUFFER)191should_tile = false;192193if (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT))194should_tile = false;195196/* If there's no user modifiers and buffer is shared we use linear */197if (!has_user_modifiers && (templat->bind & PIPE_BIND_SHARED))198should_tile = false;199200if (has_user_modifiers &&201!drm_find_modifier(DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,202modifiers, count))203should_tile = false;204205if (should_tile || (templat->bind & PIPE_BIND_RENDER_TARGET) ||206(templat->bind & PIPE_BIND_DEPTH_STENCIL)) {207should_align_dimensions = true;208width = align(templat->width0, 16);209height = align(templat->height0, 16);210}211else {212should_align_dimensions = false;213width = templat->width0;214height = templat->height0;215}216217struct pipe_resource *pres;218if (screen->ro && (templat->bind & PIPE_BIND_SCANOUT))219pres = lima_resource_create_scanout(pscreen, templat, width, height);220else221pres = lima_resource_create_bo(pscreen, templat, width, height,222should_align_dimensions);223224if (pres) {225struct lima_resource *res = lima_resource(pres);226res->tiled = should_tile;227228if (templat->bind & PIPE_BIND_INDEX_BUFFER)229res->index_cache = CALLOC_STRUCT(panfrost_minmax_cache);230231debug_printf("%s: pres=%p width=%u height=%u depth=%u target=%d "232"bind=%x usage=%d tile=%d last_level=%d\n", __func__,233pres, pres->width0, pres->height0, pres->depth0,234pres->target, pres->bind, pres->usage, should_tile, templat->last_level);235}236return pres;237}238239static struct pipe_resource *240lima_resource_create(struct pipe_screen *pscreen,241const struct pipe_resource *templat)242{243const uint64_t mod = DRM_FORMAT_MOD_INVALID;244245return _lima_resource_create_with_modifiers(pscreen, templat, &mod, 1);246}247248static struct pipe_resource *249lima_resource_create_with_modifiers(struct pipe_screen *pscreen,250const struct pipe_resource *templat,251const uint64_t *modifiers,252int count)253{254struct pipe_resource tmpl = *templat;255256/* gbm_bo_create_with_modifiers & gbm_surface_create_with_modifiers257* don't have usage parameter, but buffer created by these functions258* may be used for scanout. So we assume buffer created by this259* function always enable scanout if linear modifier is permitted.260*/261if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))262tmpl.bind |= PIPE_BIND_SCANOUT;263264return _lima_resource_create_with_modifiers(pscreen, &tmpl, modifiers, count);265}266267static void268lima_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres)269{270struct lima_screen *screen = lima_screen(pscreen);271struct lima_resource *res = lima_resource(pres);272273if (res->bo)274lima_bo_unreference(res->bo);275276if (res->scanout)277renderonly_scanout_destroy(res->scanout, screen->ro);278279if (res->damage.region)280FREE(res->damage.region);281282if (res->index_cache)283FREE(res->index_cache);284285FREE(res);286}287288static struct pipe_resource *289lima_resource_from_handle(struct pipe_screen *pscreen,290const struct pipe_resource *templat,291struct winsys_handle *handle, unsigned usage)292{293if (templat->bind & (PIPE_BIND_SAMPLER_VIEW |294PIPE_BIND_RENDER_TARGET |295PIPE_BIND_DEPTH_STENCIL)) {296/* sampler hardware need offset alignment 64, while render hardware297* need offset alignment 8, but due to render target may be reloaded298* which uses the sampler, set alignment requrement to 64 for all299*/300if (handle->offset & 0x3f) {301debug_error("import buffer offset not properly aligned\n");302return NULL;303}304}305306struct lima_resource *res = CALLOC_STRUCT(lima_resource);307if (!res)308return NULL;309310struct pipe_resource *pres = &res->base;311*pres = *templat;312pres->screen = pscreen;313pipe_reference_init(&pres->reference, 1);314res->levels[0].offset = handle->offset;315res->levels[0].stride = handle->stride;316317struct lima_screen *screen = lima_screen(pscreen);318res->bo = lima_bo_import(screen, handle);319if (!res->bo) {320FREE(res);321return NULL;322}323324res->modifier_constant = true;325326switch (handle->modifier) {327case DRM_FORMAT_MOD_LINEAR:328res->tiled = false;329break;330case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:331res->tiled = true;332break;333case DRM_FORMAT_MOD_INVALID:334/* Modifier wasn't specified and it's shared buffer. We create these335* as linear, so disable tiling.336*/337res->tiled = false;338break;339default:340fprintf(stderr, "Attempted to import unsupported modifier 0x%llx\n",341(long long)handle->modifier);342goto err_out;343}344345/* check alignment for the buffer */346if (res->tiled ||347(pres->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL))) {348unsigned width, height, stride, size;349350width = align(pres->width0, 16);351height = align(pres->height0, 16);352stride = util_format_get_stride(pres->format, width);353size = util_format_get_2d_size(pres->format, stride, height);354355if (res->tiled && res->levels[0].stride != stride) {356fprintf(stderr, "tiled imported buffer has mismatching stride: %d (BO) != %d (expected)",357res->levels[0].stride, stride);358goto err_out;359}360361if (!res->tiled && (res->levels[0].stride % 8)) {362fprintf(stderr, "linear imported buffer stride is not aligned to 8 bytes: %d\n",363res->levels[0].stride);364}365366if (!res->tiled && res->levels[0].stride < stride) {367fprintf(stderr, "linear imported buffer stride is smaller than minimal: %d (BO) < %d (min)",368res->levels[0].stride, stride);369goto err_out;370}371372if ((res->bo->size - res->levels[0].offset) < size) {373fprintf(stderr, "imported bo size is smaller than expected: %d (BO) < %d (expected)\n",374(res->bo->size - res->levels[0].offset), size);375goto err_out;376}377378res->levels[0].width = width;379}380else381res->levels[0].width = pres->width0;382383if (screen->ro) {384/* Make sure that renderonly has a handle to our buffer in the385* display's fd, so that a later renderonly_get_handle()386* returns correct handles or GEM names.387*/388res->scanout =389renderonly_create_gpu_import_for_resource(pres,390screen->ro,391NULL);392/* ignore failiure to allow importing non-displayable buffer */393}394395return pres;396397err_out:398lima_resource_destroy(pscreen, pres);399return NULL;400}401402static bool403lima_resource_get_handle(struct pipe_screen *pscreen,404struct pipe_context *pctx,405struct pipe_resource *pres,406struct winsys_handle *handle, unsigned usage)407{408struct lima_screen *screen = lima_screen(pscreen);409struct lima_resource *res = lima_resource(pres);410411if (res->tiled)412handle->modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;413else414handle->modifier = DRM_FORMAT_MOD_LINEAR;415416res->modifier_constant = true;417418if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro)419return renderonly_get_handle(res->scanout, handle);420421if (!lima_bo_export(res->bo, handle))422return false;423424handle->offset = res->levels[0].offset;425handle->stride = res->levels[0].stride;426return true;427}428429static bool430lima_resource_get_param(struct pipe_screen *pscreen,431struct pipe_context *pctx,432struct pipe_resource *pres,433unsigned plane, unsigned layer, unsigned level,434enum pipe_resource_param param,435unsigned usage, uint64_t *value)436{437struct lima_resource *res = lima_resource(pres);438439switch (param) {440case PIPE_RESOURCE_PARAM_STRIDE:441*value = res->levels[level].stride;442return true;443case PIPE_RESOURCE_PARAM_OFFSET:444*value = res->levels[level].offset;445return true;446case PIPE_RESOURCE_PARAM_MODIFIER:447if (res->tiled)448*value = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;449else450*value = DRM_FORMAT_MOD_LINEAR;451452return true;453default:454return false;455}456}457458static void459get_scissor_from_box(struct pipe_scissor_state *s,460const struct pipe_box *b, int h)461{462int y = h - (b->y + b->height);463/* region in tile unit */464s->minx = b->x >> 4;465s->miny = y >> 4;466s->maxx = (b->x + b->width + 0xf) >> 4;467s->maxy = (y + b->height + 0xf) >> 4;468}469470static void471get_damage_bound_box(struct pipe_resource *pres,472const struct pipe_box *rects,473unsigned int nrects,474struct pipe_scissor_state *bound)475{476struct pipe_box b = rects[0];477478for (int i = 1; i < nrects; i++)479u_box_union_2d(&b, &b, rects + i);480481int ret = u_box_clip_2d(&b, &b, pres->width0, pres->height0);482if (ret < 0)483memset(bound, 0, sizeof(*bound));484else485get_scissor_from_box(bound, &b, pres->height0);486}487488static void489lima_resource_set_damage_region(struct pipe_screen *pscreen,490struct pipe_resource *pres,491unsigned int nrects,492const struct pipe_box *rects)493{494struct lima_resource *res = lima_resource(pres);495struct lima_damage_region *damage = &res->damage;496int i;497498if (damage->region) {499FREE(damage->region);500damage->region = NULL;501damage->num_region = 0;502}503504if (!nrects)505return;506507/* check full damage508*509* TODO: currently only check if there is any single damage510* region that can cover the full render target; there may511* be some accurate way, but a single window size damage512* region is most of the case from weston513*/514for (i = 0; i < nrects; i++) {515if (rects[i].x <= 0 && rects[i].y <= 0 &&516rects[i].x + rects[i].width >= pres->width0 &&517rects[i].y + rects[i].height >= pres->height0)518return;519}520521struct pipe_scissor_state *bound = &damage->bound;522get_damage_bound_box(pres, rects, nrects, bound);523524damage->region = CALLOC(nrects, sizeof(*damage->region));525if (!damage->region)526return;527528for (i = 0; i < nrects; i++)529get_scissor_from_box(damage->region + i, rects + i,530pres->height0);531532/* is region aligned to tiles? */533damage->aligned = true;534for (i = 0; i < nrects; i++) {535if (rects[i].x & 0xf || rects[i].y & 0xf ||536rects[i].width & 0xf || rects[i].height & 0xf) {537damage->aligned = false;538break;539}540}541542damage->num_region = nrects;543}544545void546lima_resource_screen_init(struct lima_screen *screen)547{548screen->base.resource_create = lima_resource_create;549screen->base.resource_create_with_modifiers = lima_resource_create_with_modifiers;550screen->base.resource_from_handle = lima_resource_from_handle;551screen->base.resource_destroy = lima_resource_destroy;552screen->base.resource_get_handle = lima_resource_get_handle;553screen->base.resource_get_param = lima_resource_get_param;554screen->base.set_damage_region = lima_resource_set_damage_region;555}556557static struct pipe_surface *558lima_surface_create(struct pipe_context *pctx,559struct pipe_resource *pres,560const struct pipe_surface *surf_tmpl)561{562struct lima_surface *surf = CALLOC_STRUCT(lima_surface);563564if (!surf)565return NULL;566567assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);568569struct pipe_surface *psurf = &surf->base;570unsigned level = surf_tmpl->u.tex.level;571572pipe_reference_init(&psurf->reference, 1);573pipe_resource_reference(&psurf->texture, pres);574575psurf->context = pctx;576psurf->format = surf_tmpl->format;577psurf->width = u_minify(pres->width0, level);578psurf->height = u_minify(pres->height0, level);579psurf->u.tex.level = level;580psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;581psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;582583surf->tiled_w = align(psurf->width, 16) >> 4;584surf->tiled_h = align(psurf->height, 16) >> 4;585586surf->reload = 0;587if (util_format_has_stencil(util_format_description(psurf->format)))588surf->reload |= PIPE_CLEAR_STENCIL;589if (util_format_has_depth(util_format_description(psurf->format)))590surf->reload |= PIPE_CLEAR_DEPTH;591if (!util_format_is_depth_or_stencil(psurf->format))592surf->reload |= PIPE_CLEAR_COLOR0;593594return &surf->base;595}596597static void598lima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)599{600struct lima_surface *surf = lima_surface(psurf);601602pipe_resource_reference(&psurf->texture, NULL);603FREE(surf);604}605606static void *607lima_transfer_map(struct pipe_context *pctx,608struct pipe_resource *pres,609unsigned level,610unsigned usage,611const struct pipe_box *box,612struct pipe_transfer **pptrans)613{614struct lima_screen *screen = lima_screen(pres->screen);615struct lima_context *ctx = lima_context(pctx);616struct lima_resource *res = lima_resource(pres);617struct lima_bo *bo = res->bo;618struct lima_transfer *trans;619struct pipe_transfer *ptrans;620621/* No direct mappings of tiled, since we need to manually622* tile/untile.623*/624if (res->tiled && (usage & PIPE_MAP_DIRECTLY))625return NULL;626627/* bo might be in use in a previous stream draw. Allocate a new628* one for the resource to avoid overwriting data in use. */629if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {630struct lima_bo *new_bo;631assert(res->bo && res->bo->size);632633new_bo = lima_bo_create(screen, res->bo->size, res->bo->flags);634if (!new_bo)635return NULL;636637lima_bo_unreference(res->bo);638res->bo = new_bo;639640if (pres->bind & PIPE_BIND_VERTEX_BUFFER)641ctx->dirty |= LIMA_CONTEXT_DIRTY_VERTEX_BUFF;642643bo = res->bo;644}645else if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&646(usage & PIPE_MAP_READ_WRITE)) {647/* use once buffers are made sure to not read/write overlapped648* range, so no need to sync */649lima_flush_job_accessing_bo(ctx, bo, usage & PIPE_MAP_WRITE);650651unsigned op = usage & PIPE_MAP_WRITE ?652LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ;653lima_bo_wait(bo, op, PIPE_TIMEOUT_INFINITE);654}655656if (!lima_bo_map(bo))657return NULL;658659trans = slab_alloc(&ctx->transfer_pool);660if (!trans)661return NULL;662663memset(trans, 0, sizeof(*trans));664ptrans = &trans->base;665666pipe_resource_reference(&ptrans->resource, pres);667ptrans->level = level;668ptrans->usage = usage;669ptrans->box = *box;670671*pptrans = ptrans;672673if (res->tiled) {674ptrans->stride = util_format_get_stride(pres->format, ptrans->box.width);675ptrans->layer_stride = ptrans->stride * ptrans->box.height;676677trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth);678679if (usage & PIPE_MAP_READ) {680unsigned i;681for (i = 0; i < ptrans->box.depth; i++)682panfrost_load_tiled_image(683trans->staging + i * ptrans->stride * ptrans->box.height,684bo->map + res->levels[level].offset + (i + box->z) * res->levels[level].layer_stride,685ptrans->box.x, ptrans->box.y,686ptrans->box.width, ptrans->box.height,687ptrans->stride,688res->levels[level].stride,689pres->format);690}691692return trans->staging;693} else {694unsigned dpw = PIPE_MAP_DIRECTLY | PIPE_MAP_WRITE |695PIPE_MAP_PERSISTENT;696if ((usage & dpw) == dpw && res->index_cache)697return NULL;698699ptrans->stride = res->levels[level].stride;700ptrans->layer_stride = res->levels[level].layer_stride;701702if ((usage & PIPE_MAP_WRITE) && (usage & PIPE_MAP_DIRECTLY))703panfrost_minmax_cache_invalidate(res->index_cache, ptrans);704705return bo->map + res->levels[level].offset +706box->z * res->levels[level].layer_stride +707box->y / util_format_get_blockheight(pres->format) * ptrans->stride +708box->x / util_format_get_blockwidth(pres->format) *709util_format_get_blocksize(pres->format);710}711}712713static void714lima_transfer_flush_region(struct pipe_context *pctx,715struct pipe_transfer *ptrans,716const struct pipe_box *box)717{718719}720721static bool722lima_should_convert_linear(struct lima_resource *res,723struct pipe_transfer *ptrans)724{725if (res->modifier_constant)726return false;727728/* Overwriting the entire resource indicates streaming, for which729* linear layout is most efficient due to the lack of expensive730* conversion.731*732* For now we just switch to linear after a number of complete733* overwrites to keep things simple, but we could do better.734*/735736unsigned depth = res->base.target == PIPE_TEXTURE_3D ?737res->base.depth0 : res->base.array_size;738bool entire_overwrite =739res->base.last_level == 0 &&740ptrans->box.width == res->base.width0 &&741ptrans->box.height == res->base.height0 &&742ptrans->box.depth == depth &&743ptrans->box.x == 0 &&744ptrans->box.y == 0 &&745ptrans->box.z == 0;746747if (entire_overwrite)748++res->full_updates;749750return res->full_updates >= LAYOUT_CONVERT_THRESHOLD;751}752753static void754lima_transfer_unmap_inner(struct lima_context *ctx,755struct pipe_transfer *ptrans)756{757struct lima_resource *res = lima_resource(ptrans->resource);758struct lima_transfer *trans = lima_transfer(ptrans);759struct lima_bo *bo = res->bo;760struct pipe_resource *pres;761762if (trans->staging) {763pres = &res->base;764if (trans->base.usage & PIPE_MAP_WRITE) {765unsigned i;766if (lima_should_convert_linear(res, ptrans)) {767/* It's safe to re-use the same BO since tiled BO always has768* aligned dimensions */769for (i = 0; i < trans->base.box.depth; i++) {770util_copy_rect(bo->map + res->levels[0].offset +771(i + trans->base.box.z) * res->levels[0].stride,772res->base.format,773res->levels[0].stride,7740, 0,775ptrans->box.width,776ptrans->box.height,777trans->staging + i * ptrans->stride * ptrans->box.height,778ptrans->stride,7790, 0);780}781res->tiled = false;782res->modifier_constant = true;783/* Update texture descriptor */784ctx->dirty |= LIMA_CONTEXT_DIRTY_TEXTURES;785} else {786for (i = 0; i < trans->base.box.depth; i++)787panfrost_store_tiled_image(788bo->map + res->levels[trans->base.level].offset + (i + trans->base.box.z) * res->levels[trans->base.level].layer_stride,789trans->staging + i * ptrans->stride * ptrans->box.height,790ptrans->box.x, ptrans->box.y,791ptrans->box.width, ptrans->box.height,792res->levels[ptrans->level].stride,793ptrans->stride,794pres->format);795}796}797}798}799800static void801lima_transfer_unmap(struct pipe_context *pctx,802struct pipe_transfer *ptrans)803{804struct lima_context *ctx = lima_context(pctx);805struct lima_transfer *trans = lima_transfer(ptrans);806struct lima_resource *res = lima_resource(ptrans->resource);807808lima_transfer_unmap_inner(ctx, ptrans);809if (trans->staging)810free(trans->staging);811panfrost_minmax_cache_invalidate(res->index_cache, ptrans);812813pipe_resource_reference(&ptrans->resource, NULL);814slab_free(&ctx->transfer_pool, trans);815}816817static void818lima_util_blitter_save_states(struct lima_context *ctx)819{820util_blitter_save_blend(ctx->blitter, (void *)ctx->blend);821util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->zsa);822util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);823util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer);824util_blitter_save_fragment_shader(ctx->blitter, ctx->uncomp_fs);825util_blitter_save_vertex_shader(ctx->blitter, ctx->uncomp_vs);826util_blitter_save_viewport(ctx->blitter,827&ctx->viewport.transform);828util_blitter_save_scissor(ctx->blitter, &ctx->scissor);829util_blitter_save_vertex_elements(ctx->blitter,830ctx->vertex_elements);831util_blitter_save_vertex_buffer_slot(ctx->blitter,832ctx->vertex_buffers.vb);833834util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base);835836util_blitter_save_fragment_sampler_states(ctx->blitter,837ctx->tex_stateobj.num_samplers,838(void**)ctx->tex_stateobj.samplers);839util_blitter_save_fragment_sampler_views(ctx->blitter,840ctx->tex_stateobj.num_textures,841ctx->tex_stateobj.textures);842}843844static void845lima_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)846{847struct lima_context *ctx = lima_context(pctx);848struct pipe_blit_info info = *blit_info;849850if (util_try_blit_via_copy_region(pctx, &info)) {851return; /* done */852}853854if (info.mask & PIPE_MASK_S) {855debug_printf("lima: cannot blit stencil, skipping\n");856info.mask &= ~PIPE_MASK_S;857}858859if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {860debug_printf("lima: blit unsupported %s -> %s\n",861util_format_short_name(info.src.resource->format),862util_format_short_name(info.dst.resource->format));863return;864}865866lima_util_blitter_save_states(ctx);867868util_blitter_blit(ctx->blitter, &info);869}870871static void872lima_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)873{874875}876877static void878lima_texture_subdata(struct pipe_context *pctx,879struct pipe_resource *prsc,880unsigned level,881unsigned usage,882const struct pipe_box *box,883const void *data,884unsigned stride,885unsigned layer_stride)886{887struct lima_context *ctx = lima_context(pctx);888struct lima_resource *res = lima_resource(prsc);889890if (!res->tiled) {891u_default_texture_subdata(pctx, prsc, level, usage, box,892data, stride, layer_stride);893return;894}895896assert(!(usage & PIPE_MAP_READ));897898struct lima_transfer t = {899.base = {900.resource = prsc,901.usage = PIPE_MAP_WRITE,902.level = level,903.box = *box,904.stride = stride,905.layer_stride = layer_stride,906},907.staging = (void *)data,908};909910lima_flush_job_accessing_bo(ctx, res->bo, true);911lima_bo_wait(res->bo, LIMA_GEM_WAIT_WRITE, PIPE_TIMEOUT_INFINITE);912if (!lima_bo_map(res->bo))913return;914915lima_transfer_unmap_inner(ctx, &t.base);916}917918void919lima_resource_context_init(struct lima_context *ctx)920{921ctx->base.create_surface = lima_surface_create;922ctx->base.surface_destroy = lima_surface_destroy;923924ctx->base.buffer_subdata = u_default_buffer_subdata;925ctx->base.texture_subdata = lima_texture_subdata;926/* TODO: optimize resource_copy_region to do copy directly927* between 2 tiled or tiled and linear resources instead of928* using staging buffer.929*/930ctx->base.resource_copy_region = util_resource_copy_region;931932ctx->base.blit = lima_blit;933934ctx->base.buffer_map = lima_transfer_map;935ctx->base.texture_map = lima_transfer_map;936ctx->base.transfer_flush_region = lima_transfer_flush_region;937ctx->base.buffer_unmap = lima_transfer_unmap;938ctx->base.texture_unmap = lima_transfer_unmap;939940ctx->base.flush_resource = lima_flush_resource;941}942943944