Files
third_party_mesa3d/src/gallium/drivers/etnaviv/etnaviv_surface.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

197 lines
7.5 KiB
C
Raw Normal View History

/*
* Copyright (c) 2012-2013 Etnaviv Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sub license,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Wladimir J. van der Laan <laanwj@gmail.com>
*/
#include "etnaviv_surface.h"
#include "etnaviv_screen.h"
#include "etnaviv_clear_blit.h"
#include "etnaviv_context.h"
#include "etnaviv_translate.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "util/u_inlines.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "drm-uapi/drm_fourcc.h"
static struct etna_resource *
etna_render_handle_incompatible(struct pipe_context *pctx,
struct pipe_resource *prsc,
unsigned int level)
{
struct etna_context *ctx = etna_context(pctx);
struct etna_screen *screen = ctx->screen;
struct etna_resource *res = etna_resource(prsc);
bool need_multitiled = screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer;
bool want_supertiled = screen->specs.can_supertile;
unsigned int min_tilesize = etna_screen_get_tile_size(screen, TS_MODE_128B,
prsc->nr_samples > 1);
/* Resource is compatible if it is tiled or PE is able to render to linear
* and has multi tiling when required.
*/
if ((res->layout != ETNA_LAYOUT_LINEAR ||
(VIV_FEATURE(screen, ETNA_FEATURE_LINEAR_PE) &&
(!VIV_FEATURE(screen, ETNA_FEATURE_FAST_CLEAR) ||
res->levels[level].stride % min_tilesize == 0))) &&
(!need_multitiled || (res->layout & ETNA_LAYOUT_BIT_MULTI)))
return res;
if (!res->render) {
struct pipe_resource templat = *prsc;
unsigned layout = ETNA_LAYOUT_TILED;
if (need_multitiled)
layout |= ETNA_LAYOUT_BIT_MULTI;
if (want_supertiled)
layout |= ETNA_LAYOUT_BIT_SUPER;
templat.bind &= (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET |
PIPE_BIND_BLENDABLE);
res->render =
etna_resource_alloc(pctx->screen, layout,
DRM_FORMAT_MOD_LINEAR, &templat);
assert(res->render);
}
return etna_resource(res->render);
}
static struct pipe_surface *
etna_create_surface(struct pipe_context *pctx, struct pipe_resource *prsc,
const struct pipe_surface *templat)
{
struct etna_context *ctx = etna_context(pctx);
struct etna_screen *screen = ctx->screen;
unsigned layer = templat->u.tex.first_layer;
unsigned level = templat->u.tex.level;
struct etna_resource *rsc = etna_render_handle_incompatible(pctx, prsc, level);
struct etna_resource_level *lev = &rsc->levels[level];
struct etna_surface *surf = CALLOC_STRUCT(etna_surface);
if (!surf)
return NULL;
assert(templat->u.tex.first_layer == templat->u.tex.last_layer);
assert(layer <= util_max_layer(prsc, level));
surf->base.context = pctx;
pipe_reference_init(&surf->base.reference, 1);
pipe_resource_reference(&surf->base.texture, &rsc->base);
pipe_resource_reference(&surf->prsc, prsc);
/* Allocate a TS for the resource if there isn't one yet,
* and it is allowed by the hw (width is a multiple of 16).
* Avoid doing this for GPUs with MC1.0, as kernel sources
* indicate the tile status module bypasses the memory
* offset and MMU. */
if (VIV_FEATURE(screen, ETNA_FEATURE_FAST_CLEAR) &&
!rsc->ts_bo &&
/* needs to be RS/BLT compatible for transfer_map/unmap */
(rsc->levels[level].padded_width & ETNA_RS_WIDTH_MASK) == 0 &&
(rsc->levels[level].padded_height & ETNA_RS_HEIGHT_MASK) == 0 &&
etna_resource_hw_tileable(screen->specs.use_blt, prsc) &&
/* Multi-layer resources would need to keep much more state (TS valid and
* clear color per layer) and are unlikely to profit from TS usage. */
prsc->depth0 == 1 && prsc->array_size == 1) {
etnaviv: add support for sharing the TS buffer This adds support for sharing the TS buffer, which up until now has been an internal implementation detail, with the outside world. This mainly improves performance with a GPU compositor present, but on i.MX8M also direct to display use-cases benefit. The impact of this change depends on the GPU generation: - old GPUs with a single pipe won't see any difference - GC2000 can skip the TS resolve in the client and will benefit from a more efficient blit into the sampler compatible format when the client buffer contains cleared tiles - GC3000 can directly sample with TS support, so saves both write and read memory bandwidth when the client buffer contains cleared tiles - GC7000 with compression support can keep the client buffer in compressed format, thus saving both read and write bandwidth even for fully filled client buffers - GC7000 coupled to a display unit supporting the compression format (DCSS on i.MX8M) does not even need to uncompress the render buffer for display so will see significant bandwidth saving even when GPU compositing is bypassed There is a slight complication in that the tile clear color isn't part of the TS buffer, but is programmed into state registers in the GPU. To handle this externally shared TS buffers now contain a software metadata area, where the clear color is stored by the driver, so the receiving end of the TS buffer can retrieve the clear color from this area. The compression format is handled in the same way by storing it in the SW meta area. While we can derive the compression format from the color buffer format in most cases, some users, like weston, expect that they can "upgrade" ARGB to XRGB color formats. While this works with plain color formats, as it's just masking a channel, the compression format differs when alpha is in use. Receivers of the TS buffer should thus not try to infer the compression format from the color buffer format, but instead fetch it from the SW meta. The import/export handling of the TS buffer is modelled after the Intel iris driver: we add a separate plane for the TS buffer and fold it into the base resource after the import. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Tested-by: Guido Günther <agx@sigxcpu.org> Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9780>
2020-10-28 20:13:45 +01:00
etna_screen_resource_alloc_ts(pctx->screen, rsc, 0);
}
surf->base.format = templat->format;
surf->base.width = rsc->levels[level].width;
surf->base.height = rsc->levels[level].height;
surf->base.writable = templat->writable; /* what is this for anyway */
surf->base.u = templat->u;
surf->level = lev;
/* XXX we don't really need a copy but it's convenient */
surf->offset = lev->offset + layer * lev->layer_stride;
/* Setup template relocations for this surface */
for (unsigned pipe = 0; pipe < screen->specs.pixel_pipes; ++pipe) {
surf->reloc[pipe].bo = rsc->bo;
surf->reloc[pipe].offset = surf->offset;
surf->reloc[pipe].flags = 0;
}
/* In single buffer mode, both pixel pipes must point to the same address,
* for multi-tiled surfaces on the other hand the second pipe is expected to
* point halfway the image vertically.
*/
if (rsc->layout & ETNA_LAYOUT_BIT_MULTI)
surf->reloc[1].offset = surf->offset + lev->stride * lev->padded_height / 2;
if (surf->level->ts_size) {
unsigned int layer_offset = layer * lev->ts_layer_stride;
assert(layer_offset < surf->level->ts_size);
surf->ts_offset = surf->level->ts_offset + layer_offset;
surf->ts_reloc.bo = rsc->ts_bo;
surf->ts_reloc.offset = surf->ts_offset;
surf->ts_reloc.flags = 0;
if (!screen->specs.use_blt) {
/* This (ab)uses the RS as a plain buffer memset().
* Currently uses a fixed row size of 64 bytes. Some benchmarking with
* different sizes may be in order. */
struct etna_bo *ts_bo = etna_resource(surf->base.texture)->ts_bo;
etna_compile_rs_state(ctx, &surf->clear_command, &(struct rs_state) {
.source_format = RS_FORMAT_A8R8G8B8,
.dest_format = RS_FORMAT_A8R8G8B8,
.dest = ts_bo,
.dest_offset = surf->ts_offset,
.dest_stride = 0x40,
.dest_tiling = ETNA_LAYOUT_TILED,
.dither = {0xffffffff, 0xffffffff},
.width = 16,
.height = align(lev->ts_layer_stride / 0x40, 4),
.clear_value = {screen->specs.ts_clear_value},
.clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_ENABLED1,
.clear_bits = 0xffff
});
}
}
return &surf->base;
}
static void
etna_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
{
pipe_resource_reference(&psurf->texture, NULL);
pipe_resource_reference(&etna_surface(psurf)->prsc, NULL);
FREE(psurf);
}
void
etna_surface_init(struct pipe_context *pctx)
{
pctx->create_surface = etna_create_surface;
pctx->surface_destroy = etna_surface_destroy;
}