From 3dcbf743c4d4b3146f255ac192634b2a8fa1a881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Tue, 14 Jan 2025 22:33:18 -0500 Subject: [PATCH] radeonsi: implement replacing frag_coord with pixel_coord at draw time This adds an option into the prolog key to replace frag_coord.xy with pixel_coord when sample shading is disabled, which is most of the time. This reduces the number of input VGPRs. It's already implement in ac_nir_lower_ps_early for monolithic shaders and the PS prolog in ACO, so this just implements it for the PS prolog in LLVM IR. Reviewed-by: Pierre-Eric Pelloux-Prayer --- src/gallium/drivers/radeonsi/si_shader.c | 37 ++++++++++++++----- src/gallium/drivers/radeonsi/si_shader.h | 2 + src/gallium/drivers/radeonsi/si_shader_aco.c | 2 + .../drivers/radeonsi/si_shader_llvm_ps.c | 23 +++++++++++- .../drivers/radeonsi/si_state_shaders.cpp | 4 ++ 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index 00e2459b304..2df02422b15 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -1572,6 +1572,8 @@ static void si_dump_shader_key(const struct si_shader *shader, FILE *f) key->ps.part.prolog.bc_optimize_for_linear); fprintf(f, " prolog.samplemask_log_ps_iter = %u\n", key->ps.part.prolog.samplemask_log_ps_iter); + fprintf(f, " prolog.get_frag_coord_from_pixel_coord = %u\n", + key->ps.part.prolog.get_frag_coord_from_pixel_coord); fprintf(f, " epilog.spi_shader_col_format = 0x%x\n", key->ps.part.epilog.spi_shader_col_format); fprintf(f, " epilog.color_is_int8 = 0x%X\n", key->ps.part.epilog.color_is_int8); @@ -2491,11 +2493,13 @@ static struct nir_shader *si_get_nir_shader(struct si_shader *shader, struct si_ key->ps.mono.interpolate_at_sample_force_center, .load_sample_positions_always_loads_current_ones = true, .force_front_face = key->ps.opt.force_front_face_input, + .optimize_frag_coord = true, /* This does a lot of things. See the description in ac_nir_lower_ps_early_options. */ .ps_iter_samples = key->ps.part.prolog.samplemask_log_ps_iter ? (1 << key->ps.part.prolog.samplemask_log_ps_iter) : (key->ps.part.prolog.force_persp_sample_interp || - key->ps.part.prolog.force_linear_sample_interp ? 2 : 0), + key->ps.part.prolog.force_linear_sample_interp ? 2 : + (key->ps.part.prolog.get_frag_coord_from_pixel_coord ? 1 : 0)), .fbfetch_is_1D = key->ps.mono.fbfetch_is_1D, .fbfetch_layered = key->ps.mono.fbfetch_layered, @@ -2538,6 +2542,7 @@ static struct nir_shader *si_get_nir_shader(struct si_shader *shader, struct si_ } } else if (nir->info.stage == MESA_SHADER_FRAGMENT) { ac_nir_lower_ps_early_options early_options = { + .optimize_frag_coord = true, .alpha_func = COMPARE_FUNC_ALWAYS, .spi_shader_col_format_hint = ~0, }; @@ -2908,6 +2913,12 @@ static void si_fixup_spi_ps_input_config(struct si_shader *shader) /* The sample mask fixup has an optimization that replaces the sample mask with the sample ID. */ if (key->ps.part.prolog.samplemask_log_ps_iter == 3) shader->config.spi_ps_input_ena &= C_0286CC_SAMPLE_COVERAGE_ENA; + + if (key->ps.part.prolog.get_frag_coord_from_pixel_coord) { + shader->config.spi_ps_input_ena &= C_0286CC_POS_X_FLOAT_ENA; + shader->config.spi_ps_input_ena &= C_0286CC_POS_Y_FLOAT_ENA; + shader->config.spi_ps_input_ena |= S_0286CC_POS_FIXED_PT_ENA(1); + } } static void @@ -2921,6 +2932,8 @@ si_set_spi_ps_input_config(struct si_shader *shader) * otherwise LLVM will have a performance advantage here because it determines * VGPR inputs for each shader variant after LLVM optimizations. */ + uint8_t frag_coord_mask = info->reads_frag_coord_mask | info->reads_sample_pos_mask; + shader->config.spi_ps_input_ena = S_0286CC_PERSP_CENTER_ENA(info->uses_persp_center) | S_0286CC_PERSP_CENTROID_ENA(info->uses_persp_centroid) | @@ -2928,14 +2941,16 @@ si_set_spi_ps_input_config(struct si_shader *shader) S_0286CC_LINEAR_CENTER_ENA(info->uses_linear_center) | S_0286CC_LINEAR_CENTROID_ENA(info->uses_linear_centroid) | S_0286CC_LINEAR_SAMPLE_ENA(info->uses_linear_sample) | + S_0286CC_POS_X_FLOAT_ENA(!!(frag_coord_mask & 0x1) && + !key->ps.part.prolog.get_frag_coord_from_pixel_coord) | + S_0286CC_POS_Y_FLOAT_ENA(!!(frag_coord_mask & 0x2) && + !key->ps.part.prolog.get_frag_coord_from_pixel_coord) | + S_0286CC_POS_Z_FLOAT_ENA(!!(frag_coord_mask & 0x4)) | + S_0286CC_POS_W_FLOAT_ENA(!!(frag_coord_mask & 0x8)) | S_0286CC_FRONT_FACE_ENA(info->uses_frontface && !key->ps.opt.force_front_face_input) | S_0286CC_SAMPLE_COVERAGE_ENA(info->reads_samplemask) | - S_0286CC_ANCILLARY_ENA(info->uses_sampleid || info->uses_layer_id); - - uint8_t mask = info->reads_frag_coord_mask | info->reads_sample_pos_mask; - u_foreach_bit(i, mask) { - shader->config.spi_ps_input_ena |= S_0286CC_POS_X_FLOAT_ENA(1) << i; - } + S_0286CC_ANCILLARY_ENA(info->uses_sampleid || info->uses_layer_id) | + S_0286CC_POS_FIXED_PT_ENA(key->ps.part.prolog.get_frag_coord_from_pixel_coord); if (key->ps.part.prolog.color_two_side) shader->config.spi_ps_input_ena |= S_0286CC_FRONT_FACE_ENA(1); @@ -3316,12 +3331,15 @@ static void si_get_ps_prolog_key(struct si_shader *shader, union si_shader_part_ key->ps_prolog.states.force_persp_center_interp || key->ps_prolog.states.force_linear_center_interp || key->ps_prolog.states.bc_optimize_for_persp || key->ps_prolog.states.bc_optimize_for_linear || - key->ps_prolog.states.samplemask_log_ps_iter); + key->ps_prolog.states.samplemask_log_ps_iter || + key->ps_prolog.states.get_frag_coord_from_pixel_coord); key->ps_prolog.fragcoord_usage_mask = G_0286CC_POS_X_FLOAT_ENA(shader->config.spi_ps_input_ena) | (G_0286CC_POS_Y_FLOAT_ENA(shader->config.spi_ps_input_ena) << 1) | (G_0286CC_POS_Z_FLOAT_ENA(shader->config.spi_ps_input_ena) << 2) | (G_0286CC_POS_W_FLOAT_ENA(shader->config.spi_ps_input_ena) << 3); + key->ps_prolog.pixel_center_integer = key->ps_prolog.fragcoord_usage_mask && + shader->selector->info.base.fs.pixel_center_integer; if (shader->key.ps.part.prolog.poly_stipple) shader->info.uses_vmem_load_other = true; @@ -3422,7 +3440,8 @@ static bool si_need_ps_prolog(const union si_shader_part_key *key) key->ps_prolog.states.force_linear_center_interp || key->ps_prolog.states.bc_optimize_for_persp || key->ps_prolog.states.bc_optimize_for_linear || key->ps_prolog.states.poly_stipple || - key->ps_prolog.states.samplemask_log_ps_iter; + key->ps_prolog.states.samplemask_log_ps_iter || + key->ps_prolog.states.get_frag_coord_from_pixel_coord; } /** diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h index 11f16ee73d8..d8b9d1f7bb0 100644 --- a/src/gallium/drivers/radeonsi/si_shader.h +++ b/src/gallium/drivers/radeonsi/si_shader.h @@ -676,6 +676,7 @@ struct si_ps_prolog_bits { unsigned bc_optimize_for_persp : 1; unsigned bc_optimize_for_linear : 1; unsigned samplemask_log_ps_iter : 2; + unsigned get_frag_coord_from_pixel_coord : 1; }; /* Common PS bits between the shader key and the epilog key. */ @@ -705,6 +706,7 @@ union si_shader_part_key { unsigned colors_read : 8; /* color input components read */ unsigned num_interp_inputs : 5; /* BCOLOR is at this location */ unsigned fragcoord_usage_mask : 4; + unsigned pixel_center_integer : 1; unsigned wqm : 1; char color_attr_index[2]; signed char color_interp_vgpr_index[2]; /* -1 == constant */ diff --git a/src/gallium/drivers/radeonsi/si_shader_aco.c b/src/gallium/drivers/radeonsi/si_shader_aco.c index edb0e3015ca..59734f3b89b 100644 --- a/src/gallium/drivers/radeonsi/si_shader_aco.c +++ b/src/gallium/drivers/radeonsi/si_shader_aco.c @@ -278,6 +278,8 @@ si_aco_build_ps_prolog(struct aco_compiler_options *options, .force_linear_center_interp = key->ps_prolog.states.force_linear_center_interp, .samplemask_log_ps_iter = key->ps_prolog.states.samplemask_log_ps_iter, + .get_frag_coord_from_pixel_coord = key->ps_prolog.states.get_frag_coord_from_pixel_coord, + .pixel_center_integer = key->ps_prolog.pixel_center_integer, .num_interp_inputs = key->ps_prolog.num_interp_inputs, .colors_read = key->ps_prolog.colors_read, .color_interp_vgpr_index[0] = key->ps_prolog.color_interp_vgpr_index[0], diff --git a/src/gallium/drivers/radeonsi/si_shader_llvm_ps.c b/src/gallium/drivers/radeonsi/si_shader_llvm_ps.c index 18a3037106b..252da11fe66 100644 --- a/src/gallium/drivers/radeonsi/si_shader_llvm_ps.c +++ b/src/gallium/drivers/radeonsi/si_shader_llvm_ps.c @@ -656,6 +656,28 @@ void si_llvm_build_ps_prolog(struct si_shader_context *ctx, union si_shader_part ret = insert_ret_of_arg(ctx, ret, sample_mask_in, args->ac.sample_coverage.arg_index); } + if (key->ps_prolog.states.get_frag_coord_from_pixel_coord) { + LLVMValueRef pixel_coord = ac_get_arg(&ctx->ac, args->ac.pos_fixed_pt); + pixel_coord = LLVMBuildBitCast(ctx->ac.builder, pixel_coord, ctx->ac.v2i16, ""); + pixel_coord = LLVMBuildUIToFP(ctx->ac.builder, pixel_coord, ctx->ac.v2f32, ""); + + if (!key->ps_prolog.pixel_center_integer) { + LLVMValueRef vec2_half = LLVMConstVector((LLVMValueRef[]){LLVMConstReal(ctx->ac.f32, 0.5), + LLVMConstReal(ctx->ac.f32, 0.5)}, 2); + pixel_coord = LLVMBuildFAdd(ctx->ac.builder, pixel_coord, vec2_half, ""); + } + + for (unsigned i = 0; i < 2; i++) { + if (!args->ac.frag_pos[i].used) + continue; + + ret = insert_ret_of_arg(ctx, ret, + LLVMBuildExtractElement(ctx->ac.builder, pixel_coord, + LLVMConstInt(ctx->ac.i32, i, 0), ""), + args->ac.frag_pos[i].arg_index); + } + } + /* Tell LLVM to insert WQM instruction sequence when needed. */ if (key->ps_prolog.wqm) { LLVMAddTargetDependentFunctionAttr(func, "amdgpu-ps-wqm-outputs", ""); @@ -754,4 +776,3 @@ void si_llvm_build_ps_epilog(struct si_shader_context *ctx, union si_shader_part /* Compile. */ LLVMBuildRetVoid(ctx->ac.builder); } - diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.cpp b/src/gallium/drivers/radeonsi/si_state_shaders.cpp index e4377bc91f5..4286e1f3908 100644 --- a/src/gallium/drivers/radeonsi/si_state_shaders.cpp +++ b/src/gallium/drivers/radeonsi/si_state_shaders.cpp @@ -2874,6 +2874,8 @@ void si_ps_key_update_framebuffer_rasterizer_sample_shading(struct si_context *s uses_persp_center && uses_persp_centroid; key->ps.part.prolog.bc_optimize_for_linear = sel->info.uses_linear_center && sel->info.uses_linear_centroid; + key->ps.part.prolog.get_frag_coord_from_pixel_coord = + !sel->info.base.fs.uses_sample_shading && sel->info.reads_frag_coord_mask & 0x3; key->ps.mono.interpolate_at_sample_force_center = 0; } else { key->ps.part.prolog.force_persp_sample_interp = 0; @@ -2890,6 +2892,8 @@ void si_ps_key_update_framebuffer_rasterizer_sample_shading(struct si_context *s sel->info.uses_linear_sample > 1; key->ps.part.prolog.bc_optimize_for_persp = 0; key->ps.part.prolog.bc_optimize_for_linear = 0; + key->ps.part.prolog.get_frag_coord_from_pixel_coord = + !!(sel->info.reads_frag_coord_mask & 0x3); key->ps.mono.interpolate_at_sample_force_center = sel->info.uses_interp_at_sample; }