nak: Implement input interpolation

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24998>
This commit is contained in:
Faith Ekstrand 2023-04-10 17:23:29 -05:00 committed by Marge Bot
parent 6595abc1e0
commit 8c358ce105
5 changed files with 180 additions and 1 deletions

View file

@ -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] */

View file

@ -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),

View file

@ -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]);

View file

@ -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),

View file

@ -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;