From 511a637a5c65a81948bfe49c7d834db67053133b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Thu, 21 Nov 2024 12:49:11 -0500 Subject: [PATCH] radeonsi: pass cull face state via user SGPRs for shader culling The culling code always computes the determinant for culling zero-area triangles, so passing the state via user SGPRs doesn't really add much shader code to justify having shader variants for front/back face culling that uses the same determinant. Reviewed-by: Pierre-Eric Pelloux-Prayer Part-of: --- .../drivers/radeonsi/si_nir_lower_abi.c | 4 +-- src/gallium/drivers/radeonsi/si_pipe.h | 14 +++++++++ src/gallium/drivers/radeonsi/si_shader.h | 16 +++++----- src/gallium/drivers/radeonsi/si_state.c | 31 ++++--------------- src/gallium/drivers/radeonsi/si_state.h | 3 +- .../drivers/radeonsi/si_state_draw.cpp | 3 +- .../drivers/radeonsi/si_state_viewport.c | 1 + 7 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/gallium/drivers/radeonsi/si_nir_lower_abi.c b/src/gallium/drivers/radeonsi/si_nir_lower_abi.c index d66b8424965..7f61e978293 100644 --- a/src/gallium/drivers/radeonsi/si_nir_lower_abi.c +++ b/src/gallium/drivers/radeonsi/si_nir_lower_abi.c @@ -420,10 +420,10 @@ static bool lower_intrinsic(nir_builder *b, nir_instr *instr, struct lower_abi_s replacement = nir_imm_bool(b, si_shader_culling_enabled(shader)); break; case nir_intrinsic_load_cull_back_face_enabled_amd: - replacement = nir_imm_bool(b, key->ge.opt.ngg_culling & SI_NGG_CULL_BACK_FACE); + replacement = nir_i2b(b, GET_FIELD_NIR(GS_STATE_CULL_FACE_BACK)); break; case nir_intrinsic_load_cull_front_face_enabled_amd: - replacement = nir_imm_bool(b, key->ge.opt.ngg_culling & SI_NGG_CULL_FRONT_FACE); + replacement = nir_i2b(b, GET_FIELD_NIR(GS_STATE_CULL_FACE_FRONT)); break; case nir_intrinsic_load_cull_small_triangle_precision_amd: replacement = get_small_prim_precision(b, s, false); diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h index 36e568400b0..6f4bc9a7160 100644 --- a/src/gallium/drivers/radeonsi/si_pipe.h +++ b/src/gallium/drivers/radeonsi/si_pipe.h @@ -2171,6 +2171,20 @@ si_update_ngg_sgpr_state_out_prim(struct si_context *sctx, struct si_shader *hw_ SET_FIELD(sctx->current_gs_state, GS_STATE_OUTPRIM, sctx->gs_out_prim); } +static inline void +si_update_ngg_cull_face_state(struct si_context *sctx) +{ + struct si_state_rasterizer *rs = sctx->queued.named.rasterizer; + + if (sctx->viewport0_y_inverted) { + SET_FIELD(sctx->current_gs_state, GS_STATE_CULL_FACE_FRONT, rs->ngg_cull_back); + SET_FIELD(sctx->current_gs_state, GS_STATE_CULL_FACE_BACK, rs->ngg_cull_front); + } else { + SET_FIELD(sctx->current_gs_state, GS_STATE_CULL_FACE_FRONT, rs->ngg_cull_front); + SET_FIELD(sctx->current_gs_state, GS_STATE_CULL_FACE_BACK, rs->ngg_cull_back); + } +} + /* 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. */ diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h index c0d2f437830..e58a1c45ad5 100644 --- a/src/gallium/drivers/radeonsi/si_shader.h +++ b/src/gallium/drivers/radeonsi/si_shader.h @@ -242,8 +242,12 @@ enum * can be 55 at most. The ESGS vertex stride in dwords is: NUM_ES_OUTPUTS * 4 + 1 * Only used by GFX9+ to compute LDS addresses of GS inputs. */ -#define GS_STATE_NUM_ES_OUTPUTS__SHIFT 13 +#define GS_STATE_NUM_ES_OUTPUTS__SHIFT 14 #define GS_STATE_NUM_ES_OUTPUTS__MASK 0x3f +#define GS_STATE_CULL_FACE_FRONT__SHIFT 20 +#define GS_STATE_CULL_FACE_FRONT__MASK 0x1 +#define GS_STATE_CULL_FACE_BACK__SHIFT 21 +#define GS_STATE_CULL_FACE_BACK__MASK 0x1 /* Small prim filter precision = num_samples / quant_mode where num_samples is in {1, 2, 4, 8} and * quant_mode is in {256, 1024, 4096}, which is equal to 1/2^n where n is between 5 and 12. * @@ -333,11 +337,9 @@ enum */ #define SI_NGG_CULL_VS_TRIANGLES (1 << 0) /* this implies W, view.xy, and small prim culling */ #define SI_NGG_CULL_VS_LINES (1 << 1) /* this implies W and view.xy culling */ -#define SI_NGG_CULL_BACK_FACE (1 << 2) /* back faces */ -#define SI_NGG_CULL_FRONT_FACE (1 << 3) /* front faces */ -#define SI_NGG_CULL_SMALL_LINES_DIAMOND_EXIT (1 << 4) /* cull small lines according to the diamond exit rule */ -#define SI_NGG_CULL_CLIP_PLANE_ENABLE(enable) (((enable) & 0xff) << 5) -#define SI_NGG_CULL_GET_CLIP_PLANE_ENABLE(x) (((x) >> 5) & 0xff) +#define SI_NGG_CULL_SMALL_LINES_DIAMOND_EXIT (1 << 2) /* cull small lines according to the diamond exit rule */ +#define SI_NGG_CULL_CLIP_PLANE_ENABLE(enable) (((enable) & 0xff) << 3) +#define SI_NGG_CULL_GET_CLIP_PLANE_ENABLE(x) (((x) >> 3) & 0xff) struct si_shader_profile { uint32_t blake3[BLAKE3_OUT_LEN32]; @@ -768,7 +770,7 @@ struct si_shader_key_ge { unsigned remove_streamout : 1; /* For NGG VS and TES. */ - unsigned ngg_culling : 13; /* SI_NGG_CULL_* */ + unsigned ngg_culling : 11; /* SI_NGG_CULL_* */ /* For shaders where monolithic variants have better code. diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c index 0dd6b377cc6..7408fb2fd10 100644 --- a/src/gallium/drivers/radeonsi/si_state.c +++ b/src/gallium/drivers/radeonsi/si_state.c @@ -1016,35 +1016,15 @@ static void *si_create_rs_state(struct pipe_context *ctx, const struct pipe_rast S_028810_DX_LINEAR_ATTR_CLIP_ENA(1); rs->ngg_cull_flags_tris = SI_NGG_CULL_CLIP_PLANE_ENABLE(state->clip_plane_enable); - rs->ngg_cull_flags_tris_y_inverted = rs->ngg_cull_flags_tris; - rs->ngg_cull_flags_lines = (!rs->perpendicular_end_caps ? SI_NGG_CULL_SMALL_LINES_DIAMOND_EXIT : 0) | SI_NGG_CULL_CLIP_PLANE_ENABLE(state->clip_plane_enable); - if (rs->rasterizer_discard) { - rs->ngg_cull_flags_tris |= SI_NGG_CULL_FRONT_FACE | - SI_NGG_CULL_BACK_FACE; - rs->ngg_cull_flags_tris_y_inverted = rs->ngg_cull_flags_tris; + if (!state->front_ccw) { + rs->ngg_cull_front = state->cull_face & PIPE_FACE_FRONT || rs->rasterizer_discard; + rs->ngg_cull_back = state->cull_face & PIPE_FACE_BACK || rs->rasterizer_discard; } else { - bool cull_front, cull_back; - - if (!state->front_ccw) { - cull_front = !!(state->cull_face & PIPE_FACE_FRONT); - cull_back = !!(state->cull_face & PIPE_FACE_BACK); - } else { - cull_back = !!(state->cull_face & PIPE_FACE_FRONT); - cull_front = !!(state->cull_face & PIPE_FACE_BACK); - } - - if (cull_front) { - rs->ngg_cull_flags_tris |= SI_NGG_CULL_FRONT_FACE; - rs->ngg_cull_flags_tris_y_inverted |= SI_NGG_CULL_BACK_FACE; - } - - if (cull_back) { - rs->ngg_cull_flags_tris |= SI_NGG_CULL_BACK_FACE; - rs->ngg_cull_flags_tris_y_inverted |= SI_NGG_CULL_FRONT_FACE; - } + rs->ngg_cull_front = state->cull_face & PIPE_FACE_BACK || rs->rasterizer_discard; + rs->ngg_cull_back = state->cull_face & PIPE_FACE_FRONT || rs->rasterizer_discard; } /* Force gl_FrontFacing to true or false if the other face is culled. */ @@ -1335,6 +1315,7 @@ static void si_bind_rs_state(struct pipe_context *ctx, void *state) SET_FIELD(sctx->current_vs_state, VS_STATE_CLAMP_VERTEX_COLOR, rs->clamp_vertex_color); si_pm4_bind_state(sctx, rasterizer, rs); + si_update_ngg_cull_face_state(sctx); if (old_rs->scissor_enable != rs->scissor_enable) si_mark_atom_dirty(sctx, &sctx->atoms.s.scissors); diff --git a/src/gallium/drivers/radeonsi/si_state.h b/src/gallium/drivers/radeonsi/si_state.h index 54d1b3bfc71..bcb567bcddb 100644 --- a/src/gallium/drivers/radeonsi/si_state.h +++ b/src/gallium/drivers/radeonsi/si_state.h @@ -74,10 +74,11 @@ struct si_state_rasterizer { float line_width; float max_point_size; unsigned ngg_cull_flags_tris : 16; - unsigned ngg_cull_flags_tris_y_inverted : 16; unsigned ngg_cull_flags_lines : 16; unsigned sprite_coord_enable : 8; unsigned clip_plane_enable : 8; + bool ngg_cull_front : 1; + bool ngg_cull_back : 1; unsigned half_pixel_center : 1; unsigned flatshade : 1; unsigned flatshade_first : 1; diff --git a/src/gallium/drivers/radeonsi/si_state_draw.cpp b/src/gallium/drivers/radeonsi/si_state_draw.cpp index ff373bcee4f..aac689b1169 100644 --- a/src/gallium/drivers/radeonsi/si_state_draw.cpp +++ b/src/gallium/drivers/radeonsi/si_state_draw.cpp @@ -2258,8 +2258,7 @@ static void si_draw(struct pipe_context *ctx, ngg_culling = rs->ngg_cull_flags_lines | (!HAS_TESS && !HAS_GS ? SI_NGG_CULL_VS_LINES : 0); } else { - ngg_culling = (sctx->viewport0_y_inverted ? rs->ngg_cull_flags_tris_y_inverted : - rs->ngg_cull_flags_tris) | + ngg_culling = rs->ngg_cull_flags_tris | (!HAS_TESS && !HAS_GS ? SI_NGG_CULL_VS_TRIANGLES : 0); } diff --git a/src/gallium/drivers/radeonsi/si_state_viewport.c b/src/gallium/drivers/radeonsi/si_state_viewport.c index 1ce3960cb2f..b72122eec58 100644 --- a/src/gallium/drivers/radeonsi/si_state_viewport.c +++ b/src/gallium/drivers/radeonsi/si_state_viewport.c @@ -486,6 +486,7 @@ static void si_set_viewport_states(struct pipe_context *pctx, unsigned start_slo if (start_slot == 0) { ctx->viewport0_y_inverted = state->scale[1] < 0; + si_update_ngg_cull_face_state(ctx); /* NGG cull state uses the viewport and quant mode. */ if (ctx->screen->use_ngg_culling)