From 0d961b0723928186780cb52f271fcc5ea66e3461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Mon, 30 Dec 2024 23:40:05 -0500 Subject: [PATCH] nir: add barycentric coordinates src to load_point_coord_maybe_flipped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like other input loads, radeonsi needs to know the barycentric coordinates for it. This adds the src and determines the optimal barycentric coordinates in nir_lower_point_smooth, the only producer of the intrinsic. Reviewed-by: Timur Kristóf Part-of: --- src/compiler/nir/nir.h | 2 +- src/compiler/nir/nir_intrinsics.py | 4 +- src/compiler/nir/nir_lower_point_smooth.c | 66 ++++++++++++++++++++--- src/gallium/drivers/radeonsi/si_shader.c | 2 +- src/gallium/drivers/zink/zink_compiler.c | 2 +- 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 194fdc4bd2a..2d98ed86bdc 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -7107,7 +7107,7 @@ nir_opt_preamble(nir_shader *shader, nir_function_impl *nir_shader_get_preamble(nir_shader *shader); -bool nir_lower_point_smooth(nir_shader *shader); +bool nir_lower_point_smooth(nir_shader *shader, bool set_barycentrics); bool nir_lower_poly_line_smooth(nir_shader *shader, unsigned num_smooth_aa_sample); bool nir_mod_analysis(nir_scalar val, nir_alu_type val_type, unsigned div, unsigned *mod); diff --git a/src/compiler/nir/nir_intrinsics.py b/src/compiler/nir/nir_intrinsics.py index d8f271f8d3a..1b41bebf6af 100644 --- a/src/compiler/nir/nir_intrinsics.py +++ b/src/compiler/nir/nir_intrinsics.py @@ -2398,7 +2398,9 @@ system_value("sm_id_nv", 1, bit_sizes=[32]) # flipped in hardware based on a state bit. This version of gl_PointCoord # is defined to be whatever thing the hardware can easily give you, so long as # it's in normalized coordinates in the range [0, 1] across the point. -intrinsic("load_point_coord_maybe_flipped", dest_comp=2, bit_sizes=[32]) +# +# src0 contains barycentrics for interpolation. +intrinsic("load_point_coord_maybe_flipped", dest_comp=2, bit_sizes=[32], src_comp=[2]) # Load texture size values: diff --git a/src/compiler/nir/nir_lower_point_smooth.c b/src/compiler/nir/nir_lower_point_smooth.c index e6a64999d50..5f692bbc031 100644 --- a/src/compiler/nir/nir_lower_point_smooth.c +++ b/src/compiler/nir/nir_lower_point_smooth.c @@ -25,6 +25,29 @@ #include "nir_builder.h" #include "nir_builtin_builder.h" +typedef struct { + bool set_barycentrics; + nir_intrinsic_instr *found_baryc; +} lower_point_smooth_state; + +static nir_intrinsic_instr * +find_any_used_barycentrics(nir_function_impl *impl) +{ + nir_foreach_block(block, impl) { + nir_foreach_instr(instr, block) { + if (instr->type == nir_instr_type_intrinsic) { + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + if (intr->intrinsic == nir_intrinsic_load_barycentric_pixel || + intr->intrinsic == nir_intrinsic_load_barycentric_centroid || + intr->intrinsic == nir_intrinsic_load_barycentric_sample) + return intr; + } + } + } + + return NULL; +} + /** * This NIR lowers pass for point smoothing by modifying the alpha value of * fragment outputs using the distance from the center of the point. @@ -32,9 +55,10 @@ */ static bool -lower_point_smooth(nir_builder *b, nir_intrinsic_instr *intr, - UNUSED void *_state) +lower_point_smooth(nir_builder *b, nir_intrinsic_instr *intr, void *state) { + lower_point_smooth_state *s = (lower_point_smooth_state *)state; + if (intr->intrinsic != nir_intrinsic_store_output && intr->intrinsic != nir_intrinsic_store_deref) return false; @@ -59,14 +83,37 @@ lower_point_smooth(nir_builder *b, nir_intrinsic_instr *intr, b->cursor = nir_before_instr(&intr->instr); - nir_def *coord = nir_load_point_coord_maybe_flipped(b); + /* Determine the barycentric coordinates. */ + nir_def *baryc; + + if (s->set_barycentrics) { + baryc = nir_load_barycentric_pixel(b, 32, + .interp_mode = INTERP_MODE_SMOOTH); + + /* Since point interpolation mostly doesn't care about which barycentrics + * are used, use any that are used by the shader. This is an optimization + * for hw that is faster if only one set of barycentrics is used. + */ + if (s->found_baryc) { + nir_intrinsic_instr *baryc_intr = + nir_instr_as_intrinsic(baryc->parent_instr); + + /* Overwrite the intrinsic we just created. */ + baryc_intr->intrinsic = s->found_baryc->intrinsic; + nir_intrinsic_set_interp_mode(baryc_intr, + nir_intrinsic_interp_mode(s->found_baryc)); + } + } else { + baryc = nir_undef(b, 2, 32); + } + + nir_def *coord = nir_load_point_coord_maybe_flipped(b, baryc); /* point_size = 1.0 / dFdx(gl_PointCoord.x); */ nir_def *point_size = nir_frcp(b, nir_ddx(b, nir_channel(b, coord, 0))); /* radius = point_size * 0.5 */ nir_def *radius = nir_fmul_imm(b, point_size, 0.5); - ; /** * Compute the distance of point from centre @@ -92,12 +139,19 @@ lower_point_smooth(nir_builder *b, nir_intrinsic_instr *intr, } bool -nir_lower_point_smooth(nir_shader *shader) +nir_lower_point_smooth(nir_shader *shader, bool set_barycentrics) { assert(shader->info.stage == MESA_SHADER_FRAGMENT); + nir_function_impl *impl = nir_shader_get_entrypoint(shader); + + lower_point_smooth_state state = { + .set_barycentrics = set_barycentrics, + .found_baryc = set_barycentrics ? find_any_used_barycentrics(impl) : NULL, + }; + return nir_shader_intrinsics_pass(shader, lower_point_smooth, nir_metadata_loop_analysis | nir_metadata_block_index | nir_metadata_dominance, - NULL); + &state); } diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index 5bc4a38c3a3..b467df0fb5c 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -2411,7 +2411,7 @@ static struct nir_shader *si_get_nir_shader(struct si_shader *shader, struct si_ NIR_PASS(progress, nir, nir_lower_poly_line_smooth, SI_NUM_SMOOTH_AA_SAMPLES); if (key->ps.mono.point_smoothing) - NIR_PASS(progress, nir, nir_lower_point_smooth); + NIR_PASS(progress, nir, nir_lower_point_smooth, true); NIR_PASS(progress, nir, nir_lower_fragcoord_wtrans); } diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index bf153b428d7..5520dfbbf71 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -4029,7 +4029,7 @@ zink_shader_compile(struct zink_screen *screen, bool can_shobj, struct zink_shad NIR_PASS_V(nir, lower_line_stipple_fs); if (zink_fs_key(key)->lower_point_smooth) { - NIR_PASS_V(nir, nir_lower_point_smooth); + NIR_PASS_V(nir, nir_lower_point_smooth, false); NIR_PASS_V(nir, nir_lower_discard_if, nir_lower_discard_if_to_cf); nir->info.fs.uses_discard = true; need_optimize = true;