From 44fcda9631ee94f2c28367b2d70e630de8a65734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Mon, 26 May 2025 10:14:24 -0400 Subject: [PATCH] nir/opt_clip_cull_const: support GS Reviewed-by: Alyssa Rosenzweig Part-of: --- src/compiler/nir/nir_opt_clip_cull_const.c | 95 +++++++++++++++++++--- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/src/compiler/nir/nir_opt_clip_cull_const.c b/src/compiler/nir/nir_opt_clip_cull_const.c index 0132f0e7b83..c7d827c01de 100644 --- a/src/compiler/nir/nir_opt_clip_cull_const.c +++ b/src/compiler/nir/nir_opt_clip_cull_const.c @@ -15,39 +15,114 @@ * and works best with scalar store_outputs. */ -static bool -opt_clip_cull(nir_builder *b, nir_intrinsic_instr *intr, void *unused) +/* Return -1 if invalid, 0 if it's a normal clip/cull distance value, + * and 1 if it's a no-op value. + */ +static int +analyze_clip_cull_value(nir_intrinsic_instr *intr) { if (intr->intrinsic != nir_intrinsic_store_output) - return false; + return -1; const nir_io_semantics io_sem = nir_intrinsic_io_semantics(intr); const unsigned location = io_sem.location; if (io_sem.no_sysval_output) - return false; + return -1; if (location != VARYING_SLOT_CLIP_DIST0 && location != VARYING_SLOT_CLIP_DIST1) - return false; + return -1; nir_def *val = intr->src[0].ssa; for (unsigned i = 0; i < val->num_components; i++) { nir_scalar s = nir_scalar_resolved(val, i); if (!nir_scalar_is_const(s)) - return false; + return 0; float distance = nir_scalar_as_float(s); /* NaN gets clipped, and INF after interpolation is NaN. */ if (isnan(distance) || distance < 0.0 || distance == INFINITY) - return false; + return 0; } - nir_remove_sysval_output(intr, MESA_SHADER_FRAGMENT); - return true; + return 1; +} + +static bool +opt_clip_cull_vs_tes(nir_builder *b, nir_intrinsic_instr *intr, void *unused) +{ + if (analyze_clip_cull_value(intr) == 1) { + nir_remove_sysval_output(intr, MESA_SHADER_FRAGMENT); + return true; + } + + return false; +} + +/* The types of stores are first gathered for all stores. If a certain slot + * component is only written by no-op stores, they are removed. + */ +typedef struct { + bool has_normal_store[8]; + bool has_noop_store[8]; +} gs_info; + +static unsigned +get_clip_io_index(nir_intrinsic_instr *intr) +{ + nir_io_semantics sem = nir_intrinsic_io_semantics(intr); + assert(intr->intrinsic == nir_intrinsic_store_output); + assert(sem.location == VARYING_SLOT_CLIP_DIST0 || + sem.location == VARYING_SLOT_CLIP_DIST1); + assert(sem.num_slots == 1); + assert(nir_src_as_uint(*nir_get_io_offset_src(intr)) == 0); /* no indirect */ + assert(intr->src[0].ssa->num_components == 1); /* scalar */ + + return (sem.location - VARYING_SLOT_CLIP_DIST0) * 4 + + nir_intrinsic_component(intr); +} + +static bool +gather_clip_cull_gs(nir_builder *b, nir_intrinsic_instr *intr, void *unused) +{ + gs_info *info = (gs_info *)unused; + int r = analyze_clip_cull_value(intr); + + if (r == 1) + info->has_noop_store[get_clip_io_index(intr)] = true; + else if (r == 0) + info->has_normal_store[get_clip_io_index(intr)] = true; + + return false; +} + +static bool +opt_clip_cull_gs(nir_builder *b, nir_intrinsic_instr *intr, void *unused) +{ + gs_info *info = (gs_info *)unused; + + if (intr->intrinsic == nir_intrinsic_store_output && + (nir_intrinsic_io_semantics(intr).location == VARYING_SLOT_CLIP_DIST0 || + nir_intrinsic_io_semantics(intr).location == VARYING_SLOT_CLIP_DIST1)) { + unsigned index = get_clip_io_index(intr); + + if (info->has_noop_store[index] && !info->has_normal_store[index]) { + nir_remove_sysval_output(intr, MESA_SHADER_FRAGMENT); + return true; + } + } + + return false; } bool nir_opt_clip_cull_const(nir_shader *shader) { - return nir_shader_intrinsics_pass(shader, opt_clip_cull, nir_metadata_control_flow, NULL); + if (shader->info.stage == MESA_SHADER_GEOMETRY) { + gs_info info = {0}; + nir_shader_intrinsics_pass(shader, gather_clip_cull_gs, nir_metadata_all, &info); + return nir_shader_intrinsics_pass(shader, opt_clip_cull_gs, nir_metadata_all, &info); + } else { + return nir_shader_intrinsics_pass(shader, opt_clip_cull_vs_tes, nir_metadata_all, NULL); + } }