intel/brw: add load_frag_shading_rate_intel

Add a new intrinsic to read the raw shading rate provided to the FS
payload, and lower load_frag_shading_rate in NIR using it.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Tested-by: Caleb Callaway <caleb.callaway@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38879>
This commit is contained in:
Iván Briano 2025-12-09 17:07:04 -08:00 committed by Marge Bot
parent 5383afadbf
commit fea8830946
4 changed files with 69 additions and 30 deletions

View file

@ -364,6 +364,7 @@ visit_intrinsic(nir_intrinsic_instr *instr, struct divergence_state *state)
case nir_intrinsic_load_call_return_address_amd:
case nir_intrinsic_load_indirect_address_intel:
case nir_intrinsic_load_alpha_to_coverage_enable_ir3:
case nir_intrinsic_load_frag_shading_rate_intel:
case nir_intrinsic_load_msaa_rate_intel:
is_divergent = false;
break;

View file

@ -2656,6 +2656,9 @@ system_value("coverage_mask_intel", 1)
# MSAA rate provided by the FS payload.
system_value("msaa_rate_intel", 1)
# Raw fragment shading rate provided to the FS payload.
system_value("frag_shading_rate_intel", 2)
# Load a relocatable 32-bit value
intrinsic("load_reloc_const_intel", dest_comp=1, bit_sizes=[32],
indices=[PARAM_IDX, BASE], flags=[CAN_ELIMINATE, CAN_REORDER])

View file

@ -54,7 +54,6 @@ static void brw_from_nir_emit_intrinsic(nir_to_brw_state &ntb, const brw_builder
static brw_reg emit_samplepos_setup(nir_to_brw_state &ntb);
static brw_reg emit_sampleid_setup(nir_to_brw_state &ntb);
static brw_reg emit_samplemaskin_setup(nir_to_brw_state &ntb);
static brw_reg emit_shading_rate_setup(nir_to_brw_state &ntb);
static void brw_from_nir_emit_impl(nir_to_brw_state &ntb, nir_function_impl *impl);
static void brw_from_nir_emit_cf_list(nir_to_brw_state &ntb, exec_list *list);
@ -222,12 +221,6 @@ emit_system_values_block(nir_to_brw_state &ntb, nir_block *block)
}
break;
case nir_intrinsic_load_frag_shading_rate:
reg = &ntb.system_values[SYSTEM_VALUE_FRAG_SHADING_RATE];
if (reg->file == BAD_FILE)
*reg = emit_shading_rate_setup(ntb);
break;
default:
break;
}
@ -3600,49 +3593,54 @@ emit_samplemaskin_setup(nir_to_brw_state &ntb)
return mask;
}
static brw_reg
emit_shading_rate_setup(nir_to_brw_state &ntb)
static void
emit_frag_shading_rate_setup(nir_to_brw_state &ntb, brw_reg result)
{
const intel_device_info *devinfo = ntb.devinfo;
const brw_builder &bld = ntb.bld;
assert(devinfo->ver >= 11);
struct brw_fs_prog_data *fs_prog_data =
brw_fs_prog_data(bld.shader->prog_data);
const brw_builder abld = bld.annotate("compute fragment size");
result.type = BRW_TYPE_UD;
bld.MOV(offset(result, bld, 0), brw_imm_ud(1));
bld.MOV(offset(result, bld, 1), brw_imm_ud(1));
/* Coarse pixel shading size fields overlap with other fields of not in
* coarse pixel dispatch mode, so report 0 when that's not the case.
* coarse pixel dispatch mode, so report (1, 1) when that's not the case.
*/
if (fs_prog_data->coarse_pixel_dispatch == INTEL_NEVER)
return brw_imm_ud(0);
return;
const brw_builder abld = bld.annotate("compute fragment shading rate");
/* The shading rates provided in the shader are the actual 2D shading
* rate while the SPIR-V built-in is the enum value that has the shading
* rate encoded as a bitfield. Fortunately, the bitfield value is just
* the shading rate divided by two and shifted.
*/
assert(devinfo->ver >= 11);
/* r1.0 - 0:7 ActualCoarsePixelShadingSize.X */
brw_reg actual_x = brw_reg(retype(brw_vec1_grf(1, 0), BRW_TYPE_UB));
/* r1.0 - 15:8 ActualCoarsePixelShadingSize.Y */
brw_reg actual_y = byte_offset(actual_x, 1);
brw_reg int_rate_y = abld.SHR(actual_y, brw_imm_ud(1));
brw_reg int_rate_x = abld.SHR(actual_x, brw_imm_ud(1));
brw_reg coarse_size = abld.vgrf(BRW_TYPE_UD, 2);
brw_reg rate = abld.OR(abld.SHL(int_rate_x, brw_imm_ud(2)), int_rate_y);
bld.MOV(offset(coarse_size, bld, 0), actual_x);
bld.MOV(offset(coarse_size, bld, 1), actual_y);
if (fs_prog_data->coarse_pixel_dispatch == INTEL_ALWAYS)
return rate;
if (fs_prog_data->coarse_pixel_dispatch == INTEL_ALWAYS) {
for (unsigned i = 0; i < 2; i++)
bld.MOV(offset(result, bld, i), offset(coarse_size, bld, i));
return;
}
brw_check_dynamic_fs_config(abld, fs_prog_data,
INTEL_FS_CONFIG_COARSE_RT_WRITES);
set_predicate(BRW_PREDICATE_NORMAL, abld.SEL(rate, rate, brw_imm_ud(0)));
return rate;
for (unsigned i = 0; i < 2; i++) {
set_predicate(BRW_PREDICATE_NORMAL,
abld.SEL(offset(result, bld, i),
offset(coarse_size, bld, i),
offset(result, bld, i)));
}
}
/* Input data is organized with first the per-primitive values, followed
@ -3793,8 +3791,7 @@ brw_from_nir_emit_fs_intrinsic(nir_to_brw_state &ntb,
case nir_intrinsic_load_helper_invocation:
case nir_intrinsic_load_sample_mask_in:
case nir_intrinsic_load_sample_id:
case nir_intrinsic_load_frag_shading_rate: {
case nir_intrinsic_load_sample_id: {
gl_system_value sv = nir_system_value_from_intrinsic(instr->intrinsic);
brw_reg val = ntb.system_values[sv];
assert(val.file != BAD_FILE);
@ -3803,6 +3800,11 @@ brw_from_nir_emit_fs_intrinsic(nir_to_brw_state &ntb,
break;
}
case nir_intrinsic_load_frag_shading_rate_intel: {
emit_frag_shading_rate_setup(ntb, dest);
break;
}
case nir_intrinsic_load_coverage_mask_intel: {
struct brw_fs_prog_data *fs_prog_data = brw_fs_prog_data(ntb.s.prog_data);
assert(fs_prog_data->uses_sample_mask);

View file

@ -1458,6 +1458,36 @@ fragment_top_block_or_after_wa_18019110168(nir_function_impl *impl)
post_wa_18019110168_block : nir_start_block(impl);
}
static bool
lower_frag_shading_rate(nir_builder *b, nir_intrinsic_instr *intrin, void *data)
{
if (intrin->intrinsic != nir_intrinsic_load_frag_shading_rate)
return false;
b->cursor = nir_before_instr(&intrin->instr);
/* The shading rates provided in the shader are the actual 2D shading
* rate while the SPIR-V built-in is the enum value that has the shading
* rate encoded as a bitfield. Fortunately, the bitfield value is just
* the shading rate divided by two and shifted.
*/
nir_def *sr = nir_load_frag_shading_rate_intel(b);
nir_def *int_rate_x = nir_ushr_imm(b, nir_channel(b, sr, 0), 1);
nir_def *int_rate_y = nir_ushr_imm(b, nir_channel(b, sr, 1), 1);
nir_def *rate = nir_ior(b, nir_ishl_imm(b, int_rate_x, 2), int_rate_y);
nir_def_replace(&intrin->def, rate);
return true;
}
static bool
brw_nir_lower_frag_shading_rate(nir_shader *nir)
{
return nir_shader_intrinsics_pass(nir, lower_frag_shading_rate,
nir_metadata_control_flow, NULL);
}
void
brw_nir_lower_fs_inputs(nir_shader *nir,
const struct intel_device_info *devinfo,
@ -1525,6 +1555,9 @@ brw_nir_lower_fs_inputs(nir_shader *nir,
if (brw_needs_vertex_attributes_bypass(nir))
brw_nir_lower_fs_barycentrics(nir);
if (devinfo->ver >= 11)
NIR_PASS(_, nir, brw_nir_lower_frag_shading_rate);
if (key->multisample_fbo == INTEL_NEVER) {
nir_lower_single_sampled_options lss_opts = {
.lower_sample_mask_in = key->coarse_pixel == INTEL_NEVER,