Path: blob/21.2-virgl/src/gallium/drivers/vc4/vc4_resource.c
4570 views
/*1* Copyright © 2014 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/u_drm.h"3233#include "drm-uapi/drm_fourcc.h"34#include "drm-uapi/vc4_drm.h"35#include "vc4_screen.h"36#include "vc4_context.h"37#include "vc4_resource.h"38#include "vc4_tiling.h"3940static bool41vc4_resource_bo_alloc(struct vc4_resource *rsc)42{43struct pipe_resource *prsc = &rsc->base;44struct pipe_screen *pscreen = prsc->screen;45struct vc4_bo *bo;4647if (vc4_debug & VC4_DEBUG_SURFACE) {48fprintf(stderr, "alloc %p: size %d + offset %d -> %d\n",49rsc,50rsc->slices[0].size,51rsc->slices[0].offset,52rsc->slices[0].offset +53rsc->slices[0].size +54rsc->cube_map_stride * (prsc->array_size - 1));55}5657bo = vc4_bo_alloc(vc4_screen(pscreen),58rsc->slices[0].offset +59rsc->slices[0].size +60rsc->cube_map_stride * (prsc->array_size - 1),61"resource");62if (bo) {63vc4_bo_unreference(&rsc->bo);64rsc->bo = bo;65return true;66} else {67return false;68}69}7071static void72vc4_resource_transfer_unmap(struct pipe_context *pctx,73struct pipe_transfer *ptrans)74{75struct vc4_context *vc4 = vc4_context(pctx);76struct vc4_transfer *trans = vc4_transfer(ptrans);7778if (trans->map) {79struct vc4_resource *rsc = vc4_resource(ptrans->resource);80struct vc4_resource_slice *slice = &rsc->slices[ptrans->level];8182if (ptrans->usage & PIPE_MAP_WRITE) {83vc4_store_tiled_image(rsc->bo->map + slice->offset +84ptrans->box.z * rsc->cube_map_stride,85slice->stride,86trans->map, ptrans->stride,87slice->tiling, rsc->cpp,88&ptrans->box);89}90free(trans->map);91}9293pipe_resource_reference(&ptrans->resource, NULL);94slab_free(&vc4->transfer_pool, ptrans);95}9697static void *98vc4_resource_transfer_map(struct pipe_context *pctx,99struct pipe_resource *prsc,100unsigned level, unsigned usage,101const struct pipe_box *box,102struct pipe_transfer **pptrans)103{104struct vc4_context *vc4 = vc4_context(pctx);105struct vc4_resource *rsc = vc4_resource(prsc);106struct vc4_transfer *trans;107struct pipe_transfer *ptrans;108enum pipe_format format = prsc->format;109char *buf;110111/* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is112* being mapped.113*/114if ((usage & PIPE_MAP_DISCARD_RANGE) &&115!(usage & PIPE_MAP_UNSYNCHRONIZED) &&116!(prsc->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) &&117prsc->last_level == 0 &&118prsc->width0 == box->width &&119prsc->height0 == box->height &&120prsc->depth0 == box->depth &&121prsc->array_size == 1 &&122rsc->bo->private) {123usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;124}125126if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {127if (vc4_resource_bo_alloc(rsc)) {128/* If it might be bound as one of our vertex buffers,129* make sure we re-emit vertex buffer state.130*/131if (prsc->bind & PIPE_BIND_VERTEX_BUFFER)132vc4->dirty |= VC4_DIRTY_VTXBUF;133} else {134/* If we failed to reallocate, flush users so that we135* don't violate any syncing requirements.136*/137vc4_flush_jobs_reading_resource(vc4, prsc);138}139} else if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {140/* If we're writing and the buffer is being used by the CL, we141* have to flush the CL first. If we're only reading, we need142* to flush if the CL has written our buffer.143*/144if (usage & PIPE_MAP_WRITE)145vc4_flush_jobs_reading_resource(vc4, prsc);146else147vc4_flush_jobs_writing_resource(vc4, prsc);148}149150if (usage & PIPE_MAP_WRITE) {151rsc->writes++;152rsc->initialized_buffers = ~0;153}154155trans = slab_alloc(&vc4->transfer_pool);156if (!trans)157return NULL;158159/* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */160161/* slab_alloc_st() doesn't zero: */162memset(trans, 0, sizeof(*trans));163ptrans = &trans->base;164165pipe_resource_reference(&ptrans->resource, prsc);166ptrans->level = level;167ptrans->usage = usage;168ptrans->box = *box;169170if (usage & PIPE_MAP_UNSYNCHRONIZED)171buf = vc4_bo_map_unsynchronized(rsc->bo);172else173buf = vc4_bo_map(rsc->bo);174if (!buf) {175fprintf(stderr, "Failed to map bo\n");176goto fail;177}178179*pptrans = ptrans;180181struct vc4_resource_slice *slice = &rsc->slices[level];182if (rsc->tiled) {183/* No direct mappings of tiled, since we need to manually184* tile/untile.185*/186if (usage & PIPE_MAP_DIRECTLY)187return NULL;188189if (format == PIPE_FORMAT_ETC1_RGB8) {190/* ETC1 is arranged as 64-bit blocks, where each block191* is 4x4 pixels. Texture tiling operates on the192* 64-bit block the way it would an uncompressed193* pixels.194*/195assert(!(ptrans->box.x & 3));196assert(!(ptrans->box.y & 3));197ptrans->box.x >>= 2;198ptrans->box.y >>= 2;199ptrans->box.width = (ptrans->box.width + 3) >> 2;200ptrans->box.height = (ptrans->box.height + 3) >> 2;201}202203ptrans->stride = ptrans->box.width * rsc->cpp;204ptrans->layer_stride = ptrans->stride * ptrans->box.height;205206trans->map = malloc(ptrans->layer_stride * ptrans->box.depth);207208if (usage & PIPE_MAP_READ) {209vc4_load_tiled_image(trans->map, ptrans->stride,210buf + slice->offset +211ptrans->box.z * rsc->cube_map_stride,212slice->stride,213slice->tiling, rsc->cpp,214&ptrans->box);215}216return trans->map;217} else {218ptrans->stride = slice->stride;219ptrans->layer_stride = ptrans->stride;220221return buf + slice->offset +222ptrans->box.y / util_format_get_blockheight(format) * ptrans->stride +223ptrans->box.x / util_format_get_blockwidth(format) * rsc->cpp +224ptrans->box.z * rsc->cube_map_stride;225}226227228fail:229vc4_resource_transfer_unmap(pctx, ptrans);230return NULL;231}232233static void234vc4_texture_subdata(struct pipe_context *pctx,235struct pipe_resource *prsc,236unsigned level,237unsigned usage,238const struct pipe_box *box,239const void *data,240unsigned stride,241unsigned layer_stride)242{243struct vc4_resource *rsc = vc4_resource(prsc);244struct vc4_resource_slice *slice = &rsc->slices[level];245246/* For a direct mapping, we can just take the u_transfer path. */247if (!rsc->tiled ||248box->depth != 1 ||249(usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE)) {250return u_default_texture_subdata(pctx, prsc, level, usage, box,251data, stride, layer_stride);252}253254/* Otherwise, map and store the texture data directly into the tiled255* texture.256*/257void *buf;258if (usage & PIPE_MAP_UNSYNCHRONIZED)259buf = vc4_bo_map_unsynchronized(rsc->bo);260else261buf = vc4_bo_map(rsc->bo);262263vc4_store_tiled_image(buf + slice->offset +264box->z * rsc->cube_map_stride,265slice->stride,266(void *)data, stride,267slice->tiling, rsc->cpp,268box);269}270271static void272vc4_resource_destroy(struct pipe_screen *pscreen,273struct pipe_resource *prsc)274{275struct vc4_screen *screen = vc4_screen(pscreen);276struct vc4_resource *rsc = vc4_resource(prsc);277vc4_bo_unreference(&rsc->bo);278279if (rsc->scanout)280renderonly_scanout_destroy(rsc->scanout, screen->ro);281282free(rsc);283}284285static bool286vc4_resource_get_handle(struct pipe_screen *pscreen,287struct pipe_context *pctx,288struct pipe_resource *prsc,289struct winsys_handle *whandle,290unsigned usage)291{292struct vc4_screen *screen = vc4_screen(pscreen);293struct vc4_resource *rsc = vc4_resource(prsc);294295whandle->stride = rsc->slices[0].stride;296whandle->offset = 0;297298/* If we're passing some reference to our BO out to some other part of299* the system, then we can't do any optimizations about only us being300* the ones seeing it (like BO caching or shadow update avoidance).301*/302rsc->bo->private = false;303304if (rsc->tiled)305whandle->modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED;306else307whandle->modifier = DRM_FORMAT_MOD_LINEAR;308309switch (whandle->type) {310case WINSYS_HANDLE_TYPE_SHARED:311if (screen->ro) {312/* This could probably be supported, assuming that a313* control node was used for pl111.314*/315fprintf(stderr, "flink unsupported with pl111\n");316return false;317}318319return vc4_bo_flink(rsc->bo, &whandle->handle);320case WINSYS_HANDLE_TYPE_KMS:321if (screen->ro) {322return renderonly_get_handle(rsc->scanout, whandle);323}324whandle->handle = rsc->bo->handle;325return true;326case WINSYS_HANDLE_TYPE_FD:327/* FDs are cross-device, so we can export directly from vc4.328*/329whandle->handle = vc4_bo_get_dmabuf(rsc->bo);330return whandle->handle != -1;331}332333return false;334}335336static void337vc4_setup_slices(struct vc4_resource *rsc, const char *caller)338{339struct pipe_resource *prsc = &rsc->base;340uint32_t width = prsc->width0;341uint32_t height = prsc->height0;342if (prsc->format == PIPE_FORMAT_ETC1_RGB8) {343width = (width + 3) >> 2;344height = (height + 3) >> 2;345}346347uint32_t pot_width = util_next_power_of_two(width);348uint32_t pot_height = util_next_power_of_two(height);349uint32_t offset = 0;350uint32_t utile_w = vc4_utile_width(rsc->cpp);351uint32_t utile_h = vc4_utile_height(rsc->cpp);352353for (int i = prsc->last_level; i >= 0; i--) {354struct vc4_resource_slice *slice = &rsc->slices[i];355356uint32_t level_width, level_height;357if (i == 0) {358level_width = width;359level_height = height;360} else {361level_width = u_minify(pot_width, i);362level_height = u_minify(pot_height, i);363}364365if (!rsc->tiled) {366slice->tiling = VC4_TILING_FORMAT_LINEAR;367if (prsc->nr_samples > 1) {368/* MSAA (4x) surfaces are stored as raw tile buffer contents. */369level_width = align(level_width, 32);370level_height = align(level_height, 32);371} else {372level_width = align(level_width, utile_w);373}374} else {375if (vc4_size_is_lt(level_width, level_height,376rsc->cpp)) {377slice->tiling = VC4_TILING_FORMAT_LT;378level_width = align(level_width, utile_w);379level_height = align(level_height, utile_h);380} else {381slice->tiling = VC4_TILING_FORMAT_T;382level_width = align(level_width,3834 * 2 * utile_w);384level_height = align(level_height,3854 * 2 * utile_h);386}387}388389slice->offset = offset;390slice->stride = (level_width * rsc->cpp *391MAX2(prsc->nr_samples, 1));392slice->size = level_height * slice->stride;393394offset += slice->size;395396if (vc4_debug & VC4_DEBUG_SURFACE) {397static const char tiling_chars[] = {398[VC4_TILING_FORMAT_LINEAR] = 'R',399[VC4_TILING_FORMAT_LT] = 'L',400[VC4_TILING_FORMAT_T] = 'T'401};402fprintf(stderr,403"rsc %s %p (format %s: vc4 %d), %dx%d: "404"level %d (%c) -> %dx%d, stride %d@0x%08x\n",405caller, rsc,406util_format_short_name(prsc->format),407rsc->vc4_format,408prsc->width0, prsc->height0,409i, tiling_chars[slice->tiling],410level_width, level_height,411slice->stride, slice->offset);412}413}414415/* The texture base pointer that has to point to level 0 doesn't have416* intra-page bits, so we have to align it, and thus shift up all the417* smaller slices.418*/419uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -420rsc->slices[0].offset);421if (page_align_offset) {422for (int i = 0; i <= prsc->last_level; i++)423rsc->slices[i].offset += page_align_offset;424}425426/* Cube map faces appear as whole miptrees at a page-aligned offset427* from the first face's miptree.428*/429if (prsc->target == PIPE_TEXTURE_CUBE) {430rsc->cube_map_stride = align(rsc->slices[0].offset +431rsc->slices[0].size, 4096);432}433}434435static struct vc4_resource *436vc4_resource_setup(struct pipe_screen *pscreen,437const struct pipe_resource *tmpl)438{439struct vc4_resource *rsc = CALLOC_STRUCT(vc4_resource);440if (!rsc)441return NULL;442struct pipe_resource *prsc = &rsc->base;443444*prsc = *tmpl;445446pipe_reference_init(&prsc->reference, 1);447prsc->screen = pscreen;448449if (prsc->nr_samples <= 1)450rsc->cpp = util_format_get_blocksize(tmpl->format);451else452rsc->cpp = sizeof(uint32_t);453454assert(rsc->cpp);455456return rsc;457}458459static enum vc4_texture_data_type460get_resource_texture_format(struct pipe_resource *prsc)461{462struct vc4_resource *rsc = vc4_resource(prsc);463uint8_t format = vc4_get_tex_format(prsc->format);464465if (!rsc->tiled) {466if (prsc->nr_samples > 1) {467return ~0;468} else {469if (format == VC4_TEXTURE_TYPE_RGBA8888)470return VC4_TEXTURE_TYPE_RGBA32R;471else472return ~0;473}474}475476return format;477}478479static struct pipe_resource *480vc4_resource_create_with_modifiers(struct pipe_screen *pscreen,481const struct pipe_resource *tmpl,482const uint64_t *modifiers,483int count)484{485struct vc4_screen *screen = vc4_screen(pscreen);486struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);487struct pipe_resource *prsc = &rsc->base;488bool linear_ok = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);489/* Use a tiled layout if we can, for better 3D performance. */490bool should_tile = true;491492/* VBOs/PBOs are untiled (and 1 height). */493if (tmpl->target == PIPE_BUFFER)494should_tile = false;495496/* MSAA buffers are linear. */497if (tmpl->nr_samples > 1)498should_tile = false;499500/* No tiling when we're sharing with another device (pl111). */501if (screen->ro && (tmpl->bind & PIPE_BIND_SCANOUT))502should_tile = false;503504/* Cursors are always linear, and the user can request linear as well.505*/506if (tmpl->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))507should_tile = false;508509/* No shared objects with LT format -- the kernel only has T-format510* metadata. LT objects are small enough it's not worth the trouble to511* give them metadata to tile.512*/513if ((tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT)) &&514vc4_size_is_lt(prsc->width0, prsc->height0, rsc->cpp))515should_tile = false;516517/* If we're sharing or scanning out, we need the ioctl present to518* inform the kernel or the other side.519*/520if ((tmpl->bind & (PIPE_BIND_SHARED |521PIPE_BIND_SCANOUT)) && !screen->has_tiling_ioctl)522should_tile = false;523524/* No user-specified modifier; determine our own. */525if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {526linear_ok = true;527rsc->tiled = should_tile;528} else if (should_tile &&529drm_find_modifier(DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,530modifiers, count)) {531rsc->tiled = true;532} else if (linear_ok) {533rsc->tiled = false;534} else {535fprintf(stderr, "Unsupported modifier requested\n");536return NULL;537}538539if (tmpl->target != PIPE_BUFFER)540rsc->vc4_format = get_resource_texture_format(prsc);541542vc4_setup_slices(rsc, "create");543if (!vc4_resource_bo_alloc(rsc))544goto fail;545546if (screen->has_tiling_ioctl) {547uint64_t modifier;548if (rsc->tiled)549modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED;550else551modifier = DRM_FORMAT_MOD_LINEAR;552struct drm_vc4_set_tiling set_tiling = {553.handle = rsc->bo->handle,554.modifier = modifier,555};556int ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_SET_TILING,557&set_tiling);558if (ret != 0)559goto fail;560}561562/* Set up the "scanout resource" (the dmabuf export of our buffer to563* the KMS handle) if the buffer might ever have564* resource_get_handle(WINSYS_HANDLE_TYPE_KMS) called on it.565* create_with_modifiers() doesn't give us usage flags, so we have to566* assume that all calls with modifiers are scanout-possible.567*/568if (screen->ro &&569((tmpl->bind & PIPE_BIND_SCANOUT) ||570!(count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID))) {571rsc->scanout =572renderonly_scanout_for_resource(prsc, screen->ro, NULL);573if (!rsc->scanout)574goto fail;575}576577vc4_bo_label(screen, rsc->bo, "%sresource %dx%d@%d/%d",578(tmpl->bind & PIPE_BIND_SCANOUT) ? "scanout " : "",579tmpl->width0, tmpl->height0,580rsc->cpp * 8, prsc->last_level);581582return prsc;583fail:584vc4_resource_destroy(pscreen, prsc);585return NULL;586}587588struct pipe_resource *589vc4_resource_create(struct pipe_screen *pscreen,590const struct pipe_resource *tmpl)591{592const uint64_t mod = DRM_FORMAT_MOD_INVALID;593return vc4_resource_create_with_modifiers(pscreen, tmpl, &mod, 1);594}595596static struct pipe_resource *597vc4_resource_from_handle(struct pipe_screen *pscreen,598const struct pipe_resource *tmpl,599struct winsys_handle *whandle,600unsigned usage)601{602struct vc4_screen *screen = vc4_screen(pscreen);603struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);604struct pipe_resource *prsc = &rsc->base;605struct vc4_resource_slice *slice = &rsc->slices[0];606607if (!rsc)608return NULL;609610switch (whandle->type) {611case WINSYS_HANDLE_TYPE_SHARED:612rsc->bo = vc4_bo_open_name(screen, whandle->handle);613break;614case WINSYS_HANDLE_TYPE_FD:615rsc->bo = vc4_bo_open_dmabuf(screen, whandle->handle);616break;617default:618fprintf(stderr,619"Attempt to import unsupported handle type %d\n",620whandle->type);621}622623if (!rsc->bo)624goto fail;625626struct drm_vc4_get_tiling get_tiling = {627.handle = rsc->bo->handle,628};629int ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling);630631if (ret != 0) {632whandle->modifier = DRM_FORMAT_MOD_LINEAR;633} else if (whandle->modifier == DRM_FORMAT_MOD_INVALID) {634whandle->modifier = get_tiling.modifier;635} else if (whandle->modifier != get_tiling.modifier) {636fprintf(stderr,637"Modifier 0x%llx vs. tiling (0x%llx) mismatch\n",638(long long)whandle->modifier, get_tiling.modifier);639goto fail;640}641642switch (whandle->modifier) {643case DRM_FORMAT_MOD_LINEAR:644rsc->tiled = false;645break;646case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:647rsc->tiled = true;648break;649default:650fprintf(stderr,651"Attempt to import unsupported modifier 0x%llx\n",652(long long)whandle->modifier);653goto fail;654}655656rsc->vc4_format = get_resource_texture_format(prsc);657vc4_setup_slices(rsc, "import");658659if (whandle->offset != 0) {660if (rsc->tiled) {661fprintf(stderr,662"Attempt to import unsupported "663"winsys offset %u\n",664whandle->offset);665goto fail;666}667668rsc->slices[0].offset += whandle->offset;669670if (rsc->slices[0].offset + rsc->slices[0].size >671rsc->bo->size) {672fprintf(stderr, "Attempt to import "673"with overflowing offset (%d + %d > %d)\n",674whandle->offset,675rsc->slices[0].size,676rsc->bo->size);677goto fail;678}679}680681if (screen->ro) {682/* Make sure that renderonly has a handle to our buffer in the683* display's fd, so that a later renderonly_get_handle()684* returns correct handles or GEM names.685*/686rsc->scanout =687renderonly_create_gpu_import_for_resource(prsc,688screen->ro,689NULL);690}691692if (rsc->tiled && whandle->stride != slice->stride) {693static bool warned = false;694if (!warned) {695warned = true;696fprintf(stderr,697"Attempting to import %dx%d %s with "698"unsupported stride %d instead of %d\n",699prsc->width0, prsc->height0,700util_format_short_name(prsc->format),701whandle->stride,702slice->stride);703}704goto fail;705} else if (!rsc->tiled) {706slice->stride = whandle->stride;707}708709return prsc;710711fail:712vc4_resource_destroy(pscreen, prsc);713return NULL;714}715716static struct pipe_surface *717vc4_create_surface(struct pipe_context *pctx,718struct pipe_resource *ptex,719const struct pipe_surface *surf_tmpl)720{721struct vc4_surface *surface = CALLOC_STRUCT(vc4_surface);722struct vc4_resource *rsc = vc4_resource(ptex);723724if (!surface)725return NULL;726727assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);728729struct pipe_surface *psurf = &surface->base;730unsigned level = surf_tmpl->u.tex.level;731732pipe_reference_init(&psurf->reference, 1);733pipe_resource_reference(&psurf->texture, ptex);734735psurf->context = pctx;736psurf->format = surf_tmpl->format;737psurf->width = u_minify(ptex->width0, level);738psurf->height = u_minify(ptex->height0, level);739psurf->u.tex.level = level;740psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;741psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;742surface->offset = (rsc->slices[level].offset +743psurf->u.tex.first_layer * rsc->cube_map_stride);744surface->tiling = rsc->slices[level].tiling;745746return &surface->base;747}748749static void750vc4_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)751{752pipe_resource_reference(&psurf->texture, NULL);753FREE(psurf);754}755756static void757vc4_dump_surface_non_msaa(struct pipe_surface *psurf)758{759struct pipe_resource *prsc = psurf->texture;760struct vc4_resource *rsc = vc4_resource(prsc);761uint32_t *map = vc4_bo_map(rsc->bo);762uint32_t stride = rsc->slices[0].stride / 4;763uint32_t width = psurf->width;764uint32_t height = psurf->height;765uint32_t chunk_w = width / 79;766uint32_t chunk_h = height / 40;767uint32_t found_colors[10] = { 0 };768uint32_t num_found_colors = 0;769770if (rsc->vc4_format != VC4_TEXTURE_TYPE_RGBA32R) {771fprintf(stderr, "%s: Unsupported format %s\n",772__func__, util_format_short_name(psurf->format));773return;774}775776for (int by = 0; by < height; by += chunk_h) {777for (int bx = 0; bx < width; bx += chunk_w) {778int all_found_color = -1; /* nothing found */779780for (int y = by; y < MIN2(height, by + chunk_h); y++) {781for (int x = bx; x < MIN2(width, bx + chunk_w); x++) {782uint32_t pix = map[y * stride + x];783784int i;785for (i = 0; i < num_found_colors; i++) {786if (pix == found_colors[i])787break;788}789if (i == num_found_colors &&790num_found_colors <791ARRAY_SIZE(found_colors)) {792found_colors[num_found_colors++] = pix;793}794795if (i < num_found_colors) {796if (all_found_color == -1)797all_found_color = i;798else if (i != all_found_color)799all_found_color = ARRAY_SIZE(found_colors);800}801}802}803/* If all pixels for this chunk have a consistent804* value, then print a character for it. Either a805* fixed name (particularly common for piglit tests),806* or a runtime-generated number.807*/808if (all_found_color >= 0 &&809all_found_color < ARRAY_SIZE(found_colors)) {810static const struct {811uint32_t val;812const char *c;813} named_colors[] = {814{ 0xff000000, "█" },815{ 0x00000000, "█" },816{ 0xffff0000, "r" },817{ 0xff00ff00, "g" },818{ 0xff0000ff, "b" },819{ 0xffffffff, "w" },820};821int i;822for (i = 0; i < ARRAY_SIZE(named_colors); i++) {823if (named_colors[i].val ==824found_colors[all_found_color]) {825fprintf(stderr, "%s",826named_colors[i].c);827break;828}829}830/* For unnamed colors, print a number and the831* numbers will have values printed at the832* end.833*/834if (i == ARRAY_SIZE(named_colors)) {835fprintf(stderr, "%c",836'0' + all_found_color);837}838} else {839/* If there's no consistent color, print this.840*/841fprintf(stderr, ".");842}843}844fprintf(stderr, "\n");845}846847for (int i = 0; i < num_found_colors; i++) {848fprintf(stderr, "color %d: 0x%08x\n", i, found_colors[i]);849}850}851852static uint32_t853vc4_surface_msaa_get_sample(struct pipe_surface *psurf,854uint32_t x, uint32_t y, uint32_t sample)855{856struct pipe_resource *prsc = psurf->texture;857struct vc4_resource *rsc = vc4_resource(prsc);858uint32_t tile_w = 32, tile_h = 32;859uint32_t tiles_w = DIV_ROUND_UP(psurf->width, 32);860861uint32_t tile_x = x / tile_w;862uint32_t tile_y = y / tile_h;863uint32_t *tile = (vc4_bo_map(rsc->bo) +864VC4_TILE_BUFFER_SIZE * (tile_y * tiles_w + tile_x));865uint32_t subtile_x = x % tile_w;866uint32_t subtile_y = y % tile_h;867868uint32_t quad_samples = VC4_MAX_SAMPLES * 4;869uint32_t tile_stride = quad_samples * tile_w / 2;870871return *((uint32_t *)tile +872(subtile_y >> 1) * tile_stride +873(subtile_x >> 1) * quad_samples +874((subtile_y & 1) << 1) +875(subtile_x & 1) +876sample);877}878879static void880vc4_dump_surface_msaa_char(struct pipe_surface *psurf,881uint32_t start_x, uint32_t start_y,882uint32_t w, uint32_t h)883{884bool all_same_color = true;885uint32_t all_pix = 0;886887for (int y = start_y; y < start_y + h; y++) {888for (int x = start_x; x < start_x + w; x++) {889for (int s = 0; s < VC4_MAX_SAMPLES; s++) {890uint32_t pix = vc4_surface_msaa_get_sample(psurf,891x, y,892s);893if (x == start_x && y == start_y)894all_pix = pix;895else if (all_pix != pix)896all_same_color = false;897}898}899}900if (all_same_color) {901static const struct {902uint32_t val;903const char *c;904} named_colors[] = {905{ 0xff000000, "█" },906{ 0x00000000, "█" },907{ 0xffff0000, "r" },908{ 0xff00ff00, "g" },909{ 0xff0000ff, "b" },910{ 0xffffffff, "w" },911};912int i;913for (i = 0; i < ARRAY_SIZE(named_colors); i++) {914if (named_colors[i].val == all_pix) {915fprintf(stderr, "%s",916named_colors[i].c);917return;918}919}920fprintf(stderr, "x");921} else {922fprintf(stderr, ".");923}924}925926static void927vc4_dump_surface_msaa(struct pipe_surface *psurf)928{929uint32_t tile_w = 32, tile_h = 32;930uint32_t tiles_w = DIV_ROUND_UP(psurf->width, tile_w);931uint32_t tiles_h = DIV_ROUND_UP(psurf->height, tile_h);932uint32_t char_w = 140, char_h = 60;933uint32_t char_w_per_tile = char_w / tiles_w - 1;934uint32_t char_h_per_tile = char_h / tiles_h - 1;935936fprintf(stderr, "Surface: %dx%d (%dx MSAA)\n",937psurf->width, psurf->height, psurf->texture->nr_samples);938939for (int x = 0; x < (char_w_per_tile + 1) * tiles_w; x++)940fprintf(stderr, "-");941fprintf(stderr, "\n");942943for (int ty = 0; ty < psurf->height; ty += tile_h) {944for (int y = 0; y < char_h_per_tile; y++) {945946for (int tx = 0; tx < psurf->width; tx += tile_w) {947for (int x = 0; x < char_w_per_tile; x++) {948uint32_t bx1 = (x * tile_w /949char_w_per_tile);950uint32_t bx2 = ((x + 1) * tile_w /951char_w_per_tile);952uint32_t by1 = (y * tile_h /953char_h_per_tile);954uint32_t by2 = ((y + 1) * tile_h /955char_h_per_tile);956957vc4_dump_surface_msaa_char(psurf,958tx + bx1,959ty + by1,960bx2 - bx1,961by2 - by1);962}963fprintf(stderr, "|");964}965fprintf(stderr, "\n");966}967968for (int x = 0; x < (char_w_per_tile + 1) * tiles_w; x++)969fprintf(stderr, "-");970fprintf(stderr, "\n");971}972}973974/** Debug routine to dump the contents of an 8888 surface to the console */975void976vc4_dump_surface(struct pipe_surface *psurf)977{978if (!psurf)979return;980981if (psurf->texture->nr_samples > 1)982vc4_dump_surface_msaa(psurf);983else984vc4_dump_surface_non_msaa(psurf);985}986987static void988vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)989{990/* All calls to flush_resource are followed by a flush of the context,991* so there's nothing to do.992*/993}994995void996vc4_update_shadow_baselevel_texture(struct pipe_context *pctx,997struct pipe_sampler_view *pview)998{999struct vc4_context *vc4 = vc4_context(pctx);1000struct vc4_sampler_view *view = vc4_sampler_view(pview);1001struct vc4_resource *shadow = vc4_resource(view->texture);1002struct vc4_resource *orig = vc4_resource(pview->texture);10031004assert(view->texture != pview->texture);10051006if (shadow->writes == orig->writes && orig->bo->private)1007return;10081009perf_debug("Updating %dx%d@%d shadow texture due to %s\n",1010orig->base.width0, orig->base.height0,1011pview->u.tex.first_level,1012pview->u.tex.first_level ? "base level" : "raster layout");10131014for (int i = 0; i <= shadow->base.last_level; i++) {1015unsigned width = u_minify(shadow->base.width0, i);1016unsigned height = u_minify(shadow->base.height0, i);1017struct pipe_blit_info info = {1018.dst = {1019.resource = &shadow->base,1020.level = i,1021.box = {1022.x = 0,1023.y = 0,1024.z = 0,1025.width = width,1026.height = height,1027.depth = 1,1028},1029.format = shadow->base.format,1030},1031.src = {1032.resource = &orig->base,1033.level = pview->u.tex.first_level + i,1034.box = {1035.x = 0,1036.y = 0,1037.z = 0,1038.width = width,1039.height = height,1040.depth = 1,1041},1042.format = orig->base.format,1043},1044.mask = ~0,1045};1046pctx->blit(pctx, &info);1047}10481049shadow->writes = orig->writes;1050}10511052/**1053* Converts a 4-byte index buffer to 2 bytes.1054*1055* Since GLES2 only has support for 1 and 2-byte indices, the hardware doesn't1056* include 4-byte index support, and we have to shrink it down.1057*1058* There's no fallback support for when indices end up being larger than 2^16,1059* though it will at least assertion fail. Also, if the original index data1060* was in user memory, it would be nice to not have uploaded it to a VBO1061* before translating.1062*/1063struct pipe_resource *1064vc4_get_shadow_index_buffer(struct pipe_context *pctx,1065const struct pipe_draw_info *info,1066uint32_t offset,1067uint32_t count,1068uint32_t *shadow_offset)1069{1070struct vc4_context *vc4 = vc4_context(pctx);1071struct vc4_resource *orig = vc4_resource(info->index.resource);1072perf_debug("Fallback conversion for %d uint indices\n", count);10731074void *data;1075struct pipe_resource *shadow_rsc = NULL;1076u_upload_alloc(vc4->uploader, 0, count * 2, 4,1077shadow_offset, &shadow_rsc, &data);1078uint16_t *dst = data;10791080struct pipe_transfer *src_transfer = NULL;1081const uint32_t *src;1082if (info->has_user_indices) {1083src = (uint32_t*)((char*)info->index.user + offset);1084} else {1085src = pipe_buffer_map_range(pctx, &orig->base,1086offset,1087count * 4,1088PIPE_MAP_READ, &src_transfer);1089}10901091for (int i = 0; i < count; i++) {1092uint32_t src_index = src[i];1093assert(src_index <= 0xffff);1094dst[i] = src_index;1095}10961097if (src_transfer)1098pctx->buffer_unmap(pctx, src_transfer);10991100return shadow_rsc;1101}11021103static const struct u_transfer_vtbl transfer_vtbl = {1104.resource_create = vc4_resource_create,1105.resource_destroy = vc4_resource_destroy,1106.transfer_map = vc4_resource_transfer_map,1107.transfer_unmap = vc4_resource_transfer_unmap,1108.transfer_flush_region = u_default_transfer_flush_region,1109};11101111void1112vc4_resource_screen_init(struct pipe_screen *pscreen)1113{1114struct vc4_screen *screen = vc4_screen(pscreen);11151116pscreen->resource_create = vc4_resource_create;1117pscreen->resource_create_with_modifiers =1118vc4_resource_create_with_modifiers;1119pscreen->resource_from_handle = vc4_resource_from_handle;1120pscreen->resource_get_handle = vc4_resource_get_handle;1121pscreen->resource_destroy = vc4_resource_destroy;1122pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl,1123false, false,1124false, true);11251126/* Test if the kernel has GET_TILING; it will return -EINVAL if the1127* ioctl does not exist, but -ENOENT if we pass an impossible handle.1128* 0 cannot be a valid GEM object, so use that.1129*/1130struct drm_vc4_get_tiling get_tiling = {1131.handle = 0x0,1132};1133int ret = vc4_ioctl(screen->fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling);1134if (ret == -1 && errno == ENOENT)1135screen->has_tiling_ioctl = true;1136}11371138void1139vc4_resource_context_init(struct pipe_context *pctx)1140{1141pctx->buffer_map = u_transfer_helper_transfer_map;1142pctx->texture_map = u_transfer_helper_transfer_map;1143pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;1144pctx->buffer_unmap = u_transfer_helper_transfer_unmap;1145pctx->texture_unmap = u_transfer_helper_transfer_unmap;1146pctx->buffer_subdata = u_default_buffer_subdata;1147pctx->texture_subdata = vc4_texture_subdata;1148pctx->create_surface = vc4_create_surface;1149pctx->surface_destroy = vc4_surface_destroy;1150pctx->resource_copy_region = util_resource_copy_region;1151pctx->blit = vc4_blit;1152pctx->flush_resource = vc4_flush_resource;1153}115411551156