diff --git a/src/amd/common/nir/ac_nir.h b/src/amd/common/nir/ac_nir.h index 2f91252fae3..70bd5c583c6 100644 --- a/src/amd/common/nir/ac_nir.h +++ b/src/amd/common/nir/ac_nir.h @@ -275,6 +275,9 @@ typedef struct { bool force_linear_sample_interp; bool force_persp_center_interp; bool force_linear_center_interp; + bool interpolate_at_sample_force_center; + bool load_sample_positions_always_loads_current_ones; + bool dynamic_rasterization_samples; int force_front_face; /* 0 -> keep, 1 -> set to true, -1 -> set to false */ unsigned ps_iter_samples; diff --git a/src/amd/common/nir/ac_nir_lower_ps_early.c b/src/amd/common/nir/ac_nir_lower_ps_early.c index 98b7eb38ff5..ebb79932edb 100644 --- a/src/amd/common/nir/ac_nir_lower_ps_early.c +++ b/src/amd/common/nir/ac_nir_lower_ps_early.c @@ -295,6 +295,25 @@ lower_ps_load_sample_mask_in(nir_builder *b, nir_intrinsic_instr *intrin, lower_ return true; } +static nir_def * +lower_load_barycentric_at_offset(nir_builder *b, nir_def *offset, enum glsl_interp_mode mode) +{ + nir_def *baryc = nir_load_barycentric_pixel(b, 32, .interp_mode = mode); + nir_def *i = nir_channel(b, baryc, 0); + nir_def *j = nir_channel(b, baryc, 1); + nir_def *offset_x = nir_channel(b, offset, 0); + nir_def *offset_y = nir_channel(b, offset, 1); + nir_def *ddx_i = nir_ddx(b, i); + nir_def *ddx_j = nir_ddx(b, j); + nir_def *ddy_i = nir_ddy(b, i); + nir_def *ddy_j = nir_ddy(b, j); + + /* Interpolate standard barycentrics by offset. */ + nir_def *offset_i = nir_ffma(b, ddy_i, offset_y, nir_ffma(b, ddx_i, offset_x, i)); + nir_def *offset_j = nir_ffma(b, ddy_j, offset_y, nir_ffma(b, ddx_j, offset_x, j)); + return nir_vec2(b, offset_i, offset_j); +} + static bool lower_ps_intrinsic(nir_builder *b, nir_instr *instr, void *state) { @@ -339,6 +358,49 @@ lower_ps_intrinsic(nir_builder *b, nir_instr *instr, void *state) /* sample_pos = ffract(frag_coord.xy); */ nir_def_replace(&intrin->def, nir_ffract(b, nir_channels(b, nir_load_frag_coord(b), 0x3))); return true; + case nir_intrinsic_load_barycentric_at_offset: + nir_def_replace(&intrin->def, + lower_load_barycentric_at_offset(b, intrin->src[0].ssa, + nir_intrinsic_interp_mode(intrin))); + return true; + case nir_intrinsic_load_barycentric_at_sample: { + unsigned mode = nir_intrinsic_interp_mode(intrin); + + if (s->options->interpolate_at_sample_force_center) { + nir_def_replace(&intrin->def, nir_load_barycentric_pixel(b, 32, .interp_mode = mode)); + return true; + } + + /* If load_sample_positions_always_loads_current_ones is true, load_sample_positions_amd + * always loads the sample positions that are currently set in the rasterizer state + * even if MSAA is disabled. + */ + nir_def *num_samples = s->options->load_sample_positions_always_loads_current_ones ? + nir_undef(b, 1, 32) : nir_load_rasterization_samples_amd(b); + nir_def *sample_id = intrin->src[0].ssa; + nir_def *sample_pos = nir_load_sample_positions_amd(b, 32, sample_id, num_samples); + sample_pos = nir_fadd_imm(b, sample_pos, -0.5f); + + if (s->options->dynamic_rasterization_samples) { + assert(!s->options->load_sample_positions_always_loads_current_ones); + nir_def *pixel, *at_sample; + + nir_push_if(b, nir_ieq_imm(b, num_samples, 1)); + { + pixel = nir_load_barycentric_pixel(b, 32, .interp_mode = mode); + } + nir_push_else(b, NULL); + { + at_sample = lower_load_barycentric_at_offset(b, sample_pos, mode); + } + nir_pop_if(b, NULL); + nir_def_replace(&intrin->def, nir_if_phi(b, pixel, at_sample)); + } else { + nir_def_replace(&intrin->def, + lower_load_barycentric_at_offset(b, sample_pos, mode)); + } + return true; + } default: break; } diff --git a/src/gallium/drivers/radeonsi/si_nir_lower_abi.c b/src/gallium/drivers/radeonsi/si_nir_lower_abi.c index dffde5d403c..0ce7cdca73c 100644 --- a/src/gallium/drivers/radeonsi/si_nir_lower_abi.c +++ b/src/gallium/drivers/radeonsi/si_nir_lower_abi.c @@ -531,23 +531,12 @@ static bool lower_intrinsic(nir_builder *b, nir_instr *instr, struct lower_abi_s replacement = nir_imm_int(b, (1 << 2) | (1 << 4)); } break; - case nir_intrinsic_load_barycentric_at_sample: { - unsigned mode = nir_intrinsic_interp_mode(intrin); - - if (key->ps.mono.interpolate_at_sample_force_center) { - replacement = nir_load_barycentric_pixel(b, 32, .interp_mode = mode); - } else { - nir_def *sample_id = intrin->src[0].ssa; - /* offset = sample_id * 8 (8 = 2 floats containing samplepos.xy) */ - nir_def *offset = nir_ishl_imm(b, sample_id, 3); - - nir_def *buf = si_nir_load_internal_binding(b, args, SI_PS_CONST_SAMPLE_POSITIONS, 4); - nir_def *sample_pos = nir_load_ubo(b, 2, 32, buf, offset, .range = ~0); - - sample_pos = nir_fadd_imm(b, sample_pos, -0.5); - - replacement = nir_load_barycentric_at_offset(b, 32, sample_pos, .interp_mode = mode); - } + case nir_intrinsic_load_sample_positions_amd: { + /* offset = sample_id * 8 (8 = 2 floats containing samplepos.xy) */ + nir_def *buf = si_nir_load_internal_binding(b, args, SI_PS_CONST_SAMPLE_POSITIONS, 4); + nir_def *sample_id = intrin->src[0].ssa; + nir_def *offset = nir_ishl_imm(b, sample_id, 3); + replacement = nir_load_ubo(b, 2, 32, buf, offset, .range = ~0); break; } case nir_intrinsic_load_output: { diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index a6e45ff317a..5d2ba04ed03 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -2528,6 +2528,8 @@ static struct nir_shader *si_get_nir_shader(struct si_shader *shader, struct si_ .force_linear_sample_interp = key->ps.part.prolog.force_linear_sample_interp, .force_persp_center_interp = key->ps.part.prolog.force_persp_center_interp, .force_linear_center_interp = key->ps.part.prolog.force_linear_center_interp, + .interpolate_at_sample_force_center = 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, .ps_iter_samples = 1 << key->ps.part.prolog.samplemask_log_ps_iter,