diff --git a/src/back/hlsl/mod.rs b/src/back/hlsl/mod.rs index 4dc3ed6e6..242c090a5 100644 --- a/src/back/hlsl/mod.rs +++ b/src/back/hlsl/mod.rs @@ -164,8 +164,8 @@ pub struct Writer<'a, W> { namer: proc::Namer, /// HLSL backend options options: &'a Options, - /// Information about entry point arguments wrapped into structure - ep_inputs: Vec>, + /// Information about entry point arguments and result types. + entry_point_io: Vec, /// Set of expressions that have associated temporary variables named_expressions: crate::NamedExpressions, wrapped_array_lengths: crate::FastHashSet, diff --git a/src/back/hlsl/writer.rs b/src/back/hlsl/writer.rs index f3170c3e4..96740fbec 100644 --- a/src/back/hlsl/writer.rs +++ b/src/back/hlsl/writer.rs @@ -17,20 +17,36 @@ const SPECIAL_BASE_VERTEX: &str = "base_vertex"; const SPECIAL_BASE_INSTANCE: &str = "base_instance"; const SPECIAL_OTHER: &str = "other"; +struct EpStructMember { + name: String, + ty: Handle, + // technically, this should always be `Some` + binding: Option, + index: u32, +} + /// Structure contains information required for generating /// wrapped structure of all entry points arguments -pub(super) struct EntryPointBinding { +struct EntryPointBinding { + /// Name of the fake EP argument that contains the struct + /// with all the flattened input data. + arg_name: String, /// Generated structure name - name: String, + ty_name: String, /// Members of generated structure members: Vec, } -struct EpStructMember { - name: String, - ty: Handle, - binding: Option, - index: usize, +pub(super) struct EntryPointInterface { + /// If `Some`, the input of an entry point is gathered in a special + /// struct with members sorted by binding. + /// The `EntryPointBinding::members` array is sorted by index, + /// so that we can walk it in `write_ep_arguments_initialization`. + input: Option, + /// If `Some`, the output of an entry point is flattened. + /// The `EntryPointBinding::members` array is sorted by binding, + /// So that we can walk it in `Statement::Return` handler. + output: Option, } #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] @@ -50,19 +66,6 @@ impl InterfaceKey { } } -// Returns true for structures that need their members permuted, -// so that first come the user-defined varyings -// in ascending locations, and then built-ins. This allows VS and FS -// interfaces to match with regards to order. -fn needs_permutation(members: &[crate::StructMember]) -> bool { - //Note: this is a bit of a hack. We need to re-order the output fields, but we can only do this - // for non-layouted structures. It may be possible for an WGSL program can use the same struct - // for both host sharing and the interface. This case isn't supported here. - let has_layout = members.iter().any(|m| m.offset != 0); - let has_binding = members.iter().any(|m| m.binding.is_some()); - has_binding && !has_layout -} - #[derive(Copy, Clone, PartialEq)] enum Io { Input, @@ -76,7 +79,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { names: crate::FastHashMap::default(), namer: proc::Namer::default(), options, - ep_inputs: Vec::new(), + entry_point_io: Vec::new(), named_expressions: crate::NamedExpressions::default(), wrapped_array_lengths: crate::FastHashSet::default(), wrapped_image_queries: crate::FastHashSet::default(), @@ -88,7 +91,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { self.names.clear(); self.namer .reset(module, super::keywords::RESERVED, &[], &mut self.names); - self.ep_inputs.clear(); + self.entry_point_io.clear(); self.named_expressions.clear(); self.wrapped_array_lengths.clear(); self.wrapped_image_queries.clear(); @@ -199,8 +202,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { // Write all entry points wrapped structs for ep in module.entry_points.iter() { - let ep_input = self.write_ep_input_struct(module, &ep.function, ep.stage, &ep.name)?; - self.ep_inputs.push(ep_input); + let ep_io = self.write_ep_interface(module, &ep.function, ep.stage, &ep.name)?; + self.entry_point_io.push(ep_io); } // Write all regular functions @@ -306,6 +309,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { Ok(super::ReflectionInfo { entry_point_names }) } + //TODO: we could force fragment outputs to always go through `entry_point_io.output` path + // if they are struct, so that the `stage` argument here could be omitted. fn write_semantic( &mut self, binding: &crate::Binding, @@ -328,67 +333,209 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { Ok(()) } + fn write_interface_struct( + &mut self, + module: &Module, + shader_stage: (ShaderStage, Io), + struct_name: String, + mut members: Vec, + ) -> Result { + // Sort the members so that first come the user-defined varyings + // in ascending locations, and then built-ins. This allows VS and FS + // interfaces to match with regards to order. + members.sort_by_key(|m| InterfaceKey::new(m.binding.as_ref())); + + write!(self.out, "struct {}", struct_name)?; + writeln!(self.out, " {{")?; + for m in members.iter() { + write!(self.out, "{}", back::INDENT)?; + self.write_type(module, m.ty)?; + write!(self.out, " {}", &m.name)?; + if let Some(ref binding) = m.binding { + self.write_semantic(binding, Some(shader_stage))?; + } + writeln!(self.out, ";")?; + } + writeln!(self.out, "}};")?; + writeln!(self.out)?; + + match shader_stage.1 { + Io::Input => { + // bring back the original order + members.sort_by_key(|m| m.index); + } + Io::Output => { + // keep it sorted by binding + } + } + + Ok(EntryPointBinding { + arg_name: self.namer.call_unique(struct_name.to_lowercase().as_str()), + ty_name: struct_name, + members, + }) + } + + /// Flatten all entry point arguments into a single struct. + /// This is needed since we need to re-order them: first placing user locations, + /// then built-ins. fn write_ep_input_struct( &mut self, module: &Module, func: &crate::Function, stage: ShaderStage, entry_point_name: &str, - ) -> Result, Error> { - Ok(if !func.arguments.is_empty() { - let struct_name_prefix = match stage { - ShaderStage::Vertex => "VertexInput", - ShaderStage::Fragment => "FragmentInput", - ShaderStage::Compute => "ComputeInput", - }; - let struct_name = format!("{}_{}", struct_name_prefix, entry_point_name); + ) -> Result { + let struct_name = format!("{:?}Input_{}", stage, entry_point_name); - let mut members = Vec::with_capacity(func.arguments.len()); - for (index, arg) in func.arguments.iter().enumerate() { - let member_name = if let Some(ref name) = arg.name { - name - } else { - "member" - }; - members.push(EpStructMember { - name: self.namer.call_unique(member_name), - ty: arg.ty, - binding: arg.binding.clone(), - index, - }); - } - - // Sort the members so that first come the user-defined varyings - // in ascending locations, and then built-ins. This allows VS and FS - // interfaces to match with regards to order. - members.sort_by_key(|m| InterfaceKey::new(m.binding.as_ref())); - - write!(self.out, "struct {}", &struct_name)?; - writeln!(self.out, " {{")?; - for m in members.iter() { - write!(self.out, "{}", back::INDENT)?; - self.write_type(module, m.ty)?; - write!(self.out, " {}", &m.name)?; - if let Some(ref binding) = m.binding { - self.write_semantic(binding, Some((stage, Io::Input)))?; + let mut fake_members = Vec::new(); + for arg in func.arguments.iter() { + match module.types[arg.ty].inner { + TypeInner::Struct { ref members, .. } => { + for member in members.iter() { + let member_name = if let Some(ref name) = member.name { + name + } else { + "member" + }; + let index = fake_members.len() as u32; + fake_members.push(EpStructMember { + name: self.namer.call_unique(member_name), + ty: member.ty, + binding: member.binding.clone(), + index, + }); + } + } + _ => { + let member_name = if let Some(ref name) = arg.name { + name + } else { + "member" + }; + let index = fake_members.len() as u32; + fake_members.push(EpStructMember { + name: self.namer.call_unique(member_name), + ty: arg.ty, + binding: arg.binding.clone(), + index, + }); } - writeln!(self.out, ";")?; } - writeln!(self.out, "}};")?; - writeln!(self.out)?; + } - // now bring back the old order - members.sort_by_key(|m| m.index); + self.write_interface_struct(module, (stage, Io::Input), struct_name, fake_members) + } - Some(EntryPointBinding { - name: struct_name, - members, - }) - } else { - None + /// Flatten all entry point results into a single struct. + /// This is needed since we need to re-order them: first placing user locations, + /// then built-ins. + fn write_ep_output_struct( + &mut self, + module: &Module, + result: &crate::FunctionResult, + stage: ShaderStage, + entry_point_name: &str, + ) -> Result { + let struct_name = format!("{:?}Output_{}", stage, entry_point_name); + + let mut fake_members = Vec::new(); + let empty = []; + let members = match module.types[result.ty].inner { + TypeInner::Struct { ref members, .. } => members, + ref other => { + log::error!("Unexpected {:?} output type without a binding", other); + &empty[..] + } + }; + + for member in members.iter() { + let member_name = if let Some(ref name) = member.name { + name + } else { + "member" + }; + let index = fake_members.len() as u32; + fake_members.push(EpStructMember { + name: self.namer.call_unique(member_name), + ty: member.ty, + binding: member.binding.clone(), + index, + }); + } + + self.write_interface_struct(module, (stage, Io::Output), struct_name, fake_members) + } + + /// Writes special interface structures for an entry point. The special structures have + /// all the fields flattened into them and sorted by binding. They are only needed for + /// VS outputs and FS inputs, so that these interfaces match. + fn write_ep_interface( + &mut self, + module: &Module, + func: &crate::Function, + stage: ShaderStage, + ep_name: &str, + ) -> Result { + Ok(EntryPointInterface { + input: if !func.arguments.is_empty() && stage == ShaderStage::Fragment { + Some(self.write_ep_input_struct(module, func, stage, ep_name)?) + } else { + None + }, + output: match func.result { + Some(ref fr) if fr.binding.is_none() && stage == ShaderStage::Vertex => { + Some(self.write_ep_output_struct(module, fr, stage, ep_name)?) + } + _ => None, + }, }) } + /// Write an entry point preface that initializes the arguments as specified in IR. + fn write_ep_arguments_initialization( + &mut self, + module: &Module, + func: &crate::Function, + ep_index: u16, + ) -> BackendResult { + let ep_input = match self.entry_point_io[ep_index as usize].input.take() { + Some(ep_input) => ep_input, + None => return Ok(()), + }; + let mut fake_iter = ep_input.members.iter(); + for (arg_index, arg) in func.arguments.iter().enumerate() { + write!(self.out, "{}", back::INDENT)?; + self.write_type(module, arg.ty)?; + let arg_name = &self.names[&NameKey::EntryPointArgument(ep_index, arg_index as u32)]; + write!(self.out, " {}", arg_name)?; + match module.types[arg.ty].inner { + TypeInner::Array { size, .. } => { + self.write_array_size(module, size)?; + let fake_member = fake_iter.next().unwrap(); + writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?; + } + TypeInner::Struct { ref members, .. } => { + write!(self.out, " = {{ ")?; + for index in 0..members.len() { + if index != 0 { + write!(self.out, ", ")?; + } + let fake_member = fake_iter.next().unwrap(); + write!(self.out, "{}.{}", ep_input.arg_name, fake_member.name)?; + } + writeln!(self.out, " }};")?; + } + _ => { + let fake_member = fake_iter.next().unwrap(); + writeln!(self.out, " = {}.{};", ep_input.arg_name, fake_member.name)?; + } + } + } + assert!(fake_iter.next().is_none()); + Ok(()) + } + /// Helper method used to write global variables /// # Notes /// Always adds a newline @@ -571,28 +718,18 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { module: &Module, handle: Handle, _block: bool, - original_members: &[crate::StructMember], + members: &[crate::StructMember], shader_stage: Option<(ShaderStage, Io)>, ) -> BackendResult { // Write struct name - write!(self.out, "struct {}", self.names[&NameKey::Type(handle)])?; - writeln!(self.out, " {{")?; + let struct_name = &self.names[&NameKey::Type(handle)]; + writeln!(self.out, "struct {} {{", struct_name)?; - //TODO: avoid heap allocation - let mut members = original_members - .iter() - .enumerate() - .map(|(index, m)| (index, m.ty, m.binding.clone())) - .collect::>(); - if needs_permutation(original_members) { - members.sort_by_key(|&(_, _, ref binding)| InterfaceKey::new(binding.as_ref())); - } - - for (index, ty, binding) in members { + for (index, member) in members.iter().enumerate() { // The indentation is only for readability write!(self.out, "{}", back::INDENT)?; - match module.types[ty].inner { + match module.types[member.ty].inner { TypeInner::Array { base, size, @@ -629,7 +766,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { interpolation, sampling, .. - }) = binding + }) = member.binding { if let Some(interpolation) = interpolation { write!(self.out, "{} ", interpolation.to_hlsl_str())? @@ -642,12 +779,12 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } } - if let TypeInner::Matrix { .. } = module.types[ty].inner { + if let TypeInner::Matrix { .. } = module.types[member.ty].inner { write!(self.out, "row_major ")?; } // Write the member type and name - self.write_type(module, ty)?; + self.write_type(module, member.ty)?; write!( self.out, " {}", @@ -656,7 +793,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } } - if let Some(ref binding) = binding { + if let Some(ref binding) = member.binding { self.write_semantic(binding, shader_stage)?; }; writeln!(self.out, ";")?; @@ -760,7 +897,18 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { ) -> BackendResult { // Function Declaration Syntax - https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-function-syntax if let Some(ref result) = func.result { - self.write_type(module, result.ty)?; + match func_ctx.ty { + back::FunctionType::Function(_) => { + self.write_type(module, result.ty)?; + } + back::FunctionType::EntryPoint(index) => { + if let Some(ref ep_output) = self.entry_point_io[index as usize].output { + write!(self.out, "{}", ep_output.ty_name)?; + } else { + self.write_type(module, result.ty)?; + } + } + } } else { write!(self.out, "void")?; } @@ -772,6 +920,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { match func_ctx.ty { back::FunctionType::Function(handle) => { for (index, arg) in func.arguments.iter().enumerate() { + if index != 0 { + write!(self.out, ", ")?; + } // Write argument type let arg_ty = match module.types[arg.ty].inner { // pointers in function arguments are expected and resolve to `inout` @@ -792,31 +943,30 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { if let TypeInner::Array { size, .. } = module.types[arg.ty].inner { self.write_array_size(module, size)?; } - if index < func.arguments.len() - 1 { - // Add a separator between args - write!(self.out, ", ")?; - } } } - back::FunctionType::EntryPoint(index) => { - // EntryPoint arguments wrapped into structure - // We need to ensure that entry points have arguments too. - // For the case when we working with multiple entry points - // for example vertex shader with arguments and fragment shader without arguments. - if !self.ep_inputs.is_empty() - && !module.entry_points[index as usize] - .function - .arguments - .is_empty() - { - if let Some(ref ep_input) = self.ep_inputs[index as usize] { - write!( - self.out, - "{} {}", - ep_input.name, - self.namer - .call_unique(ep_input.name.to_lowercase().as_str()) - )?; + back::FunctionType::EntryPoint(ep_index) => { + if let Some(ref ep_input) = self.entry_point_io[ep_index as usize].input { + write!(self.out, "{} {}", ep_input.ty_name, ep_input.arg_name,)?; + } else { + let stage = module.entry_points[ep_index as usize].stage; + for (index, arg) in func.arguments.iter().enumerate() { + if index != 0 { + write!(self.out, ", ")?; + } + self.write_type(module, arg.ty)?; + + let argument_name = + &self.names[&NameKey::EntryPointArgument(ep_index, index as u32)]; + + write!(self.out, " {}", argument_name)?; + if let TypeInner::Array { size, .. } = module.types[arg.ty].inner { + self.write_array_size(module, size)?; + } + + if let Some(ref binding) = arg.binding { + self.write_semantic(binding, Some((stage, Io::Input)))?; + } } } } @@ -825,21 +975,25 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, ")")?; // Write semantic if it present - let stage = match func_ctx.ty { - back::FunctionType::EntryPoint(index) => { - Some(module.entry_points[index as usize].stage) - } - _ => None, - }; - if let Some(ref result) = func.result { - if let Some(ref binding) = result.binding { - self.write_semantic(binding, stage.map(|s| (s, Io::Output)))?; + if let back::FunctionType::EntryPoint(index) = func_ctx.ty { + let stage = module.entry_points[index as usize].stage; + if let Some(crate::FunctionResult { + binding: Some(ref binding), + .. + }) = func.result + { + self.write_semantic(binding, Some((stage, Io::Output)))?; } } // Function body start writeln!(self.out)?; writeln!(self.out, "{{")?; + + if let back::FunctionType::EntryPoint(index) = func_ctx.ty { + self.write_ep_arguments_initialization(module, func, index)?; + } + // Write function local variables for (handle, local) in func.local_variables.iter() { // Write indentation (only for readability) @@ -982,22 +1136,47 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { // We can safery unwrap here, since we now we working with struct let ty = base_ty_res.handle().unwrap(); let struct_name = &self.names[&NameKey::Type(ty)]; - let variable_name = self.namer.call_unique(struct_name.as_str()).to_lowercase(); + let variable_name = self.namer.call(&struct_name.to_lowercase()); write!( self.out, "{}const {} {} = ", INDENT.repeat(indent), struct_name, - variable_name + variable_name, )?; self.write_expr(module, expr, func_ctx)?; writeln!(self.out, ";")?; - writeln!( - self.out, - "{}return {};", - INDENT.repeat(indent), - variable_name - )?; + + // for entry point returns, we may need to reshuffle the outputs into a different struct + let ep_output = match func_ctx.ty { + back::FunctionType::Function(_) => None, + back::FunctionType::EntryPoint(index) => { + self.entry_point_io[index as usize].output.as_ref() + } + }; + let final_name = match ep_output { + Some(ep_output) => { + let final_name = self.namer.call_unique(&variable_name); + write!( + self.out, + "{}const {} {} = {{ ", + INDENT.repeat(indent), + ep_output.ty_name, + final_name, + )?; + for (index, m) in ep_output.members.iter().enumerate() { + if index != 0 { + write!(self.out, ", ")?; + } + let member_name = &self.names[&NameKey::StructMember(ty, m.index)]; + write!(self.out, "{}.{}", variable_name, member_name)?; + } + writeln!(self.out, " }};")?; + final_name + } + None => variable_name, + }; + writeln!(self.out, "{}return {};", INDENT.repeat(indent), final_name)?; } else { write!(self.out, "{}return ", INDENT.repeat(indent))?; self.write_expr(module, expr, func_ctx)?; @@ -1325,24 +1504,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { match *expression { Expression::Constant(constant) => self.write_constant(module, constant)?, Expression::Compose { ty, ref components } => { - let (braces_init, permutation) = match module.types[ty].inner { - TypeInner::Struct { ref members, .. } => { - let permutation = if needs_permutation(members) { - //TODO: avoid heap allocation. We can pre-compute this at the module leve. - let mut permutation = members - .iter() - .enumerate() - .map(|(index, m)| (index, InterfaceKey::new(m.binding.as_ref()))) - .collect::>(); - permutation.sort_by_key(|&(_, ref key)| key.clone()); - Some(permutation) - } else { - None - }; - (true, permutation) - } - TypeInner::Array { .. } => (true, None), - _ => (false, None), + let braces_init = match module.types[ty].inner { + TypeInner::Struct { .. } | TypeInner::Array { .. } => true, + _ => false, }; if braces_init { @@ -1352,16 +1516,12 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { write!(self.out, "(")?; } - for index in 0..components.len() { + for (index, &component) in components.iter().enumerate() { if index != 0 { // The leading space is for readability only write!(self.out, ", ")?; } - let comp_index = match permutation { - Some(ref perm) => perm[index].0, - None => index, - }; - self.write_expr(module, components[comp_index], func_ctx)?; + self.write_expr(module, component, func_ctx)?; } if braces_init { @@ -1456,24 +1616,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } } Expression::FunctionArgument(pos) => { - match func_ctx.ty { - back::FunctionType::Function(handle) => { - let name = &self.names[&NameKey::FunctionArgument(handle, pos)]; - write!(self.out, "{}", name)?; - } + let key = match func_ctx.ty { + back::FunctionType::Function(handle) => NameKey::FunctionArgument(handle, pos), back::FunctionType::EntryPoint(index) => { - // EntryPoint arguments wrapped into structure - // We can safery unwrap here, because if we write function arguments it means, that ep_input struct already exists - let ep_input = self.ep_inputs[index as usize].as_ref().unwrap(); - let member_name = &ep_input.members[pos as usize].name; - write!( - self.out, - "{}.{}", - &ep_input.name.to_lowercase(), - member_name - )? + NameKey::EntryPointArgument(index, pos) } }; + let name = &self.names[&key]; + write!(self.out, "{}", name)?; } Expression::ImageSample { image, diff --git a/tests/out/hlsl/access.hlsl b/tests/out/hlsl/access.hlsl index 1d9ff1ecf..9e306fcd8 100644 --- a/tests/out/hlsl/access.hlsl +++ b/tests/out/hlsl/access.hlsl @@ -1,10 +1,6 @@ RWByteAddressBuffer bar : register(u0); -struct VertexInput_foo { - uint vi1 : SV_VertexID; -}; - uint NagaBufferLengthRW(RWByteAddressBuffer buffer) { uint ret; @@ -12,7 +8,7 @@ uint NagaBufferLengthRW(RWByteAddressBuffer buffer) return ret; } -float4 foo(VertexInput_foo vertexinput_foo) : SV_Position +float4 foo(uint vi : SV_VertexID) : SV_Position { float foo1 = 0.0; int c[5] = {(int)0,(int)0,(int)0,(int)0,(int)0}; @@ -41,8 +37,8 @@ float4 foo(VertexInput_foo vertexinput_foo) : SV_Position int _result[5]={ a, int(b), 3, 4, 5 }; for(int _i=0; _i<5; ++_i) c[_i] = _result[_i]; } - c[(vertexinput_foo.vi1 + 1u)] = 42; - int value = c[vertexinput_foo.vi1]; + c[(vi + 1u)] = 42; + int value = c[vi]; return mul(float4(int4(value.xxxx)), matrix1); } diff --git a/tests/out/hlsl/boids.hlsl b/tests/out/hlsl/boids.hlsl index 03fd86d05..9288e5c0c 100644 --- a/tests/out/hlsl/boids.hlsl +++ b/tests/out/hlsl/boids.hlsl @@ -19,12 +19,8 @@ cbuffer params : register(b0) { SimParams params; } ByteAddressBuffer particlesSrc : register(t1); RWByteAddressBuffer particlesDst : register(u2); -struct ComputeInput_main { - uint3 global_invocation_id1 : SV_DispatchThreadID; -}; - [numthreads(64, 1, 1)] -void main(ComputeInput_main computeinput_main) +void main(uint3 global_invocation_id : SV_DispatchThreadID) { float2 vPos = (float2)0; float2 vVel = (float2)0; @@ -37,7 +33,7 @@ void main(ComputeInput_main computeinput_main) float2 vel = (float2)0; uint i = 0u; - uint index = computeinput_main.global_invocation_id1.x; + uint index = global_invocation_id.x; if ((index >= NUM_PARTICLES)) { return; } diff --git a/tests/out/hlsl/collatz.hlsl b/tests/out/hlsl/collatz.hlsl index 3f85ea87e..babae9c90 100644 --- a/tests/out/hlsl/collatz.hlsl +++ b/tests/out/hlsl/collatz.hlsl @@ -1,10 +1,6 @@ RWByteAddressBuffer v_indices : register(u0); -struct ComputeInput_main { - uint3 global_id1 : SV_DispatchThreadID; -}; - uint collatz_iterations(uint n_base) { uint n = (uint)0; @@ -32,10 +28,10 @@ uint collatz_iterations(uint n_base) } [numthreads(1, 1, 1)] -void main(ComputeInput_main computeinput_main) +void main(uint3 global_id : SV_DispatchThreadID) { - uint _expr8 = asuint(v_indices.Load(computeinput_main.global_id1.x*4+0)); + uint _expr8 = asuint(v_indices.Load(global_id.x*4+0)); const uint _e9 = collatz_iterations(_expr8); - v_indices.Store(computeinput_main.global_id1.x*4+0, asuint(_e9)); + v_indices.Store(global_id.x*4+0, asuint(_e9)); return; } diff --git a/tests/out/hlsl/control-flow.hlsl b/tests/out/hlsl/control-flow.hlsl index b4e519241..020e228f0 100644 --- a/tests/out/hlsl/control-flow.hlsl +++ b/tests/out/hlsl/control-flow.hlsl @@ -1,10 +1,6 @@ -struct ComputeInput_main { - uint3 global_id1 : SV_DispatchThreadID; -}; - [numthreads(1, 1, 1)] -void main(ComputeInput_main computeinput_main) +void main(uint3 global_id : SV_DispatchThreadID) { int pos = (int)0; diff --git a/tests/out/hlsl/image.hlsl b/tests/out/hlsl/image.hlsl index fb39bceca..d2d46cfda 100644 --- a/tests/out/hlsl/image.hlsl +++ b/tests/out/hlsl/image.hlsl @@ -16,10 +16,6 @@ SamplerState sampler_reg : register(s0, space1); SamplerComparisonState sampler_cmp : register(s1, space1); Texture2D image_2d_depth : register(t2, space1); -struct ComputeInput_main { - uint3 local_id1 : SV_GroupThreadID; -}; - int2 NagaRWDimensions2D(RWTexture2D texture) { uint4 ret; @@ -28,15 +24,15 @@ int2 NagaRWDimensions2D(RWTexture2D texture) } [numthreads(16, 1, 1)] -void main(ComputeInput_main computeinput_main) +void main(uint3 local_id : SV_GroupThreadID) { int2 dim = NagaRWDimensions2D(image_storage_src); - int2 itc = ((dim * int2(computeinput_main.local_id1.xy)) % int2(10, 20)); - uint4 value1_ = image_mipmapped_src.Load(int3(itc, int(computeinput_main.local_id1.z))); - uint4 value2_ = image_multisampled_src.Load(itc, int(computeinput_main.local_id1.z)); - float value3_ = image_depth_multisampled_src.Load(itc, int(computeinput_main.local_id1.z)).x; + int2 itc = ((dim * int2(local_id.xy)) % int2(10, 20)); + uint4 value1_ = image_mipmapped_src.Load(int3(itc, int(local_id.z))); + uint4 value2_ = image_multisampled_src.Load(itc, int(local_id.z)); + float value3_ = image_depth_multisampled_src.Load(itc, int(local_id.z)).x; uint4 value4_ = image_storage_src.Load(itc); - uint4 value5_ = image_array_src.Load(int4(itc, int(computeinput_main.local_id1.z), (int(computeinput_main.local_id1.z) + 1))); + uint4 value5_ = image_array_src.Load(int4(itc, int(local_id.z), (int(local_id.z) + 1))); image_dst[itc.x] = ((((value1_ + value2_) + uint4(uint(value3_).xxxx)) + value4_) + value5_); return; } diff --git a/tests/out/hlsl/interface.hlsl b/tests/out/hlsl/interface.hlsl index 277a00cd0..1899fc95d 100644 --- a/tests/out/hlsl/interface.hlsl +++ b/tests/out/hlsl/interface.hlsl @@ -18,45 +18,42 @@ struct FragmentOutput { groupshared uint output[1]; -struct VertexInput_vertex { - uint color1 : LOC10; - uint instance_index1 : SV_InstanceID; - uint vertex_index1 : SV_VertexID; +struct VertexOutput_vertex { + float varying : LOC1; + float4 position : SV_Position; }; struct FragmentInput_fragment { + float varying : LOC1; + float4 position : SV_Position; bool front_facing1 : SV_IsFrontFace; uint sample_index1 : SV_SampleIndex; uint sample_mask1 : SV_Coverage; - VertexOutput in2; }; -struct ComputeInput_compute { - uint3 global_id1 : SV_DispatchThreadID; - uint3 local_id1 : SV_GroupThreadID; - uint local_index1 : SV_GroupIndex; - uint3 wg_id1 : SV_GroupID; - uint3 num_wgs1 : SV_GroupID; -}; - -VertexOutput vertex(VertexInput_vertex vertexinput_vertex) +VertexOutput_vertex vertex(uint vertex_index : SV_VertexID, uint instance_index : SV_InstanceID, uint color : LOC10) { - uint tmp = (((_NagaConstants.base_vertex + vertexinput_vertex.vertex_index1) + (_NagaConstants.base_instance + vertexinput_vertex.instance_index1)) + vertexinput_vertex.color1); - const VertexOutput vertexoutput1 = { float4(1.0.xxxx), float(tmp) }; + uint tmp = (((_NagaConstants.base_vertex + vertex_index) + (_NagaConstants.base_instance + instance_index)) + color); + const VertexOutput vertexoutput = { float4(1.0.xxxx), float(tmp) }; + const VertexOutput_vertex vertexoutput1 = { vertexoutput.varying, vertexoutput.position }; return vertexoutput1; } FragmentOutput fragment(FragmentInput_fragment fragmentinput_fragment) { - uint mask = (fragmentinput_fragment.sample_mask1 & (1u << fragmentinput_fragment.sample_index1)); - float color2 = (fragmentinput_fragment.front_facing1 ? 1.0 : 0.0); - const FragmentOutput fragmentoutput1 = { fragmentinput_fragment.in2.varying, mask, color2 }; - return fragmentoutput1; + VertexOutput in1 = { fragmentinput_fragment.position, fragmentinput_fragment.varying }; + bool front_facing = fragmentinput_fragment.front_facing1; + uint sample_index = fragmentinput_fragment.sample_index1; + uint sample_mask = fragmentinput_fragment.sample_mask1; + uint mask = (sample_mask & (1u << sample_index)); + float color1 = (front_facing ? 1.0 : 0.0); + const FragmentOutput fragmentoutput = { in1.varying, mask, color1 }; + return fragmentoutput; } [numthreads(1, 1, 1)] -void compute(ComputeInput_compute computeinput_compute) +void compute(uint3 global_id : SV_DispatchThreadID, uint3 local_id : SV_GroupThreadID, uint local_index : SV_GroupIndex, uint3 wg_id : SV_GroupID, uint3 num_wgs : SV_GroupID) { - output[0] = ((((computeinput_compute.global_id1.x + computeinput_compute.local_id1.x) + computeinput_compute.local_index1) + computeinput_compute.wg_id1.x) + uint3(_NagaConstants.base_vertex, _NagaConstants.base_instance, _NagaConstants.other).x); + output[0] = ((((global_id.x + local_id.x) + local_index) + wg_id.x) + uint3(_NagaConstants.base_vertex, _NagaConstants.base_instance, _NagaConstants.other).x); return; } diff --git a/tests/out/hlsl/interpolate.hlsl b/tests/out/hlsl/interpolate.hlsl index 555727e2c..f4c56957c 100644 --- a/tests/out/hlsl/interpolate.hlsl +++ b/tests/out/hlsl/interpolate.hlsl @@ -10,11 +10,29 @@ struct FragmentInput { linear sample float perspective_sample : LOC6; }; -struct FragmentInput_main { - FragmentInput val1; +struct VertexOutput_main { + uint flat : LOC0; + float linear1 : LOC1; + float2 linear_centroid : LOC2; + float3 linear_sample : LOC3; + float4 perspective : LOC4; + float perspective_centroid : LOC5; + float perspective_sample : LOC6; + float4 position : SV_Position; }; -FragmentInput main() +struct FragmentInput_main { + uint flat : LOC0; + float linear2 : LOC1; + float2 linear_centroid : LOC2; + float3 linear_sample : LOC3; + float4 perspective : LOC4; + float perspective_centroid : LOC5; + float perspective_sample : LOC6; + float4 position : SV_Position; +}; + +VertexOutput_main main() { FragmentInput out1 = (FragmentInput)0; @@ -27,11 +45,13 @@ FragmentInput main() out1.perspective_centroid = 2197.0; out1.perspective_sample = 2744.0; FragmentInput _expr30 = out1; - const FragmentInput fragmentinput1 = _expr30; + const FragmentInput fragmentinput = _expr30; + const VertexOutput_main fragmentinput1 = { fragmentinput.flat, fragmentinput.linear1, fragmentinput.linear_centroid, fragmentinput.linear_sample, fragmentinput.perspective, fragmentinput.perspective_centroid, fragmentinput.perspective_sample, fragmentinput.position }; return fragmentinput1; } void main1(FragmentInput_main fragmentinput_main) { + FragmentInput val = { fragmentinput_main.position, fragmentinput_main.flat, fragmentinput_main.linear2, fragmentinput_main.linear_centroid, fragmentinput_main.linear_sample, fragmentinput_main.perspective, fragmentinput_main.perspective_centroid, fragmentinput_main.perspective_sample }; return; } diff --git a/tests/out/hlsl/quad-vert.hlsl b/tests/out/hlsl/quad-vert.hlsl index d190a05e5..a5cce3fcd 100644 --- a/tests/out/hlsl/quad-vert.hlsl +++ b/tests/out/hlsl/quad-vert.hlsl @@ -1,17 +1,17 @@ struct gl_PerVertex { float4 gl_Position : SV_Position; + float gl_PointSize : PSIZE; float gl_ClipDistance[1] : SV_ClipDistance; float gl_CullDistance[1] : SV_CullDistance; - float gl_PointSize : PSIZE; }; struct type10 { linear float2 member : LOC0; float4 gl_Position : SV_Position; + float gl_PointSize : PSIZE; float gl_ClipDistance[1] : SV_ClipDistance; float gl_CullDistance[1] : SV_CullDistance; - float gl_PointSize : PSIZE; }; static float2 v_uv = (float2)0; @@ -19,9 +19,12 @@ static float2 a_uv1 = (float2)0; static gl_PerVertex perVertexStruct = { float4(0.0, 0.0, 0.0, 1.0), 1.0, { 0.0 }, { 0.0 } }; static float2 a_pos1 = (float2)0; -struct VertexInput_main { - float2 a_pos2 : LOC0; - float2 a_uv2 : LOC1; +struct VertexOutput_main { + float2 member : LOC0; + float4 gl_Position : SV_Position; + float gl_ClipDistance : SV_ClipDistance; + float gl_CullDistance : SV_CullDistance; + float gl_PointSize : PSIZE; }; void main1() @@ -33,16 +36,17 @@ void main1() return; } -type10 main(VertexInput_main vertexinput_main) +VertexOutput_main main(float2 a_uv : LOC1, float2 a_pos : LOC0) { - a_uv1 = vertexinput_main.a_uv2; - a_pos1 = vertexinput_main.a_pos2; + a_uv1 = a_uv; + a_pos1 = a_pos; main1(); float2 _expr10 = v_uv; float4 _expr11 = perVertexStruct.gl_Position; float _expr12 = perVertexStruct.gl_PointSize; float _expr13[1] = perVertexStruct.gl_ClipDistance; float _expr14[1] = perVertexStruct.gl_CullDistance; - const type10 type10_ = { _expr10, _expr11, _expr13, _expr14, _expr12 }; - return type10_; + const type10 type10_ = { _expr10, _expr11, _expr12, _expr13, _expr14 }; + const VertexOutput_main type10_1 = { type10_.member, type10_.gl_Position, type10_.gl_ClipDistance, type10_.gl_CullDistance, type10_.gl_PointSize }; + return type10_1; } diff --git a/tests/out/hlsl/quad.hlsl b/tests/out/hlsl/quad.hlsl index 90cd39274..2aba7768e 100644 --- a/tests/out/hlsl/quad.hlsl +++ b/tests/out/hlsl/quad.hlsl @@ -8,24 +8,26 @@ struct VertexOutput { Texture2D u_texture : register(t0); SamplerState u_sampler : register(s1); -struct VertexInput_main { - float2 pos1 : LOC0; - float2 uv2 : LOC1; +struct VertexOutput_main { + float2 uv2 : LOC0; + float4 position : SV_Position; }; struct FragmentInput_main { float2 uv3 : LOC0; }; -VertexOutput main(VertexInput_main vertexinput_main) +VertexOutput_main main(float2 pos : LOC0, float2 uv : LOC1) { - const VertexOutput vertexoutput1 = { vertexinput_main.uv2, float4((c_scale * vertexinput_main.pos1), 0.0, 1.0) }; + const VertexOutput vertexoutput = { uv, float4((c_scale * pos), 0.0, 1.0) }; + const VertexOutput_main vertexoutput1 = { vertexoutput.uv, vertexoutput.position }; return vertexoutput1; } float4 main1(FragmentInput_main fragmentinput_main) : SV_Target0 { - float4 color = u_texture.Sample(u_sampler, fragmentinput_main.uv3); + float2 uv1 = fragmentinput_main.uv3; + float4 color = u_texture.Sample(u_sampler, uv1); if ((color.w == 0.0)) { discard; } diff --git a/tests/out/hlsl/shadow.hlsl b/tests/out/hlsl/shadow.hlsl index 742c41cbd..85cdbf88f 100644 --- a/tests/out/hlsl/shadow.hlsl +++ b/tests/out/hlsl/shadow.hlsl @@ -34,10 +34,12 @@ float fetch_shadow(uint light_id, float4 homogeneous_coords) float4 fs_main(FragmentInput_fs_main fragmentinput_fs_main) : SV_Target0 { + float3 raw_normal = fragmentinput_fs_main.raw_normal1; + float4 position = fragmentinput_fs_main.position1; float3 color = float3(0.05, 0.05, 0.05); uint i = 0u; - float3 normal = normalize(fragmentinput_fs_main.raw_normal1); + float3 normal = normalize(raw_normal); bool loop_init = true; while(true) { if (!loop_init) { @@ -53,8 +55,8 @@ float4 fs_main(FragmentInput_fs_main fragmentinput_fs_main) : SV_Target0 uint _expr19 = i; Light light = {float4x4(asfloat(s_lights.Load4(_expr19*96+0+0+0)), asfloat(s_lights.Load4(_expr19*96+0+0+16)), asfloat(s_lights.Load4(_expr19*96+0+0+32)), asfloat(s_lights.Load4(_expr19*96+0+0+48))), asfloat(s_lights.Load4(_expr19*96+0+64)), asfloat(s_lights.Load4(_expr19*96+0+80))}; uint _expr22 = i; - const float _e25 = fetch_shadow(_expr22, mul(fragmentinput_fs_main.position1, light.proj)); - float3 light_dir = normalize((light.pos.xyz - fragmentinput_fs_main.position1.xyz)); + const float _e25 = fetch_shadow(_expr22, mul(position, light.proj)); + float3 light_dir = normalize((light.pos.xyz - position.xyz)); float diffuse = max(0.0, dot(normal, light_dir)); float3 _expr34 = color; color = (_expr34 + ((_e25 * diffuse) * light.color.xyz)); diff --git a/tests/out/hlsl/skybox.hlsl b/tests/out/hlsl/skybox.hlsl index 36ec009f5..dd58f0240 100644 --- a/tests/out/hlsl/skybox.hlsl +++ b/tests/out/hlsl/skybox.hlsl @@ -19,21 +19,23 @@ cbuffer r_data : register(b0) { Data r_data; } TextureCube r_texture : register(t0); SamplerState r_sampler : register(s0, space1); -struct VertexInput_vs_main { - uint vertex_index1 : SV_VertexID; +struct VertexOutput_vs_main { + float3 uv : LOC0; + float4 position : SV_Position; }; struct FragmentInput_fs_main { - VertexOutput in2; + float3 uv : LOC0; + float4 position : SV_Position; }; -VertexOutput vs_main(VertexInput_vs_main vertexinput_vs_main) +VertexOutput_vs_main vs_main(uint vertex_index : SV_VertexID) { int tmp1_ = (int)0; int tmp2_ = (int)0; - tmp1_ = (int((_NagaConstants.base_vertex + vertexinput_vs_main.vertex_index1)) / 2); - tmp2_ = (int((_NagaConstants.base_vertex + vertexinput_vs_main.vertex_index1)) & 1); + tmp1_ = (int((_NagaConstants.base_vertex + vertex_index)) / 2); + tmp2_ = (int((_NagaConstants.base_vertex + vertex_index)) & 1); int _expr10 = tmp1_; int _expr16 = tmp2_; float4 pos = float4(((float(_expr10) * 4.0) - 1.0), ((float(_expr16) * 4.0) - 1.0), 0.0, 1.0); @@ -43,12 +45,14 @@ VertexOutput vs_main(VertexInput_vs_main vertexinput_vs_main) float3x3 inv_model_view = transpose(float3x3(_expr27.xyz, _expr31.xyz, _expr35.xyz)); float4x4 _expr40 = r_data.proj_inv; float4 unprojected = mul(pos, _expr40); - const VertexOutput vertexoutput1 = { pos, mul(unprojected.xyz, inv_model_view) }; + const VertexOutput vertexoutput = { pos, mul(unprojected.xyz, inv_model_view) }; + const VertexOutput_vs_main vertexoutput1 = { vertexoutput.uv, vertexoutput.position }; return vertexoutput1; } float4 fs_main(FragmentInput_fs_main fragmentinput_fs_main) : SV_Target0 { - float4 _expr5 = r_texture.Sample(r_sampler, fragmentinput_fs_main.in2.uv); + VertexOutput in1 = { fragmentinput_fs_main.position, fragmentinput_fs_main.uv }; + float4 _expr5 = r_texture.Sample(r_sampler, in1.uv); return _expr5; } diff --git a/tests/out/hlsl/standard.hlsl b/tests/out/hlsl/standard.hlsl index 7f0bed219..e70e87f57 100644 --- a/tests/out/hlsl/standard.hlsl +++ b/tests/out/hlsl/standard.hlsl @@ -5,8 +5,9 @@ struct FragmentInput_derivatives { float4 derivatives(FragmentInput_derivatives fragmentinput_derivatives) : SV_Target0 { - float4 x = ddx(fragmentinput_derivatives.foo1); - float4 y = ddy(fragmentinput_derivatives.foo1); - float4 z = fwidth(fragmentinput_derivatives.foo1); + float4 foo = fragmentinput_derivatives.foo1; + float4 x = ddx(foo); + float4 y = ddy(foo); + float4 z = fwidth(foo); return ((x + y) * z); }