From 6f541e2016f8b989084a03f5b4d33247586fb6e9 Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Wed, 11 Dec 2024 19:07:10 -0800 Subject: [PATCH] panfrost: add intrinsic to load frag coord at a barycentric This is needed for noperspective lowering, where we need to multiply the varying value by gl_FragCoord.w at the same barycentric as the varying. Normal nir_load_frag_coord_zw instructions are lowered to the new intrinsic on bifrost with the pan_lower_frag_coord_zw pass. Signed-off-by: Benjamin Lee Reviewed-by: Boris Brezillon Part-of: --- src/compiler/nir/nir_divergence_analysis.c | 1 + src/compiler/nir/nir_intrinsics.py | 5 +++ src/compiler/nir/nir_opt_sink.c | 1 + src/panfrost/compiler/bifrost_compile.c | 21 ++++++++++--- src/panfrost/util/meson.build | 1 + src/panfrost/util/pan_ir.h | 2 ++ src/panfrost/util/pan_lower_frag_coord_zw.c | 34 +++++++++++++++++++++ 7 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 src/panfrost/util/pan_lower_frag_coord_zw.c diff --git a/src/compiler/nir/nir_divergence_analysis.c b/src/compiler/nir/nir_divergence_analysis.c index d60145c6a7f..860b5bdd9fd 100644 --- a/src/compiler/nir/nir_divergence_analysis.c +++ b/src/compiler/nir/nir_divergence_analysis.c @@ -763,6 +763,7 @@ visit_intrinsic(nir_intrinsic_instr *instr, struct divergence_state *state) case nir_intrinsic_load_line_coord: case nir_intrinsic_load_frag_coord: case nir_intrinsic_load_frag_coord_zw: + case nir_intrinsic_load_frag_coord_zw_pan: case nir_intrinsic_load_frag_coord_unscaled_ir3: case nir_intrinsic_load_pixel_coord: case nir_intrinsic_load_fully_covered: diff --git a/src/compiler/nir/nir_intrinsics.py b/src/compiler/nir/nir_intrinsics.py index 61c595cd294..dd00ce80246 100644 --- a/src/compiler/nir/nir_intrinsics.py +++ b/src/compiler/nir/nir_intrinsics.py @@ -1504,6 +1504,11 @@ store("raw_output_pan", [], [IO_SEMANTICS, BASE]) store("combined_output_pan", [1, 1, 1, 4], [IO_SEMANTICS, COMPONENT, SRC_TYPE, DEST_TYPE]) load("raw_output_pan", [1], [IO_SEMANTICS], [CAN_ELIMINATE, CAN_REORDER]) +# Like the frag_coord_zw intrinsic, but takes a barycentric. This is needed for +# noperspective lowering. +# src[] = { barycoord } +intrinsic("load_frag_coord_zw_pan", [2], dest_comp=1, indices=[COMPONENT], flags=[CAN_ELIMINATE, CAN_REORDER], bit_sizes=[32]) + # Loads the sampler paramaters # src[] = { sampler_index } load("sampler_lod_parameters_pan", [1], flags=[CAN_ELIMINATE, CAN_REORDER]) diff --git a/src/compiler/nir/nir_opt_sink.c b/src/compiler/nir/nir_opt_sink.c index 4205b04e790..046cb9f0cc5 100644 --- a/src/compiler/nir/nir_opt_sink.c +++ b/src/compiler/nir/nir_opt_sink.c @@ -112,6 +112,7 @@ can_sink_instr(nir_instr *instr, nir_move_options options, bool *can_mov_out_of_ case nir_intrinsic_load_per_vertex_input: case nir_intrinsic_load_frag_coord: case nir_intrinsic_load_frag_coord_zw: + case nir_intrinsic_load_frag_coord_zw_pan: case nir_intrinsic_load_pixel_coord: case nir_intrinsic_load_attribute_pan: return options & nir_move_load_input; diff --git a/src/panfrost/compiler/bifrost_compile.c b/src/panfrost/compiler/bifrost_compile.c index 796246824e4..3cab9bbcbde 100644 --- a/src/panfrost/compiler/bifrost_compile.c +++ b/src/panfrost/compiler/bifrost_compile.c @@ -1654,11 +1654,21 @@ bi_emit_atomic_i32_to(bi_builder *b, bi_index dst, bi_index addr, bi_index arg, } static void -bi_emit_load_frag_coord_zw(bi_builder *b, bi_index dst, unsigned channel) +bi_emit_load_frag_coord_zw_pan(bi_builder *b, nir_intrinsic_instr *instr) { + bi_index dst = bi_def_index(&instr->def); + unsigned channel = nir_intrinsic_component(instr); + nir_intrinsic_instr *bary = nir_src_as_intrinsic(instr->src[0]); + + enum bi_sample sample = bi_interp_for_intrinsic(bary->intrinsic); + bi_index src0 = bi_varying_src0_for_barycentric(b, bary); + + /* .explicit is not supported with frag_z */ + if (channel == 2) + assert(sample != BI_SAMPLE_EXPLICIT); + bi_ld_var_special_to( - b, dst, bi_zero(), BI_REGISTER_FORMAT_F32, BI_SAMPLE_CENTER, - BI_UPDATE_CLOBBER, + b, dst, src0, BI_REGISTER_FORMAT_F32, sample, BI_UPDATE_CLOBBER, (channel == 2) ? BI_VARYING_NAME_FRAG_Z : BI_VARYING_NAME_FRAG_W, BI_VECSIZE_NONE); } @@ -1904,8 +1914,8 @@ bi_emit_intrinsic(bi_builder *b, nir_intrinsic_instr *instr) bi_mov_i32_to(b, dst, bi_preload(b, 59)); break; - case nir_intrinsic_load_frag_coord_zw: - bi_emit_load_frag_coord_zw(b, dst, nir_intrinsic_component(instr)); + case nir_intrinsic_load_frag_coord_zw_pan: + bi_emit_load_frag_coord_zw_pan(b, instr); break; case nir_intrinsic_load_converted_output_pan: @@ -5334,6 +5344,7 @@ bifrost_preprocess_nir(nir_shader *nir, unsigned gpu_id) NIR_PASS(_, nir, nir_lower_var_copies); NIR_PASS(_, nir, nir_lower_alu); NIR_PASS(_, nir, nir_lower_frag_coord_to_pixel_coord); + NIR_PASS(_, nir, pan_nir_lower_frag_coord_zw); } static bi_context * diff --git a/src/panfrost/util/meson.build b/src/panfrost/util/meson.build index a5e932178dc..e5b4718eaf8 100644 --- a/src/panfrost/util/meson.build +++ b/src/panfrost/util/meson.build @@ -9,6 +9,7 @@ libpanfrost_util_files = files( 'pan_ir.c', 'pan_ir.h', 'pan_liveness.c', + 'pan_lower_frag_coord_zw.c', 'pan_lower_framebuffer.c', 'pan_lower_helper_invocation.c', 'pan_lower_image_index.c', diff --git a/src/panfrost/util/pan_ir.h b/src/panfrost/util/pan_ir.h index 8168b550039..7366a564981 100644 --- a/src/panfrost/util/pan_ir.h +++ b/src/panfrost/util/pan_ir.h @@ -386,6 +386,8 @@ bool pan_nir_lower_store_component(nir_shader *shader); bool pan_nir_lower_image_ms(nir_shader *shader); +bool pan_nir_lower_frag_coord_zw(nir_shader *shader); + bool pan_lower_helper_invocation(nir_shader *shader); bool pan_lower_sample_pos(nir_shader *shader); bool pan_lower_xfb(nir_shader *nir); diff --git a/src/panfrost/util/pan_lower_frag_coord_zw.c b/src/panfrost/util/pan_lower_frag_coord_zw.c new file mode 100644 index 00000000000..741ca771f8f --- /dev/null +++ b/src/panfrost/util/pan_lower_frag_coord_zw.c @@ -0,0 +1,34 @@ +/* + * Copyright © 2024 Collabora Ltd. + * SPDX-License-Identifier: MIT + */ + +#include "compiler/nir/nir_builder.h" +#include "pan_ir.h" + +/* Lowers nir_load_frag_coord_zw to nir_load_frag_coord_zw_pan. */ + +static bool +lower_frag_coord_zw(nir_builder *b, nir_intrinsic_instr *intrin, void *data) +{ + if (intrin->intrinsic != nir_intrinsic_load_frag_coord_zw) + return false; + + b->cursor = nir_before_instr(&intrin->instr); + + nir_def *bary = nir_load_barycentric_pixel(b, 32, + .interp_mode = INTERP_MODE_NOPERSPECTIVE + ); + unsigned component = nir_intrinsic_component(intrin); + nir_def *new = nir_load_frag_coord_zw_pan(b, bary, .component = component); + nir_def_replace(&intrin->def, new); + + return true; +} + +bool +pan_nir_lower_frag_coord_zw(nir_shader *shader) +{ + return nir_shader_intrinsics_pass(shader, lower_frag_coord_zw, + nir_metadata_control_flow, NULL); +}