From a70423944bd46d16d72c708ebc07f87e968cbbd2 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Mon, 10 Apr 2023 17:23:33 -0500 Subject: [PATCH] nak: Wire up texture ops Part-of: --- src/nouveau/compiler/nak_encode_sm75.rs | 187 ++++++++++++++++ src/nouveau/compiler/nak_from_nir.rs | 193 ++++++++++++++++- src/nouveau/compiler/nak_ir.rs | 270 ++++++++++++++++++++++++ 3 files changed, 648 insertions(+), 2 deletions(-) diff --git a/src/nouveau/compiler/nak_encode_sm75.rs b/src/nouveau/compiler/nak_encode_sm75.rs index f118db1c431..5ccff7991b3 100644 --- a/src/nouveau/compiler/nak_encode_sm75.rs +++ b/src/nouveau/compiler/nak_encode_sm75.rs @@ -735,6 +735,187 @@ impl SM75Instr { self.set_pred_src(87..90, 90, op.srcs[0]); } + fn set_tex_dim(&mut self, range: Range, dim: TexDim) { + assert!(range.len() == 3); + self.set_field( + range, + match dim { + TexDim::_1D => 0_u8, + TexDim::Array1D => 4_u8, + TexDim::_2D => 1_u8, + TexDim::Array2D => 5_u8, + TexDim::_3D => 2_u8, + TexDim::Cube => 3_u8, + TexDim::ArrayCube => 7_u8, + }, + ); + } + + fn set_tex_lod_mode(&mut self, range: Range, lod_mode: TexLodMode) { + assert!(range.len() == 3); + self.set_field( + range, + match lod_mode { + TexLodMode::Auto => 0_u8, + TexLodMode::Zero => 1_u8, + TexLodMode::Bias => 2_u8, + TexLodMode::Lod => 3_u8, + TexLodMode::Clamp => 4_u8, + TexLodMode::BiasClamp => 5_u8, + }, + ); + } + + fn encode_tex(&mut self, op: &OpTex) { + self.set_opcode(0x361); + self.set_bit(59, true); /* .B */ + + self.set_dst(op.dsts[0]); + if let Dst::Reg(reg) = op.dsts[1] { + self.set_reg(64..72, reg); + } else { + self.set_field(64..72, 255_u8); + } + self.set_pred_dst(81..84, op.resident); + + self.set_reg_src(24..32, op.srcs[0]); + self.set_reg_src(32..40, op.srcs[1]); + + self.set_tex_dim(61..64, op.dim); + self.set_field(72..76, op.mask); + self.set_bit(76, op.offset); + self.set_bit(77, false); /* ToDo: NDV */ + self.set_bit(78, op.z_cmpr); + self.set_field(84..87, 1); + self.set_tex_lod_mode(87..90, op.lod_mode); + self.set_bit(90, false); /* TODO: .NODEP */ + } + + fn encode_tld(&mut self, op: &OpTld) { + self.set_opcode(0x367); + self.set_bit(59, true); /* .B */ + + self.set_dst(op.dsts[0]); + if let Dst::Reg(reg) = op.dsts[1] { + self.set_reg(64..72, reg); + } else { + self.set_field(64..72, 255_u8); + } + self.set_pred_dst(81..84, op.resident); + + self.set_reg_src(24..32, op.srcs[0]); + self.set_reg_src(32..40, op.srcs[1]); + + self.set_tex_dim(61..64, op.dim); + self.set_field(72..76, op.mask); + self.set_bit(76, op.offset); + /* bit 77: .CL */ + self.set_bit(78, op.is_ms); + /* bits 79..81: .F16 */ + assert!( + op.lod_mode == TexLodMode::Zero || op.lod_mode == TexLodMode::Lod + ); + self.set_tex_lod_mode(87..90, op.lod_mode); + self.set_bit(90, false); /* TODO: .NODEP */ + } + + fn encode_tld4(&mut self, op: &OpTld4) { + self.set_opcode(0x364); + self.set_bit(59, true); /* .B */ + + self.set_dst(op.dsts[0]); + if let Dst::Reg(reg) = op.dsts[1] { + self.set_reg(64..72, reg); + } else { + self.set_field(64..72, 255_u8); + } + self.set_pred_dst(81..84, op.resident); + + self.set_reg_src(24..32, op.srcs[0]); + self.set_reg_src(32..40, op.srcs[1]); + + self.set_tex_dim(61..64, op.dim); + self.set_field(72..76, op.mask); + self.set_field( + 76..78, + match op.offset_mode { + Tld4OffsetMode::None => 0_u8, + Tld4OffsetMode::AddOffI => 1_u8, + Tld4OffsetMode::PerPx => 2_u8, + }, + ); + /* bit 77: .CL */ + self.set_bit(78, op.z_cmpr); + self.set_bit(84, true); /* !.EF */ + self.set_field(87..89, op.comp); + self.set_bit(90, false); /* TODO: .NODEP */ + } + + fn encode_tmml(&mut self, op: &OpTmml) { + self.set_opcode(0x36a); + self.set_bit(59, true); /* .B */ + + self.set_dst(op.dsts[0]); + if let Dst::Reg(reg) = op.dsts[1] { + self.set_reg(64..72, reg); + } else { + self.set_field(64..72, 255_u8); + } + + self.set_reg_src(24..32, op.srcs[0]); + self.set_reg_src(32..40, op.srcs[1]); + + self.set_tex_dim(61..64, op.dim); + self.set_field(72..76, op.mask); + self.set_bit(77, false); /* ToDo: NDV */ + self.set_bit(90, false); /* TODO: .NODEP */ + } + + fn encode_txd(&mut self, op: &OpTxd) { + self.set_opcode(0x36d); + self.set_bit(59, true); /* .B */ + + self.set_dst(op.dsts[0]); + if let Dst::Reg(reg) = op.dsts[1] { + self.set_reg(64..72, reg); + } else { + self.set_field(64..72, 255_u8); + } + self.set_pred_dst(81..84, op.resident); + + self.set_reg_src(24..32, op.srcs[0]); + self.set_reg_src(32..40, op.srcs[1]); + + self.set_tex_dim(61..64, op.dim); + self.set_field(72..76, op.mask); + self.set_bit(76, op.offset); + self.set_bit(77, false); /* ToDo: NDV */ + self.set_bit(90, false); /* TODO: .NODEP */ + } + + fn encode_txq(&mut self, op: &OpTxq) { + self.set_opcode(0x370); + self.set_bit(59, true); /* .B */ + + self.set_dst(op.dsts[0]); + if let Dst::Reg(reg) = op.dsts[1] { + self.set_reg(64..72, reg); + } else { + self.set_field(64..72, 255_u8); + } + + self.set_reg_src(24..32, op.src); + self.set_field( + 62..64, + match op.query { + TexQuery::Dimension => 0_u8, + TexQuery::TextureType => 1_u8, + TexQuery::SamplerPos => 2_u8, + }, + ); + self.set_field(72..76, op.mask); + } + fn set_mem_access(&mut self, access: &MemAccess) { self.set_field( 72..73, @@ -931,6 +1112,12 @@ impl SM75Instr { Op::Mov(op) => si.encode_mov(&op), Op::Sel(op) => si.encode_sel(&op), Op::PLop3(op) => si.encode_plop3(&op), + Op::Tex(op) => si.encode_tex(&op), + Op::Tld(op) => si.encode_tld(&op), + Op::Tld4(op) => si.encode_tld4(&op), + Op::Tmml(op) => si.encode_tmml(&op), + Op::Txd(op) => si.encode_txd(&op), + Op::Txq(op) => si.encode_txq(&op), Op::Ld(op) => si.encode_ld(&op), Op::St(op) => si.encode_st(&op), Op::ALd(op) => si.encode_ald(&op), diff --git a/src/nouveau/compiler/nak_from_nir.rs b/src/nouveau/compiler/nak_from_nir.rs index 4152232f25b..92ad70bb703 100644 --- a/src/nouveau/compiler/nak_from_nir.rs +++ b/src/nouveau/compiler/nak_from_nir.rs @@ -4,12 +4,15 @@ */ #![allow(non_upper_case_globals)] +#![allow(unstable_name_collisions)] use crate::nak_ir::*; use crate::nir::*; +use crate::util::DivCeil; use nak_bindings::*; +use std::cmp::min; use std::collections::HashMap; struct ShaderFromNir<'a> { @@ -128,6 +131,29 @@ impl<'a> ShaderFromNir<'a> { split } + fn split(&mut self, ssa: SSAValue) -> Vec { + if ssa.comps() == 1 { + return vec![ssa]; + } + + let mut split_ssa = Vec::new(); + let mut dsts = Vec::new(); + for c in 0..ssa.comps() { + let dst_ssa = self.alloc_ssa(ssa.file(), 1); + split_ssa.push(dst_ssa); + dsts.push(Dst::from(dst_ssa)); + } + self.instrs.push(Instr::new_split(&dsts, ssa.into())); + split_ssa + } + + fn vec(&mut self, ssa: &[SSAValue]) -> SSAValue { + let dst = self.alloc_ssa(ssa[0].file(), ssa.len().try_into().unwrap()); + let srcs: Vec = ssa.iter().map(|s| (*s).into()).collect(); + self.instrs.push(Instr::new_vec(dst.into(), &srcs)); + dst + } + fn parse_alu(&mut self, alu: &nir_alu_instr) { let mut srcs = Vec::new(); for alu_src in alu.srcs_as_slice() { @@ -567,8 +593,171 @@ impl<'a> ShaderFromNir<'a> { /* Nothing to do */ } - fn parse_tex(&mut self, _tex: &nir_tex_instr) { - panic!("Texture instructions unimplemented"); + fn parse_tex(&mut self, tex: &nir_tex_instr) { + let dim = match tex.sampler_dim { + GLSL_SAMPLER_DIM_1D => { + if tex.is_array { + TexDim::Array1D + } else { + TexDim::_1D + } + } + GLSL_SAMPLER_DIM_2D => { + if tex.is_array { + TexDim::Array2D + } else { + TexDim::_2D + } + } + GLSL_SAMPLER_DIM_3D => { + assert!(!tex.is_array); + TexDim::_3D + } + GLSL_SAMPLER_DIM_CUBE => { + if tex.is_array { + TexDim::ArrayCube + } else { + TexDim::Cube + } + } + GLSL_SAMPLER_DIM_BUF => TexDim::_1D, + GLSL_SAMPLER_DIM_MS => { + if tex.is_array { + TexDim::Array2D + } else { + TexDim::_2D + } + } + _ => panic!("Unsupported texture dimension: {}", tex.sampler_dim), + }; + + let srcs = tex.srcs_as_slice(); + assert!(srcs[0].src_type == nir_tex_src_backend1); + if srcs.len() > 1 { + assert!(srcs.len() == 2); + assert!(srcs[1].src_type == nir_tex_src_backend2); + } + + let flags: nak_nir_tex_flags = + unsafe { std::mem::transmute_copy(&tex.backend_flags) }; + + let mask = tex.def.components_read(); + let mask = u8::try_from(mask).unwrap(); + + let dst_comps = u8::try_from(mask.count_ones()).unwrap(); + let mut dsts = [Dst::None; 2]; + dsts[0] = self.alloc_ssa(RegFile::GPR, min(dst_comps, 2)).into(); + if dst_comps > 2 { + dsts[1] = self.alloc_ssa(RegFile::GPR, dst_comps - 2).into(); + } + + if tex.op == nir_texop_hdr_dim_nv { + self.instrs.push(Instr::new(Op::Txq(OpTxq { + dsts: dsts, + src: self.get_src(&srcs[0].src), + query: TexQuery::Dimension, + mask: mask, + }))); + } else if tex.op == nir_texop_tex_type_nv { + self.instrs.push(Instr::new(Op::Txq(OpTxq { + dsts: dsts, + src: self.get_src(&srcs[0].src), + query: TexQuery::TextureType, + mask: mask, + }))); + } else { + let lod_mode = match flags.lod_mode() { + NAK_NIR_LOD_MODE_AUTO => TexLodMode::Auto, + NAK_NIR_LOD_MODE_ZERO => TexLodMode::Zero, + NAK_NIR_LOD_MODE_BIAS => TexLodMode::Bias, + NAK_NIR_LOD_MODE_LOD => TexLodMode::Lod, + NAK_NIR_LOD_MODE_CLAMP => TexLodMode::Clamp, + NAK_NIR_LOD_MODE_BIAS_CLAMP => TexLodMode::BiasClamp, + _ => panic!("Invalid LOD mode"), + }; + + let offset_mode = match flags.offset_mode() { + NAK_NIR_OFFSET_MODE_NONE => Tld4OffsetMode::None, + NAK_NIR_OFFSET_MODE_AOFFI => Tld4OffsetMode::AddOffI, + NAK_NIR_OFFSET_MODE_PER_PX => Tld4OffsetMode::PerPx, + _ => panic!("Invalid offset mode"), + }; + + let srcs = [self.get_src(&srcs[0].src), self.get_src(&srcs[1].src)]; + + if tex.op == nir_texop_txd { + assert!(lod_mode == TexLodMode::Auto); + assert!(offset_mode != Tld4OffsetMode::PerPx); + assert!(!flags.has_z_cmpr()); + self.instrs.push(Instr::new(Op::Txd(OpTxd { + dsts: dsts, + resident: Dst::None, + srcs: srcs, + dim: dim, + offset: offset_mode == Tld4OffsetMode::AddOffI, + mask: mask, + }))); + } else if tex.op == nir_texop_lod { + assert!(offset_mode == Tld4OffsetMode::None); + self.instrs.push(Instr::new(Op::Tmml(OpTmml { + dsts: dsts, + srcs: srcs, + dim: dim, + mask: mask, + }))); + } else if tex.op == nir_texop_txf { + assert!(offset_mode != Tld4OffsetMode::PerPx); + self.instrs.push(Instr::new(Op::Tld(OpTld { + dsts: dsts, + resident: Dst::None, + srcs: srcs, + dim: dim, + lod_mode: lod_mode, + is_ms: false, + offset: offset_mode == Tld4OffsetMode::AddOffI, + mask: mask, + }))); + } else if tex.op == nir_texop_tg4 { + self.instrs.push(Instr::new(Op::Tld4(OpTld4 { + dsts: dsts, + resident: Dst::None, + srcs: srcs, + dim: dim, + comp: tex.component().try_into().unwrap(), + offset_mode: offset_mode, + z_cmpr: flags.has_z_cmpr(), + mask: mask, + }))); + } else { + assert!(offset_mode != Tld4OffsetMode::PerPx); + self.instrs.push(Instr::new(Op::Tex(OpTex { + dsts: dsts, + resident: Dst::None, + srcs: srcs, + dim: dim, + lod_mode: lod_mode, + z_cmpr: flags.has_z_cmpr(), + offset: offset_mode == Tld4OffsetMode::AddOffI, + mask: mask, + }))); + } + } + + let mut dst_comps = Vec::new(); + for dst in dsts { + if let Dst::SSA(dst) = dst { + for comp in self.split(dst) { + dst_comps.push(comp.into()); + } + } + } + for c in 0..tex.def.num_components() { + if mask & (1 << c) == 0 { + dst_comps.insert(c.into(), SrcRef::Zero.into()); + } + } + self.instrs + .push(Instr::new_vec(self.get_dst(&tex.def), &dst_comps)); } fn parse_intrinsic(&mut self, intrin: &nir_intrinsic_instr) { diff --git a/src/nouveau/compiler/nak_ir.rs b/src/nouveau/compiler/nak_ir.rs index 983c11cd362..93fc42f9a39 100644 --- a/src/nouveau/compiler/nak_ir.rs +++ b/src/nouveau/compiler/nak_ir.rs @@ -859,6 +859,88 @@ impl fmt::Display for FRndMode { } } +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum TexDim { + _1D, + Array1D, + _2D, + Array2D, + _3D, + Cube, + ArrayCube, +} + +impl fmt::Display for TexDim { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TexDim::_1D => write!(f, "1D"), + TexDim::Array1D => write!(f, "ARRAY_1D"), + TexDim::_2D => write!(f, "2D"), + TexDim::Array2D => write!(f, "ARRAY_2D"), + TexDim::_3D => write!(f, "3D"), + TexDim::Cube => write!(f, "CUBE"), + TexDim::ArrayCube => write!(f, "ARRAY_CUBE"), + } + } +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum TexLodMode { + Auto, + Zero, + Bias, + Lod, + Clamp, + BiasClamp, +} + +impl fmt::Display for TexLodMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TexLodMode::Auto => write!(f, "LA"), + TexLodMode::Zero => write!(f, "LZ"), + TexLodMode::Bias => write!(f, "LB"), + TexLodMode::Lod => write!(f, "LL"), + TexLodMode::Clamp => write!(f, "LC"), + TexLodMode::BiasClamp => write!(f, "LB.LC"), + } + } +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum Tld4OffsetMode { + None, + AddOffI, + PerPx, +} + +impl fmt::Display for Tld4OffsetMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Tld4OffsetMode::None => write!(f, "NO_OFF"), + Tld4OffsetMode::AddOffI => write!(f, "AOFFI"), + Tld4OffsetMode::PerPx => write!(f, "PTP"), + } + } +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub enum TexQuery { + Dimension, + TextureType, + SamplerPos, +} + +impl fmt::Display for TexQuery { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TexQuery::Dimension => write!(f, "DIMENSION"), + TexQuery::TextureType => write!(f, "TEXTURE_TYPE"), + TexQuery::SamplerPos => write!(f, "SAMPLER_POS"), + } + } +} + pub enum IntType { U8, I8, @@ -1501,6 +1583,182 @@ impl fmt::Display for OpPLop3 { } } +#[repr(C)] +#[derive(SrcsAsSlice, DstsAsSlice)] +pub struct OpTex { + pub dsts: [Dst; 2], + pub resident: Dst, + pub srcs: [Src; 2], + pub dim: TexDim, + pub lod_mode: TexLodMode, + pub z_cmpr: bool, + pub offset: bool, + pub mask: u8, +} + +impl fmt::Display for OpTex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TEX.B")?; + if self.lod_mode != TexLodMode::Auto { + write!(f, ".{}", self.lod_mode)?; + } + if self.offset { + write!(f, ".AOFFI")?; + } + if self.z_cmpr { + write!(f, ".DC")?; + } + write!( + f, + " {{ {}, {}, {} }} {{ {}, {} }} {}", + self.dsts[0], + self.dsts[1], + self.resident, + self.srcs[0], + self.srcs[1], + self.dim, + ) + } +} + +#[repr(C)] +#[derive(SrcsAsSlice, DstsAsSlice)] +pub struct OpTld { + pub dsts: [Dst; 2], + pub resident: Dst, + pub srcs: [Src; 2], + pub dim: TexDim, + pub is_ms: bool, + pub lod_mode: TexLodMode, + pub offset: bool, + pub mask: u8, +} + +impl fmt::Display for OpTld { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TLD.B")?; + if self.lod_mode != TexLodMode::Auto { + write!(f, ".{}", self.lod_mode)?; + } + if self.offset { + write!(f, ".AOFFI")?; + } + if self.is_ms { + write!(f, ".MS")?; + } + write!( + f, + " {{ {}, {}, {} }} {{ {}, {} }} {}", + self.dsts[0], + self.dsts[1], + self.resident, + self.srcs[0], + self.srcs[1], + self.dim, + ) + } +} + +#[repr(C)] +#[derive(SrcsAsSlice, DstsAsSlice)] +pub struct OpTld4 { + pub dsts: [Dst; 2], + pub resident: Dst, + pub srcs: [Src; 2], + pub dim: TexDim, + pub comp: u8, + pub offset_mode: Tld4OffsetMode, + pub z_cmpr: bool, + pub mask: u8, +} + +impl fmt::Display for OpTld4 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TLD4.G.B")?; + if self.offset_mode != Tld4OffsetMode::None { + write!(f, ".{}", self.offset_mode)?; + } + write!( + f, + " {{ {}, {}, {} }} {{ {}, {} }} {}", + self.dsts[0], + self.dsts[1], + self.resident, + self.srcs[0], + self.srcs[1], + self.dim, + ) + } +} + +#[repr(C)] +#[derive(SrcsAsSlice, DstsAsSlice)] +pub struct OpTmml { + pub dsts: [Dst; 2], + pub srcs: [Src; 2], + pub dim: TexDim, + pub mask: u8, +} + +impl fmt::Display for OpTmml { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "TMML.B.LOD {{ {}, {} }} {{ {}, {} }} {}", + self.dsts[0], self.dsts[1], self.srcs[0], self.srcs[1], self.dim + ) + } +} + +#[repr(C)] +#[derive(SrcsAsSlice, DstsAsSlice)] +pub struct OpTxd { + pub dsts: [Dst; 2], + pub resident: Dst, + pub srcs: [Src; 2], + pub dim: TexDim, + pub offset: bool, + pub mask: u8, +} + +impl fmt::Display for OpTxd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TXD.B")?; + if self.offset { + write!(f, ".AOFFI")?; + } + write!( + f, + " {{ {}, {}, {} }} {{ {}, {} }} {}", + self.dsts[0], + self.dsts[1], + self.resident, + self.srcs[0], + self.srcs[1], + self.dim, + ) + } +} + +#[repr(C)] +#[derive(SrcsAsSlice, DstsAsSlice)] +pub struct OpTxq { + pub dsts: [Dst; 2], + pub src: Src, + pub query: TexQuery, + pub mask: u8, +} + +impl fmt::Display for OpTxq { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "TXQ.B {{ {}, {} }} {} {}", + self.dsts[0], self.dsts[1], self.src, self.query + ) + } +} + #[repr(C)] #[derive(SrcsAsSlice, DstsAsSlice)] pub struct OpLd { @@ -1953,6 +2211,12 @@ pub enum Op { Mov(OpMov), Sel(OpSel), PLop3(OpPLop3), + Tex(OpTex), + Tld(OpTld), + Tld4(OpTld4), + Tmml(OpTmml), + Txd(OpTxd), + Txq(OpTxq), Ld(OpLd), St(OpSt), ALd(OpALd), @@ -2420,6 +2684,12 @@ impl Instr { Op::ALd(_) => None, Op::ASt(_) => Some(15), Op::Ipa(_) => None, + Op::Tex(_) => None, + Op::Tld(_) => None, + Op::Tld4(_) => None, + Op::Tmml(_) => None, + Op::Txd(_) => None, + Op::Txq(_) => None, Op::Ld(_) => None, Op::St(_) => None, Op::Bra(_) | Op::Exit(_) => Some(15),