diff --git a/src/back/hlsl/mod.rs b/src/back/hlsl/mod.rs index 72ec44e3a4..11e812a156 100644 --- a/src/back/hlsl/mod.rs +++ b/src/back/hlsl/mod.rs @@ -92,14 +92,18 @@ pub struct Options { pub binding_map: BindingMap, /// Don't panic on missing bindings, instead generate any HLSL. pub fake_missing_bindings: bool, + /// Add special constants to `SV_VertexIndex` and `SV_InstanceIndex`, + /// to make them work like in Vulkan/Metal, with help of the host. + pub special_constants_binding: Option, } impl Default for Options { fn default() -> Self { Options { - shader_model: ShaderModel::V5_0, + shader_model: ShaderModel::V5_1, binding_map: BindingMap::default(), fake_missing_bindings: true, + special_constants_binding: None, } } } diff --git a/src/back/hlsl/writer.rs b/src/back/hlsl/writer.rs index bbecb3edc0..6942971007 100644 --- a/src/back/hlsl/writer.rs +++ b/src/back/hlsl/writer.rs @@ -11,6 +11,10 @@ use crate::{ use std::fmt; const LOCATION_SEMANTIC: &str = "LOC"; +const SPECIAL_CBUF_TYPE: &str = "NagaConstants"; +const SPECIAL_CBUF_VAR: &str = "_NagaConstants"; +const SPECIAL_BASE_VERTEX: &str = "base_vertex"; +const SPECIAL_BASE_INSTANCE: &str = "base_instance"; /// Structure contains information required for generating /// wrapped structure of all entry points arguments @@ -65,6 +69,23 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { ) -> Result { self.reset(module); + // Write special constants, if needed + if let Some(ref bt) = self.options.special_constants_binding { + writeln!(self.out, "struct {} {{", SPECIAL_CBUF_TYPE)?; + writeln!(self.out, "{}int {};", back::INDENT, SPECIAL_BASE_VERTEX)?; + writeln!(self.out, "{}int {};", back::INDENT, SPECIAL_BASE_INSTANCE)?; + writeln!(self.out, "}};")?; + write!( + self.out, + "ConstantBuffer<{}> {}: register(b{}", + SPECIAL_CBUF_TYPE, SPECIAL_CBUF_VAR, bt.register + )?; + if bt.space != 0 { + write!(self.out, ", space{}", bt.space)?; + } + writeln!(self.out, ");")?; + } + // Write all constants // For example, input wgsl shader: // ```wgsl @@ -410,7 +431,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { // this was already resolved earlier when we started evaluating an entry point. let bt = self.options.resolve_resource_binding(binding).unwrap(); write!(self.out, " : register({}{}", register_ty, bt.register)?; - if self.options.shader_model > super::ShaderModel::V5_0 { + if bt.space != 0 { write!(self.out, ", space{}", bt.space)?; } write!(self.out, ")")?; @@ -1105,8 +1126,30 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { ) -> BackendResult { use crate::Expression; + // Handle the special semantics for base vertex/instance + let ff_input = if self.options.special_constants_binding.is_some() { + func_ctx.is_fixed_function_input(expr, module) + } else { + None + }; + let closing_bracket = match ff_input { + Some(crate::BuiltIn::VertexIndex) => { + write!(self.out, "({}.{} + ", SPECIAL_CBUF_VAR, SPECIAL_BASE_VERTEX)?; + ")" + } + Some(crate::BuiltIn::InstanceIndex) => { + write!( + self.out, + "({}.{} + ", + SPECIAL_CBUF_VAR, SPECIAL_BASE_INSTANCE + )?; + ")" + } + _ => "", + }; + if let Some(name) = self.named_expressions.get(&expr) { - write!(self.out, "{}", name)?; + write!(self.out, "{}{}", name, closing_bracket)?; return Ok(()); } @@ -1627,6 +1670,9 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { _ => return Err(Error::Unimplemented(format!("write_expr {:?}", expression))), } + if !closing_bracket.is_empty() { + write!(self.out, "{}", closing_bracket)?; + } Ok(()) } diff --git a/src/back/mod.rs b/src/back/mod.rs index 51243a4045..e753e7aa5c 100644 --- a/src/back/mod.rs +++ b/src/back/mod.rs @@ -66,6 +66,43 @@ impl<'a> FunctionCtx<'_> { } } } + + // Returns true if the given expression points to a fixed-function pipeline input. + fn is_fixed_function_input( + &self, + mut expression: crate::Handle, + module: &crate::Module, + ) -> Option { + let ep_function = match self.ty { + FunctionType::Function(_) => return None, + FunctionType::EntryPoint(ep_index) => &module.entry_points[ep_index as usize].function, + }; + let mut built_in = None; + loop { + match self.expressions[expression] { + crate::Expression::FunctionArgument(arg_index) => { + return match ep_function.arguments[arg_index as usize].binding { + Some(crate::Binding::BuiltIn(bi)) => Some(bi), + _ => built_in, + }; + } + crate::Expression::AccessIndex { base, index } => { + match *self.info[base].ty.inner_with(&module.types) { + crate::TypeInner::Struct { ref members, .. } => { + if let Some(crate::Binding::BuiltIn(bi)) = + members[index as usize].binding + { + built_in = Some(bi); + } + } + _ => return None, + } + expression = base; + } + _ => return None, + } + } + } } /// How should code generated by Naga do indexing bounds checks? diff --git a/tests/in/skybox.param.ron b/tests/in/skybox.param.ron index d21b3b8527..951981e726 100644 --- a/tests/in/skybox.param.ron +++ b/tests/in/skybox.param.ron @@ -53,5 +53,6 @@ (group: 0, binding: 2): (space: 1, register: 0), }, fake_missing_bindings: false, + special_constants_binding: Some((space: 0, register: 1)), ), ) diff --git a/tests/out/hlsl/access.hlsl.config b/tests/out/hlsl/access.hlsl.config index f684c661e0..0f887fb4cf 100644 --- a/tests/out/hlsl/access.hlsl.config +++ b/tests/out/hlsl/access.hlsl.config @@ -1,3 +1,3 @@ -vertex=(foo:vs_5_0 ) +vertex=(foo:vs_5_1 ) fragment=() compute=() diff --git a/tests/out/hlsl/boids.hlsl.config b/tests/out/hlsl/boids.hlsl.config index c0d04b8f2a..246c485cf7 100644 --- a/tests/out/hlsl/boids.hlsl.config +++ b/tests/out/hlsl/boids.hlsl.config @@ -1,3 +1,3 @@ vertex=() fragment=() -compute=(main:cs_5_0 ) +compute=(main:cs_5_1 ) diff --git a/tests/out/hlsl/collatz.hlsl.config b/tests/out/hlsl/collatz.hlsl.config index c0d04b8f2a..246c485cf7 100644 --- a/tests/out/hlsl/collatz.hlsl.config +++ b/tests/out/hlsl/collatz.hlsl.config @@ -1,3 +1,3 @@ vertex=() fragment=() -compute=(main:cs_5_0 ) +compute=(main:cs_5_1 ) diff --git a/tests/out/hlsl/control-flow.hlsl.config b/tests/out/hlsl/control-flow.hlsl.config index c0d04b8f2a..246c485cf7 100644 --- a/tests/out/hlsl/control-flow.hlsl.config +++ b/tests/out/hlsl/control-flow.hlsl.config @@ -1,3 +1,3 @@ vertex=() fragment=() -compute=(main:cs_5_0 ) +compute=(main:cs_5_1 ) diff --git a/tests/out/hlsl/empty.hlsl.config b/tests/out/hlsl/empty.hlsl.config index c0d04b8f2a..246c485cf7 100644 --- a/tests/out/hlsl/empty.hlsl.config +++ b/tests/out/hlsl/empty.hlsl.config @@ -1,3 +1,3 @@ vertex=() fragment=() -compute=(main:cs_5_0 ) +compute=(main:cs_5_1 ) diff --git a/tests/out/hlsl/globals.hlsl.config b/tests/out/hlsl/globals.hlsl.config index c0d04b8f2a..246c485cf7 100644 --- a/tests/out/hlsl/globals.hlsl.config +++ b/tests/out/hlsl/globals.hlsl.config @@ -1,3 +1,3 @@ vertex=() fragment=() -compute=(main:cs_5_0 ) +compute=(main:cs_5_1 ) diff --git a/tests/out/hlsl/image.hlsl b/tests/out/hlsl/image.hlsl index d722391523..4ade7db1a7 100644 --- a/tests/out/hlsl/image.hlsl +++ b/tests/out/hlsl/image.hlsl @@ -11,9 +11,9 @@ TextureCube image_cube : register(t3); TextureCubeArray image_cube_array : register(t4); Texture3D image_3d : register(t5); Texture2DMS image_aa : register(t6); -SamplerState sampler_reg : register(s0); -SamplerComparisonState sampler_cmp : register(s1); -Texture2D image_2d_depth : register(t2); +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; diff --git a/tests/out/hlsl/image.hlsl.config b/tests/out/hlsl/image.hlsl.config index c182886b79..c5d0760d93 100644 --- a/tests/out/hlsl/image.hlsl.config +++ b/tests/out/hlsl/image.hlsl.config @@ -1,3 +1,3 @@ -vertex=(queries:vs_5_0 ) -fragment=(sample1:ps_5_0 sample_comparison:ps_5_0 ) -compute=(main:cs_5_0 ) +vertex=(queries:vs_5_1 ) +fragment=(sample1:ps_5_1 sample_comparison:ps_5_1 ) +compute=(main:cs_5_1 ) diff --git a/tests/out/hlsl/interface.hlsl.config b/tests/out/hlsl/interface.hlsl.config index 4da683e011..cec1fc2b98 100644 --- a/tests/out/hlsl/interface.hlsl.config +++ b/tests/out/hlsl/interface.hlsl.config @@ -1,3 +1,3 @@ -vertex=(vertex:vs_5_0 ) -fragment=(fragment:ps_5_0 ) -compute=(compute:cs_5_0 ) +vertex=(vertex:vs_5_1 ) +fragment=(fragment:ps_5_1 ) +compute=(compute:cs_5_1 ) diff --git a/tests/out/hlsl/interpolate.hlsl.config b/tests/out/hlsl/interpolate.hlsl.config index 7a83c119f5..b0a8e4ba9c 100644 --- a/tests/out/hlsl/interpolate.hlsl.config +++ b/tests/out/hlsl/interpolate.hlsl.config @@ -1,3 +1,3 @@ -vertex=(main:vs_5_0 ) -fragment=(main1:ps_5_0 ) +vertex=(main:vs_5_1 ) +fragment=(main1:ps_5_1 ) compute=() diff --git a/tests/out/hlsl/operators.hlsl.config b/tests/out/hlsl/operators.hlsl.config index c0d04b8f2a..246c485cf7 100644 --- a/tests/out/hlsl/operators.hlsl.config +++ b/tests/out/hlsl/operators.hlsl.config @@ -1,3 +1,3 @@ vertex=() fragment=() -compute=(main:cs_5_0 ) +compute=(main:cs_5_1 ) diff --git a/tests/out/hlsl/quad-vert.hlsl.config b/tests/out/hlsl/quad-vert.hlsl.config index 9f33353d2f..f72fafd91f 100644 --- a/tests/out/hlsl/quad-vert.hlsl.config +++ b/tests/out/hlsl/quad-vert.hlsl.config @@ -1,3 +1,3 @@ -vertex=(main:vs_5_0 ) +vertex=(main:vs_5_1 ) fragment=() compute=() diff --git a/tests/out/hlsl/quad.hlsl.config b/tests/out/hlsl/quad.hlsl.config index 094d9191f1..24b516da9e 100644 --- a/tests/out/hlsl/quad.hlsl.config +++ b/tests/out/hlsl/quad.hlsl.config @@ -1,3 +1,3 @@ -vertex=(main:vs_5_0 ) -fragment=(main1:ps_5_0 fs_extra:ps_5_0 ) +vertex=(main:vs_5_1 ) +fragment=(main1:ps_5_1 fs_extra:ps_5_1 ) compute=() diff --git a/tests/out/hlsl/shadow.hlsl.config b/tests/out/hlsl/shadow.hlsl.config index ead2c79fa6..b9f047558a 100644 --- a/tests/out/hlsl/shadow.hlsl.config +++ b/tests/out/hlsl/shadow.hlsl.config @@ -1,3 +1,3 @@ vertex=() -fragment=(fs_main:ps_5_0 ) +fragment=(fs_main:ps_5_1 ) compute=() diff --git a/tests/out/hlsl/skybox.hlsl b/tests/out/hlsl/skybox.hlsl index 8eba4c4ec5..058b0cbb60 100644 --- a/tests/out/hlsl/skybox.hlsl +++ b/tests/out/hlsl/skybox.hlsl @@ -1,3 +1,8 @@ +struct NagaConstants { + int base_vertex; + int base_instance; +}; +ConstantBuffer _NagaConstants: register(b1); struct VertexOutput { float4 position : SV_Position; @@ -9,8 +14,8 @@ struct Data { float4x4 view; }; -cbuffer r_data : register(b0, space0) { Data r_data; } -TextureCube r_texture : register(t0, space0); +cbuffer r_data : register(b0) { Data r_data; } +TextureCube r_texture : register(t0); SamplerState r_sampler : register(s0, space1); struct VertexInput_vs_main { @@ -26,8 +31,8 @@ VertexOutput vs_main(VertexInput_vs_main vertexinput_vs_main) int tmp1_ = (int)0; int tmp2_ = (int)0; - tmp1_ = (int(vertexinput_vs_main.vertex_index1) / 2); - tmp2_ = (int(vertexinput_vs_main.vertex_index1) & 1); + tmp1_ = (int((_NagaConstants.base_vertex + vertexinput_vs_main.vertex_index1)) / 2); + tmp2_ = (int((_NagaConstants.base_vertex + vertexinput_vs_main.vertex_index1)) & 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); diff --git a/tests/out/hlsl/standard.hlsl.config b/tests/out/hlsl/standard.hlsl.config index 512971d7c5..a2606f3ab7 100644 --- a/tests/out/hlsl/standard.hlsl.config +++ b/tests/out/hlsl/standard.hlsl.config @@ -1,3 +1,3 @@ vertex=() -fragment=(derivatives:ps_5_0 ) +fragment=(derivatives:ps_5_1 ) compute=() diff --git a/tests/out/hlsl/texture-arg.hlsl.config b/tests/out/hlsl/texture-arg.hlsl.config index 18ddfc224d..98453a04ee 100644 --- a/tests/out/hlsl/texture-arg.hlsl.config +++ b/tests/out/hlsl/texture-arg.hlsl.config @@ -1,3 +1,3 @@ vertex=() -fragment=(main:ps_5_0 ) +fragment=(main:ps_5_1 ) compute=()