etnaviv: Defer GPU state reset until first draw call

Currently, GPU state is reset immediately after each flush and during
context creation, even when the next command might be a simple BLT/RS
operation that doesn't require the full GPU rendering pipeline.

This patch introduces lazy GPU state reset by:
- Adding a needs_gpu_state_reset flag to track when reset is needed
- Setting the flag to true after flush instead of immediately resetting
- Only performing the actual reset in etna_draw_vbo() when rendering

Signed-off-by: Christian Gmeiner <cgmeiner@igalia.com>
Acked-by: Lucas Stach <l.stach@pengutronix.de>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36565>
This commit is contained in:
Christian Gmeiner
2025-08-04 23:45:12 +02:00
committed by Marge Bot
parent 55447790c4
commit ab86088438
2 changed files with 112 additions and 109 deletions

View File

@@ -227,6 +227,112 @@ static inline void clear_draw_flag(struct etna_context **ctx_ptr) {
struct etna_context *_draw_cleanup __attribute__((cleanup(clear_draw_flag))) = (ctx); \
(ctx)->in_draw_vbo = true
static void
etna_reset_gpu_state(struct etna_context *ctx)
{
struct etna_cmd_stream *stream = ctx->stream;
struct etna_screen *screen = ctx->screen;
uint32_t dummy_attribs[VIVS_NFE_GENERIC_ATTRIB__LEN] = { 0 };
if (ctx->compute_only) {
/* compute only context does not make use of any of the dirty state tracking. */
assert(ctx->dirty == 0);
assert(ctx->dirty_sampler_views == 0);
assert(ctx->prev_active_samplers == 0);
etna_cmd_stream_mark_end_of_context_init(stream);
return;
}
etna_set_state(stream, VIVS_GL_API_MODE, VIVS_GL_API_MODE_OPENGL);
etna_set_state(stream, VIVS_PA_W_CLIP_LIMIT, 0x34000001);
etna_set_state(stream, VIVS_PA_FLAGS, 0x00000000); /* blob sets ZCONVERT_BYPASS on GC3000+, this messes up z for us */
etna_set_state(stream, VIVS_PA_VIEWPORT_UNK00A80, 0x38a01404);
etna_set_state(stream, VIVS_PA_VIEWPORT_UNK00A84, fui(8192.0));
etna_set_state(stream, VIVS_PA_ZFARCLIPPING, 0x00000000);
etna_set_state(stream, VIVS_RA_HDEPTH_CONTROL, 0x00007000);
etna_set_state(stream, VIVS_PS_CONTROL_EXT, 0x00000000);
/* There is no HALTI0 specific state */
if (screen->info->halti >= 1) { /* Only on HALTI1+ */
etna_set_state(stream, VIVS_VS_HALTI1_UNK00884, 0x00000808);
}
if (screen->info->halti >= 2) { /* Only on HALTI2+ */
etna_set_state(stream, VIVS_RA_UNK00E0C, 0x00000000);
}
if (screen->info->halti >= 3) { /* Only on HALTI3+ */
etna_set_state(stream, VIVS_PS_HALTI3_UNK0103C, 0x76543210);
}
if (screen->info->halti >= 4) { /* Only on HALTI4+ */
etna_set_state(stream, VIVS_PE_HALTI4_UNK014C0, 0x00000000);
}
if (screen->info->halti >= 5) { /* Only on HALTI5+ */
etna_set_state(stream, VIVS_NTE_DESCRIPTOR_CONTROL,
COND(!DBG_ENABLED(ETNA_DBG_NO_TEXDESC), VIVS_NTE_DESCRIPTOR_CONTROL_ENABLE));
etna_set_state(stream, VIVS_FE_HALTI5_UNK007D8, 0x00000002);
etna_set_state(stream, VIVS_PS_SAMPLER_BASE, 0x00000000);
etna_set_state(stream, VIVS_VS_SAMPLER_BASE, 0x00000020);
etna_set_state(stream, VIVS_SH_CONFIG, VIVS_SH_CONFIG_RTNE_ROUNDING);
}
if (VIV_FEATURE(screen, ETNA_FEATURE_MSAA_FRAGMENT_OPERATION)) {
etna_set_state(stream, VIVS_PS_MSAA_CONFIG, 0x6fffffff & 0xf70fffff & 0xfff6ffff &
0xfffff6ff & 0xffffff7f);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(0), 0x6e80e680);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(1), 0x2ac42a4c);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(2), 0x15fb5d3b);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(3), 0x9d7391f7);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(4), 0x08e691f7);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(5), 0x4ca25d3b);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(6), 0xbf512a4c);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(7), 0x37d9e680);
}
if (VIV_FEATURE(screen, ETNA_FEATURE_BUG_FIXES18))
etna_set_state(stream, VIVS_GL_BUG_FIXES, 0x6);
if (screen->info->halti >= 5 && !DBG_ENABLED(ETNA_DBG_NO_TEXDESC)) {
/* TXDESC cache flush - do this once at the beginning, as texture
* descriptors are only written by the CPU once, then patched by the kernel
* before command stream submission. It does not need flushing if the
* referenced image data changes.
*/
etna_set_state(stream, VIVS_NTE_DESCRIPTOR_FLUSH, 0);
etna_set_state(stream, VIVS_GL_FLUSH_CACHE,
VIVS_GL_FLUSH_CACHE_DESCRIPTOR_UNK12 |
VIVS_GL_FLUSH_CACHE_DESCRIPTOR_UNK13);
/* Icache invalidate (should do this on shader change?) */
etna_set_state(stream, VIVS_VS_ICACHE_INVALIDATE,
VIVS_VS_ICACHE_INVALIDATE_UNK0 | VIVS_VS_ICACHE_INVALIDATE_UNK1 |
VIVS_VS_ICACHE_INVALIDATE_UNK2 | VIVS_VS_ICACHE_INVALIDATE_UNK3 |
VIVS_VS_ICACHE_INVALIDATE_UNK4);
}
/* It seems that some GPUs (at least some GC400 have shown this behavior)
* come out of reset with random vertex attributes enabled and also don't
* disable them on the write to the first config register as normal. Enabling
* all attributes seems to provide the GPU with the required edge to actually
* disable the unused attributes on the next draw.
*/
if (screen->info->halti >= 5) {
etna_set_state_multi(stream, VIVS_NFE_GENERIC_ATTRIB_CONFIG0(0),
VIVS_NFE_GENERIC_ATTRIB__LEN, dummy_attribs);
} else {
etna_set_state_multi(stream, VIVS_FE_VERTEX_ELEMENT_CONFIG(0),
screen->info->halti >= 0 ? 16 : 12, dummy_attribs);
}
etna_cmd_stream_mark_end_of_context_init(stream);
ctx->dirty = ~0L;
ctx->dirty_sampler_views = ~0L;
ctx->prev_active_samplers = ~0L;
ctx->needs_gpu_state_reset = false;
}
static void
etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
unsigned drawid_offset,
@@ -277,6 +383,9 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
return;
}
if (ctx->needs_gpu_state_reset)
etna_reset_gpu_state(ctx);
/* Upload a user index buffer. */
unsigned index_offset = 0;
struct pipe_resource *indexbuf = NULL;
@@ -479,111 +588,6 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
pipe_resource_reference(&indexbuf, NULL);
}
static void
etna_reset_gpu_state(struct etna_context *ctx)
{
struct etna_cmd_stream *stream = ctx->stream;
struct etna_screen *screen = ctx->screen;
uint32_t dummy_attribs[VIVS_NFE_GENERIC_ATTRIB__LEN] = { 0 };
if (ctx->compute_only) {
/* compute only context does not make use of any of the dirty state tracking. */
assert(ctx->dirty == 0);
assert(ctx->dirty_sampler_views == 0);
assert(ctx->prev_active_samplers == 0);
etna_cmd_stream_mark_end_of_context_init(stream);
return;
}
etna_set_state(stream, VIVS_GL_API_MODE, VIVS_GL_API_MODE_OPENGL);
etna_set_state(stream, VIVS_PA_W_CLIP_LIMIT, 0x34000001);
etna_set_state(stream, VIVS_PA_FLAGS, 0x00000000); /* blob sets ZCONVERT_BYPASS on GC3000+, this messes up z for us */
etna_set_state(stream, VIVS_PA_VIEWPORT_UNK00A80, 0x38a01404);
etna_set_state(stream, VIVS_PA_VIEWPORT_UNK00A84, fui(8192.0));
etna_set_state(stream, VIVS_PA_ZFARCLIPPING, 0x00000000);
etna_set_state(stream, VIVS_RA_HDEPTH_CONTROL, 0x00007000);
etna_set_state(stream, VIVS_PS_CONTROL_EXT, 0x00000000);
/* There is no HALTI0 specific state */
if (screen->info->halti >= 1) { /* Only on HALTI1+ */
etna_set_state(stream, VIVS_VS_HALTI1_UNK00884, 0x00000808);
}
if (screen->info->halti >= 2) { /* Only on HALTI2+ */
etna_set_state(stream, VIVS_RA_UNK00E0C, 0x00000000);
}
if (screen->info->halti >= 3) { /* Only on HALTI3+ */
etna_set_state(stream, VIVS_PS_HALTI3_UNK0103C, 0x76543210);
}
if (screen->info->halti >= 4) { /* Only on HALTI4+ */
etna_set_state(stream, VIVS_PE_HALTI4_UNK014C0, 0x00000000);
}
if (screen->info->halti >= 5) { /* Only on HALTI5+ */
etna_set_state(stream, VIVS_NTE_DESCRIPTOR_CONTROL,
COND(!DBG_ENABLED(ETNA_DBG_NO_TEXDESC), VIVS_NTE_DESCRIPTOR_CONTROL_ENABLE));
etna_set_state(stream, VIVS_FE_HALTI5_UNK007D8, 0x00000002);
etna_set_state(stream, VIVS_PS_SAMPLER_BASE, 0x00000000);
etna_set_state(stream, VIVS_VS_SAMPLER_BASE, 0x00000020);
etna_set_state(stream, VIVS_SH_CONFIG, VIVS_SH_CONFIG_RTNE_ROUNDING);
}
if (VIV_FEATURE(screen, ETNA_FEATURE_MSAA_FRAGMENT_OPERATION)) {
etna_set_state(stream, VIVS_PS_MSAA_CONFIG, 0x6fffffff & 0xf70fffff & 0xfff6ffff &
0xfffff6ff & 0xffffff7f);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(0), 0x6e80e680);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(1), 0x2ac42a4c);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(2), 0x15fb5d3b);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(3), 0x9d7391f7);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(4), 0x08e691f7);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(5), 0x4ca25d3b);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(6), 0xbf512a4c);
etna_set_state(stream, VIVS_PS_ALPHA_TO_COVERAGE_DITHER(7), 0x37d9e680);
}
if (VIV_FEATURE(screen, ETNA_FEATURE_BUG_FIXES18))
etna_set_state(stream, VIVS_GL_BUG_FIXES, 0x6);
if (screen->info->halti >= 5 && !DBG_ENABLED(ETNA_DBG_NO_TEXDESC)) {
/* TXDESC cache flush - do this once at the beginning, as texture
* descriptors are only written by the CPU once, then patched by the kernel
* before command stream submission. It does not need flushing if the
* referenced image data changes.
*/
etna_set_state(stream, VIVS_NTE_DESCRIPTOR_FLUSH, 0);
etna_set_state(stream, VIVS_GL_FLUSH_CACHE,
VIVS_GL_FLUSH_CACHE_DESCRIPTOR_UNK12 |
VIVS_GL_FLUSH_CACHE_DESCRIPTOR_UNK13);
/* Icache invalidate (should do this on shader change?) */
etna_set_state(stream, VIVS_VS_ICACHE_INVALIDATE,
VIVS_VS_ICACHE_INVALIDATE_UNK0 | VIVS_VS_ICACHE_INVALIDATE_UNK1 |
VIVS_VS_ICACHE_INVALIDATE_UNK2 | VIVS_VS_ICACHE_INVALIDATE_UNK3 |
VIVS_VS_ICACHE_INVALIDATE_UNK4);
}
/* It seems that some GPUs (at least some GC400 have shown this behavior)
* come out of reset with random vertex attributes enabled and also don't
* disable them on the write to the first config register as normal. Enabling
* all attributes seems to provide the GPU with the required edge to actually
* disable the unused attributes on the next draw.
*/
if (screen->info->halti >= 5) {
etna_set_state_multi(stream, VIVS_NFE_GENERIC_ATTRIB_CONFIG0(0),
VIVS_NFE_GENERIC_ATTRIB__LEN, dummy_attribs);
} else {
etna_set_state_multi(stream, VIVS_FE_VERTEX_ELEMENT_CONFIG(0),
screen->info->halti >= 0 ? 16 : 12, dummy_attribs);
}
etna_cmd_stream_mark_end_of_context_init(stream);
ctx->dirty = ~0L;
ctx->dirty_sampler_views = ~0L;
ctx->prev_active_samplers = ~0L;
}
void
etna_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence,
enum pipe_flush_flags flags, bool internal)
@@ -634,7 +638,7 @@ etna_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence,
_mesa_hash_table_clear(ctx->pending_resources, NULL);
etna_reset_gpu_state(ctx);
ctx->needs_gpu_state_reset = true;
}
static void
@@ -727,9 +731,7 @@ etna_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
ctx->sample_mask = 0xffff;
ctx->compute_only = compute_only;
/* Set sensible defaults for state */
etna_reset_gpu_state(ctx);
ctx->needs_gpu_state_reset = true;
ctx->in_fence_fd = -1;

View File

@@ -242,6 +242,7 @@ struct etna_context {
bool compute_only;
bool in_draw_vbo;
bool needs_gpu_state_reset;
/* conditional rendering */
struct pipe_query *cond_query;