etnaviv: split TS and non-TS RS clear commands
Currently both TS and non-TS paths use the same place to store the compiled
RS commands to clear the surface. In the TS case the commands only initialize
the TS buffer, while the non-TS commands clear the whole buffer. The
assumption here is that a TS enabled surface will only ever be fast cleared,
which doesn't hold anymore, now that we can fall back to slow clears on TS
enabled depth/stencil buffers.
The fallback to a slow clear will overwrite the stored RS commands with a
full buffer clear. If we can transition to a fast clear later, the commands
to initialize the TS buffer will not be regenerated and a full buffer clear
will be submitted instead. In addition to the performance degradation, it
will also leave TS in an inconsistent state, as the TS buffer will not be
initialized, but the TS state still gets marked as valid.
To avoid this confusion and not introduce any more state tracking to remember
the target of the clear commands and regenerate TS clears if needed, simply
split the storage for compiled TS and non-TS clear commands.
Fixes: df63f188e8
("etnaviv: fix separate depth/stencil clears")
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Christian Gmeiner <cgmeiner@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28696>
This commit is contained in:
@@ -332,9 +332,6 @@ etna_blit_clear_color_rs(struct pipe_context *pctx, struct pipe_surface *dst,
|
||||
struct etna_surface *surf = etna_surface(dst);
|
||||
uint64_t new_clear_value = etna_clear_blit_pack_rgba(surf->base.format, color);
|
||||
|
||||
if (!surf->clear_command.valid)
|
||||
etna_rs_gen_clear_surface(ctx, surf, surf->level->clear_value);
|
||||
|
||||
if (surf->level->ts_size) { /* TS: use precompiled clear command */
|
||||
ctx->framebuffer.TS_COLOR_CLEAR_VALUE = new_clear_value;
|
||||
ctx->framebuffer.TS_COLOR_CLEAR_VALUE_EXT = new_clear_value >> 32;
|
||||
@@ -351,14 +348,20 @@ etna_blit_clear_color_rs(struct pipe_context *pctx, struct pipe_surface *dst,
|
||||
etna_resource_ext_ts(etna_resource(dst->texture))))
|
||||
surf->level->ts_meta->v0.clear_value = new_clear_value;
|
||||
|
||||
assert(surf->ts_clear_command.valid);
|
||||
etna_submit_rs_state(ctx, &surf->ts_clear_command);
|
||||
|
||||
etna_resource_level_ts_mark_valid(surf->level);
|
||||
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 */
|
||||
/* If clear color changed, re-generate stored command */
|
||||
etna_rs_gen_clear_surface(ctx, surf, new_clear_value);
|
||||
}
|
||||
} else { /* Queue normal RS clear for non-TS surfaces */
|
||||
/* If clear color changed or no valid command yet (re-)generate
|
||||
* stored command */
|
||||
if (unlikely(new_clear_value != surf->level->clear_value ||
|
||||
!surf->clear_command.valid))
|
||||
etna_rs_gen_clear_surface(ctx, surf, new_clear_value);
|
||||
|
||||
etna_submit_rs_state(ctx, &surf->clear_command);
|
||||
etna_submit_rs_state(ctx, &surf->clear_command);
|
||||
}
|
||||
|
||||
surf->level->clear_value = new_clear_value;
|
||||
resource_written(ctx, surf->base.texture);
|
||||
@@ -374,9 +377,6 @@ etna_blit_clear_zs_rs(struct pipe_context *pctx, struct pipe_surface *dst,
|
||||
uint32_t new_clear_value = translate_clear_depth_stencil(surf->base.format, depth, stencil);
|
||||
uint32_t new_clear_bits = 0, clear_bits_depth, clear_bits_stencil;
|
||||
|
||||
if (!surf->clear_command.valid)
|
||||
etna_rs_gen_clear_surface(ctx, surf, surf->level->clear_value);
|
||||
|
||||
/* Get the channels to clear */
|
||||
switch (surf->base.format) {
|
||||
case PIPE_FORMAT_Z16_UNORM:
|
||||
@@ -408,26 +408,31 @@ etna_blit_clear_zs_rs(struct pipe_context *pctx, struct pipe_surface *dst,
|
||||
ctx->framebuffer.TS_MEM_CONFIG |= VIVS_TS_MEM_CONFIG_DEPTH_AUTO_DISABLE;
|
||||
}
|
||||
|
||||
assert(surf->ts_clear_command.valid);
|
||||
etna_submit_rs_state(ctx, &surf->ts_clear_command);
|
||||
|
||||
etna_resource_level_ts_mark_valid(surf->level);
|
||||
ctx->dirty |= ETNA_DIRTY_TS;
|
||||
} else {
|
||||
} else { /* Queue normal RS clear for non-TS surfaces */
|
||||
/* If the level has valid TS state we need to flush it, as the regular
|
||||
* clear will not update the state and we must therefore invalidate it. */
|
||||
etna_copy_resource(pctx, surf->base.texture, surf->base.texture,
|
||||
surf->base.u.tex.level, surf->base.u.tex.level);
|
||||
|
||||
if (unlikely(new_clear_value != surf->level->clear_value)) { /* Queue normal RS clear for non-TS surfaces */
|
||||
/* If clear depth value changed, re-generate stored command */
|
||||
if (unlikely(new_clear_value != surf->level->clear_value ||
|
||||
!surf->clear_command.valid)) {
|
||||
/* If clear depth/stencil value changed or no valid command yet
|
||||
* (re)-generate stored command */
|
||||
etna_rs_gen_clear_surface(ctx, surf, new_clear_value);
|
||||
}
|
||||
/* Update the channels to be cleared */
|
||||
etna_modify_rs_clearbits(&surf->clear_command, new_clear_bits);
|
||||
|
||||
etna_submit_rs_state(ctx, &surf->clear_command);
|
||||
|
||||
etna_resource_level_ts_mark_invalid(surf->level);
|
||||
}
|
||||
|
||||
etna_submit_rs_state(ctx, &surf->clear_command);
|
||||
|
||||
surf->level->clear_value = new_clear_value;
|
||||
resource_written(ctx, surf->base.texture);
|
||||
etna_resource_level_mark_changed(surf->level);
|
||||
|
@@ -160,7 +160,7 @@ etna_create_surface(struct pipe_context *pctx, struct pipe_resource *prsc,
|
||||
* 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) {
|
||||
etna_compile_rs_state(ctx, &surf->ts_clear_command, &(struct rs_state) {
|
||||
.source_format = RS_FORMAT_A8R8G8B8,
|
||||
.dest_format = RS_FORMAT_A8R8G8B8,
|
||||
.dest = ts_bo,
|
||||
|
@@ -36,6 +36,7 @@ struct etna_surface {
|
||||
struct pipe_surface base;
|
||||
|
||||
struct compiled_rs_state clear_command;
|
||||
struct compiled_rs_state ts_clear_command;
|
||||
/* Keep pointer to resource level, for fast clear */
|
||||
struct etna_resource_level *level;
|
||||
struct etna_reloc reloc[ETNA_MAX_PIXELPIPES];
|
||||
|
Reference in New Issue
Block a user