From 145213fd2cd10038b8fa5eacb01300807fc41563 Mon Sep 17 00:00:00 2001 From: Mary Guillemard Date: Tue, 26 Sep 2023 17:44:24 +0200 Subject: [PATCH] nak: Restructure ShaderInfo Signed-off-by: Mary Guillemard Part-of: --- src/nouveau/compiler/nak.rs | 8 +- src/nouveau/compiler/nak_from_nir.rs | 371 +++++++++++++++++---------- src/nouveau/compiler/nak_ir.rs | 104 +++----- src/nouveau/compiler/nak_sph.rs | 99 ++++--- 4 files changed, 321 insertions(+), 261 deletions(-) diff --git a/src/nouveau/compiler/nak.rs b/src/nouveau/compiler/nak.rs index 1c940860f41..f4051bc1a3c 100644 --- a/src/nouveau/compiler/nak.rs +++ b/src/nouveau/compiler/nak.rs @@ -31,6 +31,7 @@ use crate::nak_ir::ShaderStageInfo; use bitview::*; use nak_bindings::*; use nak_from_nir::*; +use nak_ir::ShaderIoInfo; use std::env; use std::ffi::CStr; use std::os::raw::c_void; @@ -294,7 +295,12 @@ pub extern "C" fn nak_compile_shader( }, } } - ShaderStageInfo::Fragment(fs_info) => { + ShaderStageInfo::Fragment => { + let fs_info = match &s.info.io { + ShaderIoInfo::Fragment(io) => io, + _ => unreachable!(), + }; + let nir_fs_info = unsafe { &nir.info.__bindgen_anon_1.fs }; nak_shader_info__bindgen_ty_1 { fs: nak_shader_info__bindgen_ty_1__bindgen_ty_2 { diff --git a/src/nouveau/compiler/nak_from_nir.rs b/src/nouveau/compiler/nak_from_nir.rs index a5b62e28cbe..a0844a63aa4 100644 --- a/src/nouveau/compiler/nak_from_nir.rs +++ b/src/nouveau/compiler/nak_from_nir.rs @@ -6,6 +6,8 @@ #![allow(non_upper_case_globals)] #![allow(unstable_name_collisions)] +use crate::bitset::BitSet; +use crate::bitview::{BitMutView, BitView, SetField}; use crate::nak_cfg::CFGBuilder; use crate::nak_ir::*; use crate::nak_sph::{OutputTopology, PixelImap}; @@ -18,7 +20,7 @@ use std::cmp::min; use std::collections::{HashMap, HashSet}; fn init_info_from_nir(nir: &nir_shader, sm: u8) -> ShaderInfo { - let mut res = ShaderInfo { + ShaderInfo { sm: sm, num_gprs: 0, tls_size: nir.scratch_size, @@ -38,9 +40,7 @@ fn init_info_from_nir(nir: &nir_shader, sm: u8) -> ShaderInfo { }) } MESA_SHADER_VERTEX => ShaderStageInfo::Vertex, - MESA_SHADER_FRAGMENT => { - ShaderStageInfo::Fragment(Default::default()) - } + MESA_SHADER_FRAGMENT => ShaderStageInfo::Fragment, MESA_SHADER_GEOMETRY => { let info_gs = unsafe { &nir.info.__bindgen_anon_1.gs }; @@ -59,34 +59,37 @@ fn init_info_from_nir(nir: &nir_shader, sm: u8) -> ShaderInfo { MESA_SHADER_TESS_EVAL => ShaderStageInfo::Tessellation, _ => panic!("Unknown shader stage"), }, - vtg_stage_info: match nir.info.stage() { - MESA_SHADER_COMPUTE | MESA_SHADER_FRAGMENT => None, + io: match nir.info.stage() { + MESA_SHADER_COMPUTE => ShaderIoInfo::None, + MESA_SHADER_FRAGMENT => ShaderIoInfo::Fragment(FragmentIoInfo { + sysvals_in: SysValInfo { + // Required on fragment shaders, otherwise it cause a trap. + ab: 1 << 31, + c: 0, + }, + attr_in: [PixelImap::Unused; 128], + reads_sample_mask: false, + uses_kill: false, + writes_color: 0, + writes_sample_mask: false, + writes_depth: false, + }), MESA_SHADER_VERTEX | MESA_SHADER_GEOMETRY | MESA_SHADER_TESS_CTRL - | MESA_SHADER_TESS_EVAL => Some(Default::default()), + | MESA_SHADER_TESS_EVAL => ShaderIoInfo::Vtg(VtgIoInfo { + sysvals_in: SysValInfo::default(), + sysvals_out: SysValInfo::default(), + attr_in: [0; 4], + attr_out: [0; 4], + + // TODO: figure out how to fill this. + store_req_start: 0xff, + store_req_end: 0, + }), _ => panic!("Unknown shader stage"), }, - input_attributes: [0; 32], - imap_color: 0, - system_values_in: SystemValueInfo { - ab: if nir.info.stage() == MESA_SHADER_FRAGMENT { - // Required on fragment shaders, otherwise it cause a trap. - 1 << 31 - } else { - 0 - }, - c: 0, - }, - }; - - if let Some(vtg_stage_info) = &mut res.vtg_stage_info { - // TODO: figure out how to fill this. - vtg_stage_info.store_req_start = 0xff; - vtg_stage_info.store_req_end = 0x0; } - - res } fn alloc_ssa_for_nir(b: &mut impl SSABuilder, ssa: &nir_def) -> Vec { @@ -1242,7 +1245,7 @@ impl<'a> ShaderFromNir<'a> { }); } nir_intrinsic_demote | nir_intrinsic_discard => { - if let ShaderStageInfo::Fragment(info) = &mut self.info.stage { + if let ShaderIoInfo::Fragment(info) = &mut self.info.io { info.uses_kill = true; } else { panic!("OpKill is only available in fragment shaders"); @@ -1250,7 +1253,7 @@ impl<'a> ShaderFromNir<'a> { b.push_op(OpKill {}); } nir_intrinsic_demote_if | nir_intrinsic_discard_if => { - if let ShaderStageInfo::Fragment(info) = &mut self.info.stage { + if let ShaderIoInfo::Fragment(info) = &mut self.info.io { info.uses_kill = true; } else { panic!("OpKill is only available in fragment shaders"); @@ -1338,67 +1341,101 @@ impl<'a> ShaderFromNir<'a> { let comps = intrin.def.num_components(); let dst = b.alloc_ssa(RegFile::GPR, comps); - if self.nir.info.stage() == MESA_SHADER_FRAGMENT { - assert!(intrin.intrinsic == nir_intrinsic_load_input); - let addr = u16::try_from(intrin.base()).unwrap() - + u16::try_from(srcs[0].as_uint().unwrap()).unwrap() - + u16::try_from(intrin.component()).unwrap() * 4; + // TODO: should be in the vtg block but we cannot have two mutability around. + let (vtx, offset) = match intrin.intrinsic { + nir_intrinsic_load_input => { + (Src::new_zero(), self.get_src(&srcs[0])) + } + nir_intrinsic_load_per_vertex_input => { + (self.get_src(&srcs[0]), self.get_src(&srcs[1])) + } + _ => panic!("Unhandled intrinsic"), + }; - for c in 0..comps { - let attribute_id = addr + 4 * u16::from(c); - self.info.set_used_attribute_id( - attribute_id, - None, - false, - ); - b.push_op(OpIpa { - dst: dst[usize::from(c)].into(), - addr: attribute_id, - freq: InterpFreq::Constant, - loc: InterpLoc::Default, - offset: SrcRef::Zero.into(), + match &mut self.info.io { + ShaderIoInfo::None => { + panic!("Stage does not support load_input") + } + ShaderIoInfo::Fragment(io) => { + assert!(intrin.intrinsic == nir_intrinsic_load_input); + let addr = u16::try_from(intrin.base()).unwrap() + + u16::try_from(srcs[0].as_uint().unwrap()) + .unwrap() + + u16::try_from(intrin.component()).unwrap() * 4; + + for c in 0..comps { + let attribute_id = addr + 4 * u16::from(c); + + if attribute_id < 0x080 { + io.sysvals_in.ab |= 1 << (attribute_id / 4); + } else if attribute_id >= 0x080 + && attribute_id < 0x280 + { + let user_attribute_index = + (attribute_id - 0x080) as usize / 4; + + io.attr_in[user_attribute_index] = + PixelImap::Constant; + } else if attribute_id >= 0x2c0 + && attribute_id < 0x300 + { + io.sysvals_in.c |= + 1 << ((attribute_id - 0x2c0) / 4); + } + + b.push_op(OpIpa { + dst: dst[usize::from(c)].into(), + addr: attribute_id, + freq: InterpFreq::Constant, + loc: InterpLoc::Default, + offset: SrcRef::Zero.into(), + }); + } + } + ShaderIoInfo::Vtg(io) => { + let addr = u16::try_from(intrin.base()).unwrap() + + u16::try_from(intrin.component()).unwrap() * 4; + + let access = AttrAccess { + addr: addr, + comps: comps, + patch: false, + out_load: false, + flags: 0, + }; + + let attribute_base_index = access.addr / 4; + for attribute_index in attribute_base_index + ..attribute_base_index + access.comps as u16 + { + let attribute_id = attribute_index * 4; + + if attribute_id < 0x080 { + io.sysvals_in.ab |= 1 << (attribute_id / 4); + } else if attribute_id >= 0x080 + && attribute_id < 0x280 + { + BitMutView::new(&mut io.attr_in).set_bit( + (attribute_id as usize - 0x080) / 4, + true, + ); + } else if attribute_id >= 0x2c0 + && attribute_id < 0x300 + { + io.sysvals_in.c |= + 1 << ((attribute_id - 0x2c0) / 4); + } + } + + b.push_op(OpALd { + dst: dst.into(), + vtx: vtx, + offset: offset, + access: access, }); } - } else { - let addr = u16::try_from(intrin.base()).unwrap() - + u16::try_from(intrin.component()).unwrap() * 4; - - let (vtx, offset) = match intrin.intrinsic { - nir_intrinsic_load_input => { - (Src::new_zero(), self.get_src(&srcs[0])) - } - nir_intrinsic_load_per_vertex_input => { - (self.get_src(&srcs[0]), self.get_src(&srcs[1])) - } - _ => panic!("Unhandled intrinsic"), - }; - - let access = AttrAccess { - addr: addr, - comps: comps, - patch: false, - out_load: false, - flags: 0, - }; - - let attribute_base_index = access.addr / 4; - for attribute_index in attribute_base_index - ..attribute_base_index + comps as u16 - { - self.info.set_used_attribute_id( - attribute_index * 4, - None, - false, - ); - } - - b.push_op(OpALd { - dst: dst.into(), - vtx: vtx, - offset: offset, - access: access, - }); } + self.set_dst(&intrin.def, dst); } nir_intrinsic_load_interpolated_input => { @@ -1410,7 +1447,7 @@ impl<'a> ShaderFromNir<'a> { let (freq, loc) = match bary.intrinsic { nir_intrinsic_load_barycentric_at_offset_nv => { (InterpFreq::Pass, InterpLoc::Offset) - }, + } nir_intrinsic_load_barycentric_centroid => { (InterpFreq::Pass, InterpLoc::Centroid) } @@ -1443,11 +1480,57 @@ impl<'a> ShaderFromNir<'a> { for c in 0..intrin.def.num_components() { let attribute_id = addr + 4 * u16::from(c); - self.info.set_used_attribute_id( - attribute_id, - Some(interp_mode), - false, - ); + + if attribute_id < 0x080 { + match &mut self.info.io { + ShaderIoInfo::None => { + panic!("Stage does not support load_interpolated_input") + } + ShaderIoInfo::Vtg(VtgIoInfo { + sysvals_in, .. + }) + | ShaderIoInfo::Fragment(FragmentIoInfo { + sysvals_in, + .. + }) => { + sysvals_in.ab |= 1 << (attribute_id / 4); + } + } + } else if attribute_id >= 0x080 && attribute_id < 0x280 { + let user_attribute_index = + (attribute_id - 0x080) as usize / 4; + + match &mut self.info.io { + ShaderIoInfo::None => { + panic!("Stage does not support load_interpolated_input") + } + ShaderIoInfo::Vtg(io) => { + BitMutView::new(&mut io.attr_in) + .set_bit(user_attribute_index, true); + } + ShaderIoInfo::Fragment(io) => { + io.attr_in[user_attribute_index] = interp_mode; + } + _ => {} + } + } else if attribute_id >= 0x2c0 && attribute_id < 0x300 { + match &mut self.info.io { + ShaderIoInfo::None => { + panic!("Stage does not support load_interpolated_input") + } + ShaderIoInfo::Vtg(VtgIoInfo { + sysvals_in, .. + }) + | ShaderIoInfo::Fragment(FragmentIoInfo { + sysvals_in, + .. + }) => { + sysvals_in.c |= + 1 << ((attribute_id - 0x2c0) / 4); + } + } + } + b.push_op(OpIpa { dst: dst[usize::from(c)].into(), addr: attribute_id, @@ -1467,7 +1550,7 @@ impl<'a> ShaderFromNir<'a> { self.set_dst(&intrin.def, dst); } nir_intrinsic_load_sample_mask_in => { - if let ShaderStageInfo::Fragment(info) = &mut self.info.stage { + if let ShaderIoInfo::Fragment(info) = &mut self.info.io { info.reads_sample_mask = true; } else { panic!("sample_mask_in is only available in fragment shaders"); @@ -1660,51 +1743,69 @@ impl<'a> ShaderFromNir<'a> { }); } nir_intrinsic_store_output => { - if self.nir.info.stage() == MESA_SHADER_FRAGMENT { - /* We assume these only ever happen in the last block. - * This is ensured by nir_lower_io_to_temporaries() - */ - let data = *self.get_src(&srcs[0]).as_ssa().unwrap(); - assert!(srcs[1].is_zero()); - let base: usize = intrin.base().try_into().unwrap(); - assert!(base % 4 == 0); - for c in 0..usize::from(intrin.num_components) { - self.fs_out_regs[(base / 4) + c] = data[c]; + let data = self.get_src(&srcs[0]); + let vtx = Src::new_zero(); + let offset = self.get_src(&srcs[1]); + + match &mut self.info.io { + ShaderIoInfo::None => { + panic!("Stage does not support load_input") } - } else { - let addr = u16::try_from(intrin.base()).unwrap() - + u16::try_from(intrin.component()).unwrap() * 4; - - let data = self.get_src(&srcs[0]); - let vtx = Src::new_zero(); - let offset = self.get_src(&srcs[1]); - - assert!(intrin.get_src(0).bit_size() == 32); - let access = AttrAccess { - addr: addr, - comps: intrin.get_src(0).num_components(), - patch: false, - out_load: false, - flags: 0, - }; - - let attribute_base_index = access.addr / 4; - for attribute_index in attribute_base_index - ..attribute_base_index + access.comps as u16 - { - self.info.set_used_attribute_id( - attribute_index * 4, - None, - true, - ); + ShaderIoInfo::Fragment(io) => { + /* We assume these only ever happen in the last block. + * This is ensured by nir_lower_io_to_temporaries() + */ + let data = *self.get_src(&srcs[0]).as_ssa().unwrap(); + assert!(srcs[1].is_zero()); + let base: usize = intrin.base().try_into().unwrap(); + assert!(base % 4 == 0); + for c in 0..usize::from(intrin.num_components) { + self.fs_out_regs[(base / 4) + c] = data[c]; + } } + ShaderIoInfo::Vtg(io) => { + let addr = u16::try_from(intrin.base()).unwrap() + + u16::try_from(intrin.component()).unwrap() * 4; - b.push_op(OpASt { - vtx: vtx, - offset: offset, - data: data, - access: access, - }); + assert!(intrin.get_src(0).bit_size() == 32); + let access = AttrAccess { + addr: addr, + comps: intrin.get_src(0).num_components(), + patch: false, + out_load: false, + flags: 0, + }; + + let attribute_base_index = access.addr / 4; + for attribute_index in attribute_base_index + ..attribute_base_index + access.comps as u16 + { + let attribute_id = attribute_index * 4; + + if attribute_id < 0x080 { + io.sysvals_out.ab |= 1 << (attribute_id / 4); + } else if attribute_id >= 0x080 + && attribute_id < 0x280 + { + BitMutView::new(&mut io.attr_out).set_bit( + (attribute_id as usize - 0x080) / 4, + true, + ); + } else if attribute_id >= 0x2c0 + && attribute_id < 0x300 + { + io.sysvals_out.c |= + 1 << ((attribute_id - 0x2c0) / 4); + } + } + + b.push_op(OpASt { + vtx: vtx, + offset: offset, + data: data, + access: access, + }); + } } } nir_intrinsic_store_scratch => { @@ -1801,7 +1902,7 @@ impl<'a> ShaderFromNir<'a> { } fn store_fs_outputs(&mut self, b: &mut impl SSABuilder) { - let ShaderStageInfo::Fragment(info) = &mut self.info.stage else { + let ShaderIoInfo::Fragment(info) = &mut self.info.io else { return; }; diff --git a/src/nouveau/compiler/nak_ir.rs b/src/nouveau/compiler/nak_ir.rs index aacf5d1e3bd..3900dfc03f4 100644 --- a/src/nouveau/compiler/nak_ir.rs +++ b/src/nouveau/compiler/nak_ir.rs @@ -5,6 +5,7 @@ extern crate nak_ir_proc; +use crate::bitview::{BitMutView, SetField}; pub use crate::nak_builder::{ Builder, InstrBuilder, SSABuilder, SSAInstrBuilder, }; @@ -4477,15 +4478,6 @@ pub struct ComputeShaderInfo { pub smem_size: u16, } -#[derive(Debug, Default)] -pub struct FragmentShaderInfo { - pub reads_sample_mask: bool, - pub uses_kill: bool, - pub writes_color: u32, - pub writes_sample_mask: bool, - pub writes_depth: bool, -} - #[derive(Debug)] pub struct GeometryShaderInfo { pub stream_out_mask: u8, @@ -4515,25 +4507,45 @@ pub struct TessellationControlShaderInfo { pub enum ShaderStageInfo { Compute(ComputeShaderInfo), Vertex, - Fragment(FragmentShaderInfo), + Fragment, Geometry(GeometryShaderInfo), TessellationControl(TessellationControlShaderInfo), Tessellation, } #[derive(Debug, Default)] -pub struct SystemValueInfo { +pub struct SysValInfo { pub ab: u32, pub c: u16, } -#[derive(Debug, Default)] -pub struct ShaderStageVtgInfo { - pub output_attributes: [u8; 32], +#[derive(Debug)] +pub struct VtgIoInfo { + pub sysvals_in: SysValInfo, + pub sysvals_out: SysValInfo, + pub attr_in: [u32; 4], + pub attr_out: [u32; 4], pub store_req_start: u8, pub store_req_end: u8, - pub system_values_out: SystemValueInfo, - pub omap_color: u16, +} + +#[derive(Debug)] +pub struct FragmentIoInfo { + pub sysvals_in: SysValInfo, + pub attr_in: [PixelImap; 128], + + pub reads_sample_mask: bool, + pub uses_kill: bool, + pub writes_color: u32, + pub writes_sample_mask: bool, + pub writes_depth: bool, +} + +#[derive(Debug)] +pub enum ShaderIoInfo { + None, + Vtg(VtgIoInfo), + Fragment(FragmentIoInfo), } #[derive(Debug)] @@ -4545,10 +4557,7 @@ pub struct ShaderInfo { pub writes_global_mem: bool, pub uses_fp64: bool, pub stage: ShaderStageInfo, - pub vtg_stage_info: Option, - pub input_attributes: [u8; 32], - pub imap_color: u16, - pub system_values_in: SystemValueInfo, + pub io: ShaderIoInfo, } pub struct Shader { @@ -4556,61 +4565,6 @@ pub struct Shader { pub functions: Vec, } -impl ShaderInfo { - pub fn set_used_attribute_id( - &mut self, - attribute_id: u16, - pixel_opt: Option, - is_store: bool, - ) { - if attribute_id < 0x080 { - let bit = attribute_id / 4; - - if is_store { - if let Some(vtg) = &mut self.vtg_stage_info { - vtg.system_values_out.ab |= 1 << bit; - } - } else { - self.system_values_in.ab |= 1 << bit; - } - } else if attribute_id >= 0x080 && attribute_id < 0x280 { - let user_attribute_base = attribute_id - 0x080; - let user_attribute_index = (user_attribute_base / 0x10) as usize; - let user_attribute_component_bit_start = - (user_attribute_base % 0x10) as usize / 4; - - if let Some(vtg) = &mut self.vtg_stage_info { - let attributes = if is_store { - &mut vtg.output_attributes - } else { - &mut self.input_attributes - }; - - attributes[user_attribute_index] |= - 1 << user_attribute_component_bit_start; - } else if !is_store { - if let ShaderStageInfo::Fragment(_) = &mut self.stage { - let pixel = pixel_opt.unwrap_or(PixelImap::Perspective); - - self.input_attributes[user_attribute_index] |= - u8::from(pixel) - << user_attribute_component_bit_start * 2; - } - } - } else if attribute_id >= 0x2c0 && attribute_id < 0x300 { - let bit = (attribute_id - 0x2c0) / 4; - - if is_store { - if let Some(vtg) = &mut self.vtg_stage_info { - vtg.system_values_out.c |= 1 << bit; - } - } else { - self.system_values_in.c |= 1 << bit; - } - } - } -} - impl Shader { pub fn for_each_instr(&self, f: &mut impl FnMut(&Instr)) { for func in &self.functions { diff --git a/src/nouveau/compiler/nak_sph.rs b/src/nouveau/compiler/nak_sph.rs index fa05ce82c98..4f0d4cde2e0 100644 --- a/src/nouveau/compiler/nak_sph.rs +++ b/src/nouveau/compiler/nak_sph.rs @@ -10,7 +10,7 @@ use crate::{ BitMutView, BitMutViewable, BitView, BitViewable, SetBit, SetField, SetFieldU64, }, - nak_ir::{ShaderInfo, ShaderStageInfo}, + nak_ir::{ShaderInfo, ShaderIoInfo, ShaderStageInfo}, }; pub const FERMI_SHADER_HEADER_SIZE: usize = 20; @@ -32,7 +32,7 @@ impl From<&ShaderStageInfo> for ShaderType { fn from(value: &ShaderStageInfo) -> Self { match value { ShaderStageInfo::Vertex => ShaderType::Vertex, - ShaderStageInfo::Fragment(_) => ShaderType::Fragment, + ShaderStageInfo::Fragment => ShaderType::Fragment, ShaderStageInfo::Geometry(_) => ShaderType::Geometry, ShaderStageInfo::TessellationControl(_) => { ShaderType::TessellationControl @@ -374,22 +374,21 @@ impl ShaderProgramHeader { } #[inline] - pub fn set_imap_vector(&mut self, index: usize, value: u8) { - assert!(index < 32); + pub fn set_imap_vector_ps(&mut self, index: usize, value: PixelImap) { + assert!(index < 128); + assert!(self.shader_type == ShaderType::Fragment); - let (mut imap_g, elem_size) = - if self.shader_type == ShaderType::Fragment { - (self.imap_g_ps(), 8) - } else { - (self.imap_g_vtg(), 4) - }; - - imap_g.set_field(index * elem_size..(index + 1) * elem_size, value); + self.imap_g_ps() + .set_field(index * 2..(index + 1) * 2, u8::from(value)); } #[inline] - pub fn set_imap_color(&mut self, value: u16) { - self.set_field(320..336, value); + pub fn set_imap_vector_vtg(&mut self, index: usize, value: u32) { + assert!(index < 4); + assert!(self.shader_type != ShaderType::Fragment); + + self.imap_g_vtg() + .set_field(index * 32..(index + 1) * 32, value); } #[inline] @@ -403,16 +402,11 @@ impl ShaderProgramHeader { } #[inline] - pub fn set_omap_vector(&mut self, index: usize, value: u8) { - assert!(index < 32); + pub fn set_omap_vector(&mut self, index: usize, value: u32) { + assert!(index < 4); + assert!(self.shader_type != ShaderType::Fragment); - let (mut omap_g, elem_size) = (self.omap_g(), 4); - omap_g.set_field(index * elem_size..(index + 1) * elem_size, value); - } - - #[inline] - pub fn set_omap_color(&mut self, value: u16) { - self.set_field(560..576, value); + self.omap_g().set_field(index * 32..(index + 1) * 32, value); } #[inline] @@ -452,41 +446,45 @@ pub fn encode_header( sph.set_does_fp64(shader_info.uses_fp64); sph.set_shader_local_memory_size(shader_info.tls_size.into()); - sph.set_imap_system_values_ab(shader_info.system_values_in.ab); - sph.set_imap_system_values_c(shader_info.system_values_in.c); + match &shader_info.io { + ShaderIoInfo::Vtg(io) => { + sph.set_imap_system_values_ab(io.sysvals_in.ab); + sph.set_imap_system_values_c(io.sysvals_in.c); - for (index, vec) in shader_info.input_attributes.iter().enumerate() { - sph.set_imap_vector(index, *vec); - } - sph.set_imap_color(shader_info.imap_color); + for (index, value) in io.attr_in.iter().enumerate() { + sph.set_imap_vector_vtg(index, *value); + } - if let Some(vtg_stage_info) = &shader_info.vtg_stage_info { - for (index, vec) in vtg_stage_info.output_attributes.iter().enumerate() - { - sph.set_omap_vector(index, *vec); + for (index, value) in io.attr_out.iter().enumerate() { + sph.set_omap_vector(index, *value); + } + + sph.set_store_req_start(io.store_req_start); + sph.set_store_req_end(io.store_req_end); + + sph.set_omap_system_values_ab(io.sysvals_out.ab); + sph.set_omap_system_values_c(io.sysvals_out.c); } - sph.set_omap_color(vtg_stage_info.omap_color); + ShaderIoInfo::Fragment(io) => { + sph.set_imap_system_values_ab(io.sysvals_in.ab); + sph.set_imap_system_values_c(io.sysvals_in.c); - sph.set_store_req_start(vtg_stage_info.store_req_start); - sph.set_store_req_end(vtg_stage_info.store_req_end); + for (index, imap) in io.attr_in.iter().enumerate() { + sph.set_imap_vector_ps(index, *imap); + } - sph.set_omap_system_values_ab(vtg_stage_info.system_values_out.ab); - sph.set_omap_system_values_c(vtg_stage_info.system_values_out.c); + let zs_self_dep = fs_key.map_or(false, |key| key.zs_self_dep); + + sph.set_multiple_render_target_enable(io.writes_color > 0xf); + sph.set_kills_pixels(io.uses_kill || zs_self_dep); + sph.set_omap_sample_mask(io.writes_sample_mask); + sph.set_omap_depth(io.writes_depth); + sph.set_omap_targets(io.writes_color); + } + _ => {} } match &shader_info.stage { - // Already covered by VTG common data. - ShaderStageInfo::Vertex | ShaderStageInfo::Tessellation => {} - ShaderStageInfo::Fragment(stage) => { - let zs_self_dep = fs_key.map_or(false, |key| key.zs_self_dep); - - sph.set_multiple_render_target_enable(stage.writes_color > 0xf); - sph.set_kills_pixels(stage.uses_kill || zs_self_dep); - sph.set_omap_sample_mask(stage.writes_sample_mask); - sph.set_omap_depth(stage.writes_depth); - - sph.set_omap_targets(stage.writes_color); - } ShaderStageInfo::Geometry(stage) => { sph.set_stream_out_mask(stage.stream_out_mask); sph.set_threads_per_input_primitive( @@ -502,6 +500,7 @@ pub fn encode_header( ShaderStageInfo::Compute(_) => { panic!("Compute shaders don't have a SPH!") } + _ => {} }; sph.data