librashader_reflect/reflect/cross/
hlsl.rs1use crate::back::hlsl::{CrossHlslContext, HlslBufferAssignment, HlslBufferAssignments};
2use crate::back::targets::HLSL;
3use crate::back::{CompileShader, ShaderCompilerOutput};
4use crate::error::ShaderCompileError;
5use crate::reflect::cross::{CompiledProgram, CrossReflect};
6use spirv::Decoration;
7
8use spirv_cross2::compile::hlsl::HlslShaderModel;
9use spirv_cross2::compile::CompilableTarget;
10use spirv_cross2::reflect::{DecorationValue, ResourceType};
11use spirv_cross2::{targets, SpirvCrossError};
12
13pub(crate) type HlslReflect = CrossReflect<targets::Hlsl>;
14
15impl CompileShader<HLSL> for CrossReflect<targets::Hlsl> {
16 type Options = Option<HlslShaderModel>;
17 type Context = CrossHlslContext;
18
19 fn compile(
20 mut self,
21 options: Self::Options,
22 ) -> Result<ShaderCompilerOutput<String, CrossHlslContext>, ShaderCompileError> {
23 let sm = options.unwrap_or(HlslShaderModel::ShaderModel5_0);
24
25 let mut options = targets::Hlsl::options();
26 options.shader_model = sm;
27
28 let vertex_resources = self.vertex.shader_resources()?;
31 let fragment_resources = self.fragment.shader_resources()?;
32
33 let mut vertex_buffer_assignment = HlslBufferAssignments::default();
34 let mut fragment_buffer_assignment = HlslBufferAssignments::default();
35
36 let mut vertex_ubo = vertex_resources.resources_for_type(ResourceType::UniformBuffer)?;
37 if vertex_ubo.len() > 1 {
38 return Err(ShaderCompileError::SpirvCrossCompileError(
39 SpirvCrossError::InvalidArgument(String::from(
40 "Cannot have more than one uniform buffer",
41 )),
42 ));
43 }
44
45 if let Some(buf) = vertex_ubo.next() {
46 vertex_buffer_assignment.ubo = Some(HlslBufferAssignment {
47 name: buf.name.to_string(),
48 id: buf.id.id(),
49 })
50 }
51
52 let mut vertex_pcb = vertex_resources.resources_for_type(ResourceType::PushConstant)?;
53 if vertex_pcb.len() > 1 {
54 return Err(ShaderCompileError::SpirvCrossCompileError(
55 SpirvCrossError::InvalidArgument(String::from(
56 "Cannot have more than one push constant buffer",
57 )),
58 ));
59 }
60 if let Some(buf) = vertex_pcb.next() {
61 vertex_buffer_assignment.push = Some(HlslBufferAssignment {
62 name: buf.name.to_string(),
63 id: buf.id.id(),
64 })
65 }
66
67 let mut fragment_ubo =
68 fragment_resources.resources_for_type(ResourceType::UniformBuffer)?;
69 if fragment_ubo.len() > 1 {
70 return Err(ShaderCompileError::SpirvCrossCompileError(
71 SpirvCrossError::InvalidArgument(String::from(
72 "Cannot have more than one uniform buffer",
73 )),
74 ));
75 }
76
77 if let Some(buf) = fragment_ubo.next() {
78 fragment_buffer_assignment.ubo = Some(HlslBufferAssignment {
79 name: buf.name.to_string(),
80 id: buf.id.id(),
81 })
82 }
83
84 let mut fragment_pcb = fragment_resources.resources_for_type(ResourceType::PushConstant)?;
85 if fragment_pcb.len() > 1 {
86 return Err(ShaderCompileError::SpirvCrossCompileError(
87 SpirvCrossError::InvalidArgument(String::from(
88 "Cannot have more than one push constant buffer",
89 )),
90 ));
91 }
92
93 if let Some(buf) = fragment_pcb.next() {
94 fragment_buffer_assignment.push = Some(HlslBufferAssignment {
95 name: buf.name.to_string(),
96 id: buf.id.id(),
97 })
98 }
99
100 if sm == HlslShaderModel::ShaderModel3_0 {
101 for res in fragment_resources.resources_for_type(ResourceType::SampledImage)? {
102 let Some(DecorationValue::Literal(binding)) =
103 self.fragment.decoration(res.id, Decoration::Binding)?
104 else {
105 continue;
106 };
107 self.fragment
108 .set_name(res.id, format!("LIBRA_SAMPLER2D_{binding}"))?;
109 }
112 }
113
114 let vertex_compiled = self.vertex.compile(&options)?;
115 let fragment_compiled = self.fragment.compile(&options)?;
116
117 Ok(ShaderCompilerOutput {
118 vertex: vertex_compiled.to_string(),
119 fragment: fragment_compiled.to_string(),
120 context: CrossHlslContext {
121 artifact: CompiledProgram {
122 vertex: vertex_compiled,
123 fragment: fragment_compiled,
124 },
125
126 vertex_buffers: vertex_buffer_assignment,
127 fragment_buffers: fragment_buffer_assignment,
128 },
129 })
130 }
131
132 fn compile_boxed(
133 self: Box<Self>,
134 options: Self::Options,
135 ) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> {
136 <CrossReflect<targets::Hlsl> as CompileShader<HLSL>>::compile(*self, options)
137 }
138}