diff --git a/src/nouveau/compiler/nak.rs b/src/nouveau/compiler/nak.rs index bd0e82d6709..22839e5c371 100644 --- a/src/nouveau/compiler/nak.rs +++ b/src/nouveau/compiler/nak.rs @@ -19,6 +19,8 @@ mod nir; mod union_find; mod util; +use crate::nir::NirShader; + use bitview::*; use nak_bindings::*; use nak_from_nir::*; @@ -276,6 +278,32 @@ fn encode_hdr_for_nir(nir: &nir_shader, tls_size: u32) -> [u32; 32] { imap_sv.set_bit(31, true); //has_frag_coord); /* [192, 447]: ImapGenericVector[32] */ + /* TODO: Non-perspective */ + let mut imap_g = hdr_view.subset_mut(192..447); + + let nir_ir = BitView::new(&nir.info.inputs_read); + let input0: usize = VARYING_SLOT_VAR0.try_into().unwrap(); + for var in nir.iter_variables() { + if var.data.mode() != nir_var_shader_in { + continue; + } + let loc_u32 = u32::try_from(var.data.location).unwrap(); + let slot = + (loc_u32 - VARYING_SLOT_VAR0) * 4 + var.data.location_frac(); + let num_slots = unsafe { glsl_get_component_slots(var.type_) }; + let mode: u8 = match var.data.interpolation() { + INTERP_MODE_NONE | INTERP_MODE_SMOOTH => 2, /* Perspective */ + INTERP_MODE_FLAT => 1, /* Constant */ + INTERP_MODE_NOPERSPECTIVE => 3, /* ScreenLinear */ + INTERP_MODE_EXPLICIT => 0, /* Unused */ + _ => panic!("Unsupported INTERP_MODE"), + }; + for s in slot..(slot + num_slots) { + let s = usize::try_from(s).unwrap(); + imap_g.set_field((s * 2)..(s * 2 + 2), mode); + } + } + /* [448, 463]: ImapColor */ /* [464, 479]: ImapSystemValuesC */ /* [480, 559]: ImapFixedFncTexture[10] */ diff --git a/src/nouveau/compiler/nak_encode_sm75.rs b/src/nouveau/compiler/nak_encode_sm75.rs index 9e5fdc64afd..75f5e3ec6ee 100644 --- a/src/nouveau/compiler/nak_encode_sm75.rs +++ b/src/nouveau/compiler/nak_encode_sm75.rs @@ -766,6 +766,37 @@ impl SM75Instr { assert!(!op.access.out_load); } + fn encode_ipa(&mut self, op: &OpIpa) { + self.set_opcode(0x326); + + self.set_dst(op.dst); + + assert!(op.addr % 4 == 0); + self.set_field(64..72, op.addr >> 2); + + self.set_field( + 76..78, + match op.freq { + InterpFreq::Pass => 0_u8, + InterpFreq::Constant => 1_u8, + InterpFreq::State => 2_u8, + }, + ); + self.set_field( + 78..80, + match op.loc { + InterpLoc::Default => 0_u8, + InterpLoc::Centroid => 1_u8, + InterpLoc::Offset => 2_u8, + }, + ); + + self.set_reg_src(32..40, op.offset); + + /* TODO: What is this for? */ + self.set_pred_dst(81..84, Dst::None); + } + fn encode_bra( &mut self, op: &OpBra, @@ -837,6 +868,7 @@ impl SM75Instr { Op::St(op) => si.encode_st(&op), Op::ALd(op) => si.encode_ald(&op), Op::ASt(op) => si.encode_ast(&op), + Op::Ipa(op) => si.encode_ipa(&op), Op::Bra(op) => si.encode_bra(&op, ip, block_offsets), Op::Exit(op) => si.encode_exit(&op), Op::S2R(op) => si.encode_s2r(&op), diff --git a/src/nouveau/compiler/nak_from_nir.rs b/src/nouveau/compiler/nak_from_nir.rs index e22602eb29e..a59d15316c6 100644 --- a/src/nouveau/compiler/nak_from_nir.rs +++ b/src/nouveau/compiler/nak_from_nir.rs @@ -484,6 +484,9 @@ impl<'a> ShaderFromNir<'a> { fn parse_intrinsic(&mut self, intrin: &nir_intrinsic_instr) { let srcs = intrin.srcs_as_slice(); match intrin.intrinsic { + nir_intrinsic_load_barycentric_centroid => (), + nir_intrinsic_load_barycentric_pixel => (), + nir_intrinsic_load_barycentric_sample => (), nir_intrinsic_load_global => { let size_B = (intrin.def.bit_size() / 8) * intrin.def.num_components(); @@ -505,6 +508,32 @@ impl<'a> ShaderFromNir<'a> { let dst = self.get_dst(&intrin.def); self.instrs.push(Instr::new_ald(dst, addr, vtx, offset)); } + nir_intrinsic_load_interpolated_input => { + let bary = + srcs[0].as_def().parent_instr().as_intrinsic().unwrap(); + let addr = u16::try_from(intrin.base()).unwrap() + + u16::try_from(srcs[1].as_uint().unwrap()).unwrap(); + let freq = InterpFreq::Pass; + let loc = match bary.intrinsic { + nir_intrinsic_load_barycentric_pixel => InterpLoc::Default, + _ => panic!("Unsupported interp mode"), + }; + let dst = self.get_dst(&intrin.def); + + let mut comps = Vec::new(); + for c in 0..intrin.num_components { + let tmp = self.alloc_ssa(RegFile::GPR, 1); + self.instrs.push(Instr::new(Op::Ipa(OpIpa { + dst: tmp.into(), + addr: addr + 4 * u16::try_from(c).unwrap(), + freq: freq, + loc: loc, + offset: SrcRef::Zero.into(), + }))); + comps.push(tmp.into()); + } + self.instrs.push(Instr::new_vec(dst, &comps)); + } nir_intrinsic_load_per_vertex_input => { let addr = u16::try_from(intrin.base()).unwrap(); let vtx = self.get_src(&srcs[0]); diff --git a/src/nouveau/compiler/nak_ir.rs b/src/nouveau/compiler/nak_ir.rs index fa0f4d26318..570e5530451 100644 --- a/src/nouveau/compiler/nak_ir.rs +++ b/src/nouveau/compiler/nak_ir.rs @@ -1011,6 +1011,20 @@ impl fmt::Display for MemAccess { } } +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum InterpFreq { + Pass, + Constant, + State, +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum InterpLoc { + Default, + Centroid, + Offset, +} + pub struct AttrAccess { pub addr: u16, pub comps: u8, @@ -1427,6 +1441,38 @@ impl fmt::Display for OpASt { } } +#[repr(C)] +#[derive(SrcsAsSlice, DstsAsSlice)] +pub struct OpIpa { + pub dst: Dst, + pub addr: u16, + pub freq: InterpFreq, + pub loc: InterpLoc, + pub offset: Src, +} + +impl fmt::Display for OpIpa { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "IPA")?; + match self.freq { + InterpFreq::Pass => (), + InterpFreq::Constant => write!(f, ".CONSTANT")?, + InterpFreq::State => write!(f, ".STATE")?, + } + match self.loc { + InterpLoc::Default => (), + InterpLoc::Centroid => write!(f, ".CENTROID")?, + InterpLoc::Offset => write!(f, ".OFFSET")?, + } + + write!(f, " {} a[{:#x}]", self.dst, self.addr)?; + if !self.offset.is_zero() { + write!(f, " {}", self.offset)?; + } + Ok(()) + } +} + #[repr(C)] #[derive(SrcsAsSlice, DstsAsSlice)] pub struct OpBra { @@ -1763,6 +1809,7 @@ pub enum Op { St(OpSt), ALd(OpALd), ASt(OpASt), + Ipa(OpIpa), Bra(OpBra), Exit(OpExit), S2R(OpS2R), @@ -2218,6 +2265,7 @@ impl Instr { Op::S2R(_) => None, Op::ALd(_) => None, Op::ASt(_) => Some(15), + Op::Ipa(_) => None, Op::Ld(_) => None, Op::St(_) => None, Op::Bra(_) | Op::Exit(_) => Some(15), diff --git a/src/nouveau/compiler/nak_nir.c b/src/nouveau/compiler/nak_nir.c index 925532d5d5f..6d4d80ed1bc 100644 --- a/src/nouveau/compiler/nak_nir.c +++ b/src/nouveau/compiler/nak_nir.c @@ -312,6 +312,48 @@ vec_size_4(const struct glsl_type *type, bool bindless) return 4; } +static bool +nak_nir_lower_fs_inputs(nir_shader *nir) +{ + bool progress = false; + + OPT(nir, nak_nir_lower_varyings, nir_var_shader_in); + + if (!progress) + return false; + + nir_function_impl *impl = nir_shader_get_entrypoint(nir); + + const uint16_t w_addr = + nak_sysval_attr_addr(SYSTEM_VALUE_FRAG_COORD) + 12; + + nir_builder b = nir_builder_create(impl); + + nir_foreach_block(block, impl) { + nir_foreach_instr_safe(instr, block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_load_interpolated_input) + continue; + + b.cursor = nir_after_instr(&intrin->instr); + + nir_def *w = + nir_load_interpolated_input(&b, 1, 32, intrin->src[0].ssa, + nir_imm_int(&b, 0), .base = w_addr, + .dest_type = nir_type_float32); + + /* Interpolated inputs need to be divided by .w */ + nir_def *res = nir_fdiv(&b, &intrin->def, w); + nir_def_rewrite_uses_after(&intrin->def, res, res->parent_instr); + } + } + + return true; +} + static bool nak_nir_lower_fs_outputs(nir_shader *nir) { @@ -502,7 +544,7 @@ nak_postprocess_nir(nir_shader *nir, const struct nak_compiler *nak) break; case MESA_SHADER_FRAGMENT: - OPT(nir, nak_nir_lower_varyings, nir_var_shader_in); + OPT(nir, nak_nir_lower_fs_inputs); OPT(nir, nak_nir_lower_fs_outputs); break;