mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-29 01:30:08 +01:00
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>
This commit is contained in:
parent
f7463b1292
commit
c2b06e1a38
9 changed files with 378 additions and 66 deletions
|
|
@ -258,6 +258,12 @@ etna_blit_clear_color_blt(struct pipe_context *pctx, struct pipe_surface *dst,
|
|||
if (surf->surf.ts_size) {
|
||||
ctx->framebuffer.TS_COLOR_CLEAR_VALUE = new_clear_value;
|
||||
ctx->framebuffer.TS_COLOR_CLEAR_VALUE_EXT = new_clear_value >> 32;
|
||||
|
||||
/* update clear color in SW meta area of the buffer if TS is exported */
|
||||
if (unlikely(new_clear_value != surf->level->clear_value &&
|
||||
etna_resource_ext_ts(etna_resource(dst->texture))))
|
||||
etna_resource(dst->texture)->ts_meta->v0.clear_value = new_clear_value;
|
||||
|
||||
surf->level->ts_valid = true;
|
||||
ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ etna_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
|
|||
etna_copy_resource(pctx, prsc, rsc->render, 0, 0);
|
||||
rsc->seqno = etna_resource(rsc->render)->seqno;
|
||||
}
|
||||
} else if (etna_resource_needs_flush(rsc)) {
|
||||
} else if (!etna_resource_ext_ts(rsc) && etna_resource_needs_flush(rsc)) {
|
||||
etna_copy_resource(pctx, prsc, prsc, 0, 0);
|
||||
rsc->flush_seqno = rsc->seqno;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,9 @@
|
|||
#include "util/u_inlines.h"
|
||||
#include "util/u_memory.h"
|
||||
|
||||
#include "drm-uapi/drm_fourcc.h"
|
||||
|
||||
static enum etna_surface_layout modifier_to_layout(uint64_t modifier)
|
||||
{
|
||||
switch (modifier) {
|
||||
switch (modifier & ~VIVANTE_MOD_EXT_MASK) {
|
||||
case DRM_FORMAT_MOD_VIVANTE_TILED:
|
||||
return ETNA_LAYOUT_TILED;
|
||||
case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
|
||||
|
|
@ -75,19 +73,27 @@ static uint64_t layout_to_modifier(enum etna_surface_layout layout)
|
|||
}
|
||||
}
|
||||
|
||||
static uint64_t etna_resource_modifier(struct etna_resource *rsc)
|
||||
{
|
||||
if (etna_resource_ext_ts(rsc))
|
||||
return rsc->modifier;
|
||||
|
||||
return layout_to_modifier(rsc->layout);
|
||||
}
|
||||
|
||||
/* A tile is either 64 bytes or, when the GPU has the CACHE128B256BPERLINE
|
||||
* feature, 128/256 bytes of color/depth data, tracked by
|
||||
* 'screen->specs.bits_per_tile' bits of tile status.
|
||||
*/
|
||||
bool
|
||||
etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
|
||||
struct etna_resource *rsc)
|
||||
struct etna_resource *rsc, uint64_t modifier)
|
||||
{
|
||||
struct etna_screen *screen = etna_screen(pscreen);
|
||||
struct pipe_resource *prsc = &rsc->base;
|
||||
size_t tile_size, rt_ts_size, ts_layer_stride;
|
||||
size_t tile_size, ts_size, ts_bo_size, ts_layer_stride, ts_data_offset = 0;
|
||||
uint8_t ts_mode = TS_MODE_128B;
|
||||
int8_t ts_compress_fmt;
|
||||
int8_t ts_compress_fmt = -1;
|
||||
unsigned layers;
|
||||
|
||||
assert(!rsc->ts_bo);
|
||||
|
|
@ -96,36 +102,64 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
|
|||
* v4 compression can be enabled everywhere without any known drawback,
|
||||
* except that in-place resolve must go through a slower path
|
||||
*/
|
||||
ts_compress_fmt = (screen->specs.v4_compression || prsc->nr_samples > 1) ?
|
||||
translate_ts_format(prsc->format) : -1;
|
||||
if ((screen->specs.v4_compression &&
|
||||
(!modifier || (modifier & VIVANTE_MOD_COMP_DEC400))) ||
|
||||
(!modifier && prsc->nr_samples > 1))
|
||||
ts_compress_fmt = translate_ts_format(prsc->format);
|
||||
|
||||
/* enable 256B ts mode with compression, as it improves performance
|
||||
* the size of the resource might also determine if we want to use it or not
|
||||
*/
|
||||
if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE) &&
|
||||
ts_compress_fmt >= 0 &&
|
||||
(rsc->layout != ETNA_LAYOUT_LINEAR ||
|
||||
rsc->levels[0].stride % 256 == 0) )
|
||||
if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE)) {
|
||||
if ((modifier & VIVANTE_MOD_TS_MASK) == VIVANTE_MOD_TS_128_4)
|
||||
ts_mode = TS_MODE_128B;
|
||||
else if ((modifier & VIVANTE_MOD_TS_MASK) == VIVANTE_MOD_TS_256_4)
|
||||
ts_mode = TS_MODE_256B;
|
||||
else {
|
||||
/* Without a TS modifier TS is only internal, so we can choose the
|
||||
* mode to use freely. Enable 256B ts mode with compression, as it
|
||||
* improves performance. The size of the resource might also determine
|
||||
* if we want to use it or not.
|
||||
*/
|
||||
if (ts_compress_fmt >= 0 &&
|
||||
(rsc->layout != ETNA_LAYOUT_LINEAR ||
|
||||
rsc->levels[0].stride % 256 == 0))
|
||||
ts_mode = TS_MODE_256B;
|
||||
else
|
||||
ts_mode = TS_MODE_128B;
|
||||
}
|
||||
}
|
||||
|
||||
tile_size = etna_screen_get_tile_size(screen, ts_mode, prsc->nr_samples > 1);
|
||||
layers = prsc->target == PIPE_TEXTURE_3D ? prsc->depth0 : prsc->array_size;
|
||||
ts_layer_stride = align(DIV_ROUND_UP(rsc->levels[0].layer_stride,
|
||||
tile_size * 8 / screen->specs.bits_per_tile),
|
||||
0x100 * screen->specs.pixel_pipes);
|
||||
rt_ts_size = ts_layer_stride * layers;
|
||||
if (rt_ts_size == 0)
|
||||
ts_size = ts_bo_size = ts_layer_stride * layers;
|
||||
if (ts_size == 0)
|
||||
return true;
|
||||
|
||||
/* add space for the software meta */
|
||||
if (modifier & VIVANTE_MOD_TS_MASK) {
|
||||
/* The offset is a educated guess for a safe value based on the experience
|
||||
* that various object pointers on the GPU need to be 64B aligned. Maybe
|
||||
* some GPU needs even more alignment, or we could drop this to 32B. 64B
|
||||
* has worked well across various GPU generations so far.
|
||||
*/
|
||||
ts_data_offset = 64;
|
||||
assert(ts_data_offset >= sizeof(struct etna_ts_sw_meta));
|
||||
ts_bo_size += ts_data_offset;
|
||||
}
|
||||
|
||||
DBG_F(ETNA_DBG_RESOURCE_MSGS, "%p: Allocating tile status of size %zu",
|
||||
rsc, rt_ts_size);
|
||||
rsc, ts_bo_size);
|
||||
|
||||
if ((rsc->base.bind & PIPE_BIND_SCANOUT) && screen->ro->kms_fd >= 0) {
|
||||
struct pipe_resource scanout_templat;
|
||||
struct winsys_handle handle;
|
||||
|
||||
scanout_templat.format = PIPE_FORMAT_R8_UNORM;
|
||||
scanout_templat.width0 = align(rt_ts_size, 4096);
|
||||
scanout_templat.width0 = align(ts_bo_size, 4096);
|
||||
scanout_templat.height0 = 1;
|
||||
|
||||
rsc->ts_scanout = renderonly_scanout_for_resource(&scanout_templat,
|
||||
|
|
@ -147,12 +181,21 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
|
|||
return false;
|
||||
}
|
||||
|
||||
rsc->levels[0].ts_offset = 0;
|
||||
rsc->levels[0].ts_offset = ts_data_offset;
|
||||
rsc->levels[0].ts_layer_stride = ts_layer_stride;
|
||||
rsc->levels[0].ts_size = rt_ts_size;
|
||||
rsc->levels[0].ts_size = ts_size;
|
||||
rsc->levels[0].ts_mode = ts_mode;
|
||||
rsc->levels[0].ts_compress_fmt = ts_compress_fmt;
|
||||
|
||||
/* fill software meta */
|
||||
if (modifier & VIVANTE_MOD_TS_MASK) {
|
||||
rsc->ts_meta = etna_bo_map(rsc->ts_bo);
|
||||
rsc->ts_meta->version = 0;
|
||||
rsc->ts_meta->v0.data_size = ts_size;
|
||||
rsc->ts_meta->v0.data_offset = ts_data_offset;
|
||||
rsc->ts_meta->v0.layer_stride = ts_layer_stride;
|
||||
rsc->ts_meta->v0.comp_format = ts_format_to_drmfourcc(rsc->levels[0].ts_compress_fmt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -305,6 +348,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
|
|||
rsc->base.screen = pscreen;
|
||||
rsc->base.nr_samples = templat->nr_samples;
|
||||
rsc->layout = layout;
|
||||
rsc->modifier = modifier;
|
||||
rsc->halign = halign;
|
||||
rsc->explicit_flush = true;
|
||||
|
||||
|
|
@ -346,6 +390,12 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
|
|||
}
|
||||
}
|
||||
|
||||
/* If TS is externally visible set it up now, so it can be exported before
|
||||
* the first rendering to a surface.
|
||||
*/
|
||||
if (etna_resource_ext_ts(rsc))
|
||||
etna_screen_resource_alloc_ts(pscreen, rsc, modifier);
|
||||
|
||||
if (DBG_ENABLED(ETNA_DBG_ZERO)) {
|
||||
void *map = etna_bo_map(rsc->bo);
|
||||
etna_bo_cpu_prep(rsc->bo, DRM_ETNA_PREP_WRITE);
|
||||
|
|
@ -433,9 +483,10 @@ select_best_modifier(const struct etna_screen * screen,
|
|||
const uint64_t *modifiers, const unsigned count)
|
||||
{
|
||||
enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
|
||||
uint64_t best_modifier, base_modifier;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
switch (modifiers[i]) {
|
||||
switch (modifiers[i] & ~VIVANTE_MOD_EXT_MASK) {
|
||||
case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
|
||||
if ((screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) ||
|
||||
!screen->specs.can_supertile)
|
||||
|
|
@ -466,7 +517,32 @@ select_best_modifier(const struct etna_screen * screen,
|
|||
}
|
||||
}
|
||||
|
||||
return priority_to_modifier[prio];
|
||||
best_modifier = base_modifier = priority_to_modifier[prio];
|
||||
|
||||
/* Make a second pass to try and find the best TS modifier if any. */
|
||||
for (int i = 0; i < count; i++) {
|
||||
if ((modifiers[i] & ~VIVANTE_MOD_EXT_MASK) == base_modifier)
|
||||
if ((modifiers[i] & VIVANTE_MOD_TS_MASK) >
|
||||
(best_modifier & VIVANTE_MOD_TS_MASK))
|
||||
best_modifier = modifiers[i];
|
||||
}
|
||||
|
||||
/* If no modifier with TS was found, there is no point in looking further,
|
||||
* as compression depends on TS.
|
||||
*/
|
||||
if (best_modifier == base_modifier)
|
||||
return best_modifier;
|
||||
|
||||
/* Make a third pass to find a modifier allowing compression. */
|
||||
base_modifier = best_modifier;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if ((modifiers[i] & ~VIVANTE_MOD_COMP_MASK) == base_modifier)
|
||||
if ((modifiers[i] & VIVANTE_MOD_COMP_MASK) >
|
||||
(best_modifier & VIVANTE_MOD_COMP_MASK))
|
||||
best_modifier = modifiers[i];
|
||||
}
|
||||
|
||||
return best_modifier;
|
||||
}
|
||||
|
||||
static struct pipe_resource *
|
||||
|
|
@ -504,6 +580,9 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
|
|||
if (rsc->scanout)
|
||||
renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro);
|
||||
|
||||
if (rsc->ts_scanout)
|
||||
renderonly_scanout_destroy(rsc->ts_scanout, etna_screen(pscreen)->ro);
|
||||
|
||||
util_range_destroy(&rsc->valid_buffer_range);
|
||||
|
||||
pipe_resource_reference(&rsc->texture, NULL);
|
||||
|
|
@ -515,6 +594,38 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
|
|||
FREE(rsc);
|
||||
}
|
||||
|
||||
static void etna_resource_finish_ts_import(struct etna_screen *screen,
|
||||
struct etna_resource *rsc)
|
||||
{
|
||||
struct etna_resource *ts_rsc = etna_resource(rsc->base.next);
|
||||
uint64_t ts_modifier = rsc->modifier & VIVANTE_MOD_TS_MASK;
|
||||
uint8_t ts_mode = 0;
|
||||
|
||||
if (ts_modifier == VIVANTE_MOD_TS_256_4)
|
||||
ts_mode = TS_MODE_256B;
|
||||
|
||||
rsc->ts_bo = etna_bo_ref(ts_rsc->bo);
|
||||
rsc->ts_meta = etna_bo_map(rsc->ts_bo) + ts_rsc->levels[0].offset;
|
||||
|
||||
rsc->ts_scanout = ts_rsc->scanout;
|
||||
ts_rsc->scanout = NULL;
|
||||
|
||||
/* Get TS layout/usage information from the SW meta. FIXME: clear color may
|
||||
* change over the lifetime of the resource, so might need to look this up
|
||||
* at a few other places. For now it's not an issue, as buffers with shared
|
||||
* TS get re-imported all the time. */
|
||||
rsc->levels[0].ts_compress_fmt = drmfourcc_to_ts_format(rsc->ts_meta->v0.comp_format);
|
||||
rsc->levels[0].ts_offset = ts_rsc->levels[0].offset + rsc->ts_meta->v0.data_offset;
|
||||
rsc->levels[0].ts_layer_stride = rsc->ts_meta->v0.layer_stride;
|
||||
rsc->levels[0].clear_value = rsc->ts_meta->v0.clear_value;
|
||||
rsc->levels[0].ts_size = rsc->ts_meta->v0.data_size;
|
||||
rsc->levels[0].ts_mode = ts_mode;
|
||||
rsc->levels[0].ts_valid = true;
|
||||
|
||||
etna_resource_destroy(&screen->base, rsc->base.next);
|
||||
rsc->base.next = NULL;
|
||||
}
|
||||
|
||||
static struct pipe_resource *
|
||||
etna_resource_from_handle(struct pipe_screen *pscreen,
|
||||
const struct pipe_resource *tmpl,
|
||||
|
|
@ -554,6 +665,7 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
|
|||
|
||||
rsc->seqno = 1;
|
||||
rsc->layout = modifier_to_layout(modifier);
|
||||
rsc->modifier = modifier;
|
||||
|
||||
if (usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)
|
||||
rsc->explicit_flush = true;
|
||||
|
|
@ -576,6 +688,20 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
|
|||
level->padded_height);
|
||||
level->size = level->layer_stride;
|
||||
|
||||
if (screen->ro) {
|
||||
struct pipe_resource *imp_prsc = prsc;
|
||||
do {
|
||||
etna_resource(imp_prsc)->scanout =
|
||||
renderonly_create_gpu_import_for_resource(imp_prsc, screen->ro,
|
||||
NULL);
|
||||
/* failure is expected for scanout incompatible buffers */
|
||||
} while ((imp_prsc = imp_prsc->next));
|
||||
}
|
||||
|
||||
/* If the buffer is for a TS plane, skip the RS compatible checks */
|
||||
if (handle->plane >= util_format_get_num_planes(prsc->format))
|
||||
return prsc;
|
||||
|
||||
/* The DDX must give us a BO which conforms to our padding size.
|
||||
* The stride of the BO must be greater or equal to our padded
|
||||
* stride. The size of the BO must accomodate the padded height. */
|
||||
|
|
@ -592,15 +718,8 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (screen->ro) {
|
||||
struct pipe_resource *imp_prsc = prsc;
|
||||
do {
|
||||
etna_resource(imp_prsc)->scanout =
|
||||
renderonly_create_gpu_import_for_resource(imp_prsc, screen->ro,
|
||||
NULL);
|
||||
/* failure is expected for scanout incompatible buffers */
|
||||
} while ((imp_prsc = imp_prsc->next));
|
||||
}
|
||||
if (handle->plane == 0 && etna_resource_ext_ts(rsc))
|
||||
etna_resource_finish_ts_import(screen, rsc);
|
||||
|
||||
return prsc;
|
||||
|
||||
|
|
@ -618,9 +737,12 @@ etna_resource_get_handle(struct pipe_screen *pscreen,
|
|||
{
|
||||
struct etna_screen *screen = etna_screen(pscreen);
|
||||
struct etna_resource *rsc = etna_resource(prsc);
|
||||
bool wants_ts = etna_resource_ext_ts(rsc) &&
|
||||
handle->plane >= util_format_get_num_planes(prsc->format);
|
||||
struct renderonly_scanout *scanout;
|
||||
struct etna_bo *bo;
|
||||
|
||||
if (handle->plane) {
|
||||
if (handle->plane && !wants_ts) {
|
||||
struct pipe_resource *cur = prsc;
|
||||
|
||||
for (int i = 0; i < handle->plane; i++) {
|
||||
|
|
@ -634,24 +756,37 @@ etna_resource_get_handle(struct pipe_screen *pscreen,
|
|||
/* Scanout is always attached to the base resource */
|
||||
scanout = rsc->scanout;
|
||||
|
||||
handle->stride = rsc->levels[0].stride;
|
||||
handle->offset = rsc->levels[0].offset;
|
||||
handle->modifier = layout_to_modifier(rsc->layout);
|
||||
if (wants_ts) {
|
||||
handle->stride = DIV_ROUND_UP(rsc->levels[0].stride,
|
||||
etna_screen_get_tile_size(screen,
|
||||
rsc->levels[0].ts_mode,
|
||||
false)
|
||||
* 8 /screen->specs.bits_per_tile);
|
||||
handle->offset = rsc->levels[0].ts_offset - rsc->ts_meta->v0.data_offset;
|
||||
scanout = rsc->ts_scanout;
|
||||
bo = rsc->ts_bo;
|
||||
} else {
|
||||
handle->stride = rsc->levels[0].stride;
|
||||
handle->offset = rsc->levels[0].offset;
|
||||
scanout = rsc->scanout;
|
||||
bo = rsc->bo;
|
||||
}
|
||||
handle->modifier = etna_resource_modifier(rsc);
|
||||
|
||||
if (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH))
|
||||
rsc->explicit_flush = false;
|
||||
|
||||
if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
|
||||
return etna_bo_get_name(rsc->bo, &handle->handle) == 0;
|
||||
return etna_bo_get_name(bo, &handle->handle) == 0;
|
||||
} else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
|
||||
if (screen->ro) {
|
||||
return renderonly_get_handle(scanout, handle);
|
||||
} else {
|
||||
handle->handle = etna_bo_handle(rsc->bo);
|
||||
handle->handle = etna_bo_handle(bo);
|
||||
return true;
|
||||
}
|
||||
} else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
|
||||
handle->handle = etna_bo_dmabuf(rsc->bo);
|
||||
handle->handle = etna_bo_dmabuf(bo);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
@ -665,32 +800,54 @@ etna_resource_get_param(struct pipe_screen *pscreen,
|
|||
enum pipe_resource_param param,
|
||||
unsigned usage, uint64_t *value)
|
||||
{
|
||||
if (param == PIPE_RESOURCE_PARAM_NPLANES) {
|
||||
unsigned count = 0;
|
||||
struct etna_screen *screen = etna_screen(pscreen);
|
||||
struct etna_resource *rsc = etna_resource(prsc);
|
||||
bool wants_ts = etna_resource_ext_ts(rsc) &&
|
||||
plane >= util_format_get_num_planes(prsc->format);
|
||||
|
||||
for (struct pipe_resource *cur = prsc; cur; cur = cur->next)
|
||||
count++;
|
||||
*value = count;
|
||||
if (param == PIPE_RESOURCE_PARAM_NPLANES) {
|
||||
if (etna_resource_ext_ts(rsc)) {
|
||||
*value = 2;
|
||||
} else {
|
||||
unsigned count = 0;
|
||||
|
||||
for (struct pipe_resource *cur = prsc; cur; cur = cur->next)
|
||||
count++;
|
||||
*value = count;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct pipe_resource *cur = prsc;
|
||||
for (int i = 0; i < plane; i++) {
|
||||
cur = cur->next;
|
||||
if (!cur)
|
||||
return false;
|
||||
if (!wants_ts) {
|
||||
struct pipe_resource *cur = prsc;
|
||||
for (int i = 0; i < plane; i++) {
|
||||
cur = cur->next;
|
||||
if (!cur)
|
||||
return false;
|
||||
}
|
||||
rsc = etna_resource(cur);
|
||||
}
|
||||
struct etna_resource *rsc = etna_resource(cur);
|
||||
|
||||
switch (param) {
|
||||
case PIPE_RESOURCE_PARAM_STRIDE:
|
||||
*value = rsc->levels[level].stride;
|
||||
if (wants_ts) {
|
||||
*value = DIV_ROUND_UP(rsc->levels[0].stride,
|
||||
etna_screen_get_tile_size(screen,
|
||||
rsc->levels[0].ts_mode,
|
||||
prsc->nr_samples > 1)
|
||||
* 8 / screen->specs.bits_per_tile);
|
||||
} else {
|
||||
*value = rsc->levels[0].stride;
|
||||
}
|
||||
return true;
|
||||
case PIPE_RESOURCE_PARAM_OFFSET:
|
||||
*value = rsc->levels[level].offset;
|
||||
if (wants_ts)
|
||||
*value = rsc->levels[0].ts_offset - rsc->ts_meta->v0.data_offset;
|
||||
else
|
||||
*value = rsc->levels[0].offset;
|
||||
return true;
|
||||
case PIPE_RESOURCE_PARAM_MODIFIER:
|
||||
*value = layout_to_modifier(rsc->layout);
|
||||
*value = etna_resource_modifier(rsc);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -36,10 +36,23 @@
|
|||
#include "util/u_helpers.h"
|
||||
#include "util/u_range.h"
|
||||
|
||||
#include "drm-uapi/drm_fourcc.h"
|
||||
|
||||
struct etna_context;
|
||||
struct pipe_screen;
|
||||
struct util_dynarray;
|
||||
|
||||
struct etna_ts_sw_meta {
|
||||
uint16_t version;
|
||||
struct {
|
||||
uint16_t data_offset;
|
||||
uint32_t data_size;
|
||||
uint32_t layer_stride;
|
||||
uint32_t comp_format;
|
||||
uint64_t clear_value;
|
||||
} v0;
|
||||
};
|
||||
|
||||
struct etna_resource_level {
|
||||
unsigned width, padded_width; /* in pixels */
|
||||
unsigned height, padded_height; /* in samples */
|
||||
|
|
@ -79,10 +92,13 @@ struct etna_resource {
|
|||
/* only lod 0 used for non-texture buffers */
|
||||
/* Layout for surface (tiled, multitiled, split tiled, ...) */
|
||||
enum etna_surface_layout layout;
|
||||
uint64_t modifier;
|
||||
/* Horizontal alignment for texture unit (TEXTURE_HALIGN_*) */
|
||||
unsigned halign;
|
||||
struct etna_bo *bo; /* Surface video memory */
|
||||
struct etna_bo *ts_bo; /* Tile status video memory */
|
||||
struct renderonly_scanout *ts_scanout; /* display compatible TS */
|
||||
struct etna_ts_sw_meta *ts_meta; /* metadata for shared TS */
|
||||
|
||||
struct etna_resource_level levels[ETNA_NUM_LOD];
|
||||
|
||||
|
|
@ -142,6 +158,13 @@ etna_resource_hw_tileable(bool use_blt, const struct pipe_resource *pres)
|
|||
util_format_get_blocksize(pres->format) == 4;
|
||||
}
|
||||
|
||||
/* returns TRUE if resource TS buffer is exposed externally */
|
||||
static inline bool
|
||||
etna_resource_ext_ts(const struct etna_resource *res)
|
||||
{
|
||||
return res->modifier & VIVANTE_MOD_TS_MASK;
|
||||
}
|
||||
|
||||
static inline struct etna_resource *
|
||||
etna_resource(struct pipe_resource *p)
|
||||
{
|
||||
|
|
@ -173,7 +196,8 @@ etna_resource_status(struct etna_context *ctx, struct etna_resource *res);
|
|||
* This is also called "fast clear". */
|
||||
bool
|
||||
etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
|
||||
struct etna_resource *prsc);
|
||||
struct etna_resource *prsc,
|
||||
uint64_t modifier);
|
||||
|
||||
struct pipe_resource *
|
||||
etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
|
||||
|
|
|
|||
|
|
@ -340,6 +340,11 @@ etna_blit_clear_color_rs(struct pipe_context *pctx, struct pipe_surface *dst,
|
|||
ctx->framebuffer.TS_MEM_CONFIG |= VIVS_TS_MEM_CONFIG_COLOR_AUTO_DISABLE;
|
||||
}
|
||||
|
||||
/* update clear color in SW meta area of the buffer if TS is exported */
|
||||
if (unlikely(new_clear_value != surf->level->clear_value &&
|
||||
etna_resource_ext_ts(etna_resource(dst->texture))))
|
||||
etna_resource(dst->texture)->ts_meta->v0.clear_value = new_clear_value;
|
||||
|
||||
surf->level->ts_valid = true;
|
||||
ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS;
|
||||
} else if (unlikely(new_clear_value != surf->level->clear_value)) { /* Queue normal RS clear for non-TS surfaces */
|
||||
|
|
|
|||
|
|
@ -643,22 +643,66 @@ etna_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
|
|||
unsigned int *external_only, int *count)
|
||||
{
|
||||
struct etna_screen *screen = etna_screen(pscreen);
|
||||
int num_modifiers = etna_get_num_modifiers(screen);
|
||||
int i;
|
||||
int num_base_mods = etna_get_num_modifiers(screen);
|
||||
int mods_multiplier = 1;
|
||||
int i, j;
|
||||
|
||||
if (max > num_modifiers)
|
||||
max = num_modifiers;
|
||||
if (VIV_FEATURE(screen, chipFeatures, FAST_CLEAR)) {
|
||||
/* If TS is supported expose the TS modifiers. GPUs with feature
|
||||
* CACHE128B256BPERLINE have both 128B and 256B color tile TS modes,
|
||||
* older cores support exactly one TS layout.
|
||||
*/
|
||||
if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE))
|
||||
if (screen->specs.v4_compression &&
|
||||
translate_ts_format(format) != ETNA_NO_MATCH)
|
||||
mods_multiplier += 4;
|
||||
else
|
||||
mods_multiplier += 2;
|
||||
else
|
||||
mods_multiplier += 1;
|
||||
}
|
||||
|
||||
if (max > num_base_mods * mods_multiplier)
|
||||
max = num_base_mods * mods_multiplier;
|
||||
|
||||
if (!max) {
|
||||
modifiers = NULL;
|
||||
max = num_modifiers;
|
||||
max = num_base_mods * mods_multiplier;
|
||||
}
|
||||
|
||||
for (i = 0, *count = 0; *count < max && i < num_modifiers; i++, (*count)++) {
|
||||
if (modifiers)
|
||||
modifiers[*count] = supported_modifiers[i];
|
||||
if (external_only)
|
||||
external_only[*count] = util_format_is_yuv(format) ? 1 : 0;
|
||||
for (i = 0, *count = 0; *count < max && i < num_base_mods; i++) {
|
||||
for (j = 0; *count < max && j < mods_multiplier; j++, (*count)++) {
|
||||
uint64_t ts_mod;
|
||||
|
||||
if (j == 0) {
|
||||
ts_mod = 0;
|
||||
} else if (VIV_FEATURE(screen, chipMinorFeatures6,
|
||||
CACHE128B256BPERLINE)) {
|
||||
switch (j) {
|
||||
case 1:
|
||||
ts_mod = VIVANTE_MOD_TS_128_4;
|
||||
break;
|
||||
case 2:
|
||||
ts_mod = VIVANTE_MOD_TS_256_4;
|
||||
break;
|
||||
case 3:
|
||||
ts_mod = VIVANTE_MOD_TS_128_4 | VIVANTE_MOD_COMP_DEC400;
|
||||
break;
|
||||
case 4:
|
||||
ts_mod = VIVANTE_MOD_TS_256_4 | VIVANTE_MOD_COMP_DEC400;
|
||||
}
|
||||
} else {
|
||||
if (screen->specs.bits_per_tile == 2)
|
||||
ts_mod = VIVANTE_MOD_TS_64_2;
|
||||
else
|
||||
ts_mod = VIVANTE_MOD_TS_64_4;
|
||||
}
|
||||
|
||||
if (modifiers)
|
||||
modifiers[*count] = supported_modifiers[i] | ts_mod;
|
||||
if (external_only)
|
||||
external_only[*count] = util_format_is_yuv(format) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -669,13 +713,36 @@ etna_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,
|
|||
bool *external_only)
|
||||
{
|
||||
struct etna_screen *screen = etna_screen(pscreen);
|
||||
int num_modifiers = etna_get_num_modifiers(screen);
|
||||
int num_base_mods = etna_get_num_modifiers(screen);
|
||||
uint64_t base_mod = modifier & ~VIVANTE_MOD_EXT_MASK;
|
||||
uint64_t ts_mod = modifier & VIVANTE_MOD_TS_MASK;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_modifiers; i++) {
|
||||
if (modifier != supported_modifiers[i])
|
||||
for (i = 0; i < num_base_mods; i++) {
|
||||
if (base_mod != supported_modifiers[i])
|
||||
continue;
|
||||
|
||||
if ((modifier & VIVANTE_MOD_COMP_DEC400) &&
|
||||
(!screen->specs.v4_compression || translate_ts_format(format) == ETNA_NO_MATCH))
|
||||
return false;
|
||||
|
||||
if (ts_mod) {
|
||||
if (!VIV_FEATURE(screen, chipFeatures, FAST_CLEAR))
|
||||
return false;
|
||||
|
||||
if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE)) {
|
||||
if (ts_mod != VIVANTE_MOD_TS_128_4 &&
|
||||
ts_mod != VIVANTE_MOD_TS_256_4)
|
||||
return false;
|
||||
} else {
|
||||
if ((screen->specs.bits_per_tile == 2 &&
|
||||
ts_mod != VIVANTE_MOD_TS_64_2) ||
|
||||
(screen->specs.bits_per_tile == 4 &&
|
||||
ts_mod != VIVANTE_MOD_TS_64_4))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (external_only)
|
||||
*external_only = util_format_is_yuv(format) ? 1 : 0;
|
||||
|
||||
|
|
@ -685,6 +752,19 @@ etna_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,
|
|||
return false;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
etna_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen,
|
||||
uint64_t modifier,
|
||||
enum pipe_format format)
|
||||
{
|
||||
unsigned planes = util_format_get_num_planes(format);
|
||||
|
||||
if (modifier & VIVANTE_MOD_TS_MASK)
|
||||
return planes * 2;
|
||||
|
||||
return planes;
|
||||
}
|
||||
|
||||
static void
|
||||
etna_determine_uniform_limits(struct etna_screen *screen)
|
||||
{
|
||||
|
|
@ -1141,6 +1221,7 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
|
|||
pscreen->is_format_supported = etna_screen_is_format_supported;
|
||||
pscreen->query_dmabuf_modifiers = etna_screen_query_dmabuf_modifiers;
|
||||
pscreen->is_dmabuf_modifier_supported = etna_screen_is_dmabuf_modifier_supported;
|
||||
pscreen->get_dmabuf_modifier_planes = etna_screen_get_dmabuf_modifier_planes;
|
||||
|
||||
if (!etna_shader_screen_init(pscreen))
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ etna_create_surface(struct pipe_context *pctx, struct pipe_resource *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) {
|
||||
etna_screen_resource_alloc_ts(pctx->screen, rsc);
|
||||
etna_screen_resource_alloc_ts(pctx->screen, rsc, 0);
|
||||
}
|
||||
|
||||
surf->base.format = templat->format;
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ struct etna_resource *
|
|||
etna_texture_handle_incompatible(struct pipe_context *pctx, struct pipe_resource *prsc)
|
||||
{
|
||||
struct etna_resource *res = etna_resource(prsc);
|
||||
|
||||
if (!etna_resource_sampler_compatible(res)) {
|
||||
/* The original resource is not compatible with the sampler.
|
||||
* Allocate an appropriately tiled texture. */
|
||||
|
|
|
|||
|
|
@ -333,6 +333,44 @@ translate_blt_format(enum pipe_format fmt)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
drmfourcc_to_ts_format(uint32_t fourcc)
|
||||
{
|
||||
switch (fourcc) {
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
return COMPRESSION_FORMAT_A8R8G8B8;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
return COMPRESSION_FORMAT_X8R8G8B8;
|
||||
case DRM_FORMAT_RGB565:
|
||||
return COMPRESSION_FORMAT_R5G6B5;
|
||||
case DRM_FORMAT_ARGB4444:
|
||||
return COMPRESSION_FORMAT_A4R4G4B4;
|
||||
case DRM_FORMAT_ARGB1555:
|
||||
return COMPRESSION_FORMAT_A1R5G5B5;
|
||||
default:
|
||||
return ~0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
ts_format_to_drmfourcc(uint32_t comp_format)
|
||||
{
|
||||
switch (comp_format) {
|
||||
case COMPRESSION_FORMAT_A8R8G8B8:
|
||||
return DRM_FORMAT_ARGB8888;
|
||||
case COMPRESSION_FORMAT_X8R8G8B8:
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
case COMPRESSION_FORMAT_R5G6B5:
|
||||
return DRM_FORMAT_RGB565;
|
||||
case COMPRESSION_FORMAT_A4R4G4B4:
|
||||
return DRM_FORMAT_ARGB4444;
|
||||
case COMPRESSION_FORMAT_A1R5G5B5:
|
||||
return DRM_FORMAT_ARGB1555;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return normalization flag for vertex element format */
|
||||
static inline uint32_t
|
||||
translate_vertex_format_normalize(enum pipe_format fmt)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue