diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index d1f06a82bd8..4b7f91dbdd2 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -221,6 +221,7 @@ files_libnir = files( 'nir_normalize_cubemap_coords.c', 'nir_opt_access.c', 'nir_opt_barriers.c', + 'nir_opt_clip_cull_const.c', 'nir_opt_combine_stores.c', 'nir_opt_comparison_pre.c', 'nir_opt_conditional_discard.c', diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 77a472327d3..616353cd408 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -5718,6 +5718,8 @@ void nir_assign_io_var_locations(nir_shader *shader, unsigned *size, gl_shader_stage stage); +bool nir_opt_clip_cull_const(nir_shader *shader); + typedef enum { /* If set, this causes all 64-bit IO operations to be lowered on-the-fly * to 32-bit operations. This is only valid for nir_var_shader_in/out diff --git a/src/compiler/nir/nir_opt_clip_cull_const.c b/src/compiler/nir/nir_opt_clip_cull_const.c new file mode 100644 index 00000000000..9026d50605c --- /dev/null +++ b/src/compiler/nir/nir_opt_clip_cull_const.c @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Valve Corporation + * SPDX-License-Identifier: MIT + */ + +#include "nir.h" +#include "nir_builder.h" + +/** + * If a clip/cull distance is constant >= 0, + * we know that it will never cause clipping/culling. + * Remove the sysval_output in that case. + * + * Assumes that nir_lower_io_to_temporaries was run, + * and works best with scalar store_outputs. + */ + +static bool +opt_clip_cull(nir_builder *b, nir_intrinsic_instr *intr, void *unused) +{ + if (intr->intrinsic != nir_intrinsic_store_output) + return false; + + 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; + + if (location != VARYING_SLOT_CLIP_DIST0 && location != VARYING_SLOT_CLIP_DIST1) + return false; + + 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; + 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; + } + + nir_remove_sysval_output(intr); + return true; +} + +bool +nir_opt_clip_cull_const(nir_shader *shader) +{ + return nir_shader_intrinsics_pass(shader, opt_clip_cull, nir_metadata_control_flow, NULL); +}