From dcd80d31cfbc13c563121176f2eec4ddbe08e6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sun, 14 Aug 2022 08:20:01 -0400 Subject: [PATCH] radeonsi: set GS_STATE_OUTPRIM and PROVOKING_VTX_INDEX only when they change This moves setting those registers from an unconditional place in draw_vbo into si_set_rasterized_prim (for draw_vbo), si_update_rasterized_prim (for bind_xx_shader), and si_bind_rs_state. It's a little more complicated than expected. Reviewed-by: Pierre-Eric Pelloux-Prayer Part-of: --- src/gallium/drivers/radeonsi/si_pipe.h | 30 +++++++++++++++++-- src/gallium/drivers/radeonsi/si_state.c | 3 ++ .../drivers/radeonsi/si_state_draw.cpp | 29 ++++++++---------- .../drivers/radeonsi/si_state_shaders.cpp | 9 ++++-- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h index 7bafc9932f5..811f34075db 100644 --- a/src/gallium/drivers/radeonsi/si_pipe.h +++ b/src/gallium/drivers/radeonsi/si_pipe.h @@ -2105,9 +2105,34 @@ void si_check_dirty_buffers_textures(struct si_context *sctx) } } -/* Set the primitive type seen by the rasterizer. GS and tessellation affect this. */ +/* Update these two GS_STATE fields. They depend on whatever the last shader before PS is + * and the rasterizer state. + * + * It's expected that hw_vs and ngg are inline constants in draw_vbo after optimizations. + */ static inline void -si_set_rasterized_prim(struct si_context *sctx, enum pipe_prim_type rast_prim) +si_update_ngg_prim_state_sgpr(struct si_context *sctx, struct si_shader *hw_vs, bool ngg) +{ + if (!ngg || !hw_vs) + return; + + if (hw_vs->uses_vs_state_provoking_vertex) { + unsigned vtx_index = sctx->queued.named.rasterizer->flatshade_first ? 0 : sctx->gs_out_prim; + + SET_FIELD(sctx->current_gs_state, GS_STATE_PROVOKING_VTX_INDEX, vtx_index); + } + + if (hw_vs->uses_gs_state_outprim) { + SET_FIELD(sctx->current_gs_state, GS_STATE_OUTPRIM, sctx->gs_out_prim); + } +} + +/* Set the primitive type seen by the rasterizer. GS and tessellation affect this. + * It's expected that hw_vs and ngg are inline constants in draw_vbo after optimizations. + */ +static inline void +si_set_rasterized_prim(struct si_context *sctx, enum pipe_prim_type rast_prim, + struct si_shader *hw_vs, bool ngg) { if (rast_prim != sctx->current_rast_prim) { bool is_rect = rast_prim == SI_PRIM_RECTANGLE_LIST; @@ -2123,6 +2148,7 @@ si_set_rasterized_prim(struct si_context *sctx, enum pipe_prim_type rast_prim) is_lines ? V_028A6C_LINESTRIP : is_rect ? V_028A6C_RECTLIST : V_028A6C_POINTLIST; sctx->do_update_shaders = true; + si_update_ngg_prim_state_sgpr(sctx, hw_vs, ngg); } } diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c index ba0b20404e3..4afee51d1d9 100644 --- a/src/gallium/drivers/radeonsi/si_state.c +++ b/src/gallium/drivers/radeonsi/si_state.c @@ -1215,6 +1215,9 @@ static void si_bind_rs_state(struct pipe_context *ctx, void *state) old_rs->poly_stipple_enable != rs->poly_stipple_enable || old_rs->flatshade != rs->flatshade) si_update_vrs_flat_shading(sctx); + + if (old_rs->flatshade_first != rs->flatshade_first) + si_update_ngg_prim_state_sgpr(sctx, si_get_vs(sctx)->current, sctx->ngg); } static void si_delete_rs_state(struct pipe_context *ctx, void *state) diff --git a/src/gallium/drivers/radeonsi/si_state_draw.cpp b/src/gallium/drivers/radeonsi/si_state_draw.cpp index 23e80fc3e0b..63c1de0951a 100644 --- a/src/gallium/drivers/radeonsi/si_state_draw.cpp +++ b/src/gallium/drivers/radeonsi/si_state_draw.cpp @@ -110,6 +110,8 @@ static bool si_update_shaders(struct si_context *sctx) struct pipe_context *ctx = (struct pipe_context *)sctx; struct si_shader *old_vs = si_get_vs_inline(sctx, HAS_TESS, HAS_GS)->current; unsigned old_pa_cl_vs_out_cntl = old_vs ? old_vs->pa_cl_vs_out_cntl : 0; + bool old_uses_vs_state_provoking_vertex = old_vs ? old_vs->uses_vs_state_provoking_vertex : false; + bool old_uses_gs_state_outprim = old_vs ? old_vs->uses_gs_state_outprim : false; struct si_shader *old_ps = sctx->shader.ps.current; unsigned old_spi_shader_col_format = old_ps ? old_ps->key.ps.part.epilog.spi_shader_col_format : 0; @@ -247,10 +249,16 @@ static bool si_update_shaders(struct si_context *sctx) *pm4 = si_build_vgt_shader_config(sctx->screen, key); si_pm4_bind_state(sctx, vgt_shader_config, *pm4); - if (old_pa_cl_vs_out_cntl != - si_get_vs_inline(sctx, HAS_TESS, HAS_GS)->current->pa_cl_vs_out_cntl) + struct si_shader *hw_vs = si_get_vs_inline(sctx, HAS_TESS, HAS_GS)->current; + + if (old_pa_cl_vs_out_cntl != hw_vs->pa_cl_vs_out_cntl) si_mark_atom_dirty(sctx, &sctx->atoms.s.clip_regs); + /* If we start to use any of these, we need to update the SGPR. */ + if ((hw_vs->uses_vs_state_provoking_vertex && !old_uses_vs_state_provoking_vertex) || + (hw_vs->uses_gs_state_outprim && !old_uses_gs_state_outprim)) + si_update_ngg_prim_state_sgpr(sctx, hw_vs, NGG); + r = si_shader_select(ctx, &sctx->shader.ps); if (r) return false; @@ -1157,20 +1165,6 @@ static void si_emit_rasterizer_prim_state(struct si_context *sctx) radeon_end_update_context_roll(sctx); else radeon_end(); - - if (NGG) { - struct si_shader *hw_vs = si_get_vs_inline(sctx, HAS_TESS, HAS_GS)->current; - - if (hw_vs->uses_vs_state_provoking_vertex) { - unsigned vtx_index = rs->flatshade_first ? 0 : gs_out_prim; - - SET_FIELD(sctx->current_gs_state, GS_STATE_PROVOKING_VTX_INDEX, vtx_index); - } - - if (hw_vs->uses_gs_state_outprim) { - SET_FIELD(sctx->current_gs_state, GS_STATE_OUTPRIM, gs_out_prim); - } - } } template current, + NGG); } if (IS_DRAW_VERTEX_STATE) { diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.cpp b/src/gallium/drivers/radeonsi/si_state_shaders.cpp index 415d9cf4ec0..8d33e9bb767 100644 --- a/src/gallium/drivers/radeonsi/si_state_shaders.cpp +++ b/src/gallium/drivers/radeonsi/si_state_shaders.cpp @@ -3313,15 +3313,20 @@ static void si_update_clip_regs(struct si_context *sctx, struct si_shader_select static void si_update_rasterized_prim(struct si_context *sctx) { + struct si_shader *hw_vs = si_get_vs(sctx)->current; + if (sctx->shader.gs.cso) { /* Only possibilities: POINTS, LINE_STRIP, TRIANGLES */ - si_set_rasterized_prim(sctx, sctx->shader.gs.cso->rast_prim); + si_set_rasterized_prim(sctx, sctx->shader.gs.cso->rast_prim, hw_vs, sctx->ngg); } else if (sctx->shader.tes.cso) { /* Only possibilities: POINTS, LINE_STRIP, TRIANGLES */ - si_set_rasterized_prim(sctx, sctx->shader.tes.cso->rast_prim); + si_set_rasterized_prim(sctx, sctx->shader.tes.cso->rast_prim, hw_vs, sctx->ngg); } else { /* The rasterized prim is determined by draw calls. */ } + + /* This must be done unconditionally because it also depends on si_shader fields. */ + si_update_ngg_prim_state_sgpr(sctx, hw_vs, sctx->ngg); } static void si_update_common_shader_state(struct si_context *sctx, struct si_shader_selector *sel,