1#![allow(dead_code)] #[cfg(feature = "dot-out")]
7pub mod dot;
8#[cfg(feature = "glsl-out")]
9pub mod glsl;
10#[cfg(feature = "hlsl-out")]
11pub mod hlsl;
12#[cfg(feature = "msl-out")]
13pub mod msl;
14#[cfg(feature = "spv-out")]
15pub mod spv;
16#[cfg(feature = "wgsl-out")]
17pub mod wgsl;
18
19const COMPONENTS: &[char] = &['x', 'y', 'z', 'w'];
20const INDENT: &str = " ";
21const BAKE_PREFIX: &str = "_e";
22
23type NeedBakeExpressions = crate::FastHashSet<crate::Handle<crate::Expression>>;
24
25#[derive(Clone, Copy)]
26struct Level(usize);
27
28impl Level {
29 const fn next(&self) -> Self {
30 Level(self.0 + 1)
31 }
32}
33
34impl std::fmt::Display for Level {
35 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
36 (0..self.0).try_for_each(|_| formatter.write_str(INDENT))
37 }
38}
39
40enum FunctionType {
44 Function(crate::Handle<crate::Function>),
46 EntryPoint(crate::proc::EntryPointIndex),
48}
49
50impl FunctionType {
51 fn is_compute_entry_point(&self, module: &crate::Module) -> bool {
52 match *self {
53 FunctionType::EntryPoint(index) => {
54 module.entry_points[index as usize].stage == crate::ShaderStage::Compute
55 }
56 FunctionType::Function(_) => false,
57 }
58 }
59}
60
61struct FunctionCtx<'a> {
63 ty: FunctionType,
65 info: &'a crate::valid::FunctionInfo,
67 expressions: &'a crate::Arena<crate::Expression>,
69 named_expressions: &'a crate::NamedExpressions,
71}
72
73impl FunctionCtx<'_> {
74 fn resolve_type<'a>(
75 &'a self,
76 handle: crate::Handle<crate::Expression>,
77 types: &'a crate::UniqueArena<crate::Type>,
78 ) -> &'a crate::TypeInner {
79 self.info[handle].ty.inner_with(types)
80 }
81
82 const fn name_key(&self, local: crate::Handle<crate::LocalVariable>) -> crate::proc::NameKey {
84 match self.ty {
85 FunctionType::Function(handle) => crate::proc::NameKey::FunctionLocal(handle, local),
86 FunctionType::EntryPoint(idx) => crate::proc::NameKey::EntryPointLocal(idx, local),
87 }
88 }
89
90 const fn argument_key(&self, arg: u32) -> crate::proc::NameKey {
95 match self.ty {
96 FunctionType::Function(handle) => crate::proc::NameKey::FunctionArgument(handle, arg),
97 FunctionType::EntryPoint(ep_index) => {
98 crate::proc::NameKey::EntryPointArgument(ep_index, arg)
99 }
100 }
101 }
102
103 fn is_fixed_function_input(
105 &self,
106 mut expression: crate::Handle<crate::Expression>,
107 module: &crate::Module,
108 ) -> Option<crate::BuiltIn> {
109 let ep_function = match self.ty {
110 FunctionType::Function(_) => return None,
111 FunctionType::EntryPoint(ep_index) => &module.entry_points[ep_index as usize].function,
112 };
113 let mut built_in = None;
114 loop {
115 match self.expressions[expression] {
116 crate::Expression::FunctionArgument(arg_index) => {
117 return match ep_function.arguments[arg_index as usize].binding {
118 Some(crate::Binding::BuiltIn(bi)) => Some(bi),
119 _ => built_in,
120 };
121 }
122 crate::Expression::AccessIndex { base, index } => {
123 match *self.info[base].ty.inner_with(&module.types) {
124 crate::TypeInner::Struct { ref members, .. } => {
125 if let Some(crate::Binding::BuiltIn(bi)) =
126 members[index as usize].binding
127 {
128 built_in = Some(bi);
129 }
130 }
131 _ => return None,
132 }
133 expression = base;
134 }
135 _ => return None,
136 }
137 }
138 }
139}
140
141impl crate::Expression {
142 const fn bake_ref_count(&self) -> usize {
151 match *self {
152 crate::Expression::Access { .. } | crate::Expression::AccessIndex { .. } => usize::MAX,
154 crate::Expression::ImageSample { .. } | crate::Expression::ImageLoad { .. } => 1,
156 crate::Expression::Derivative { .. } => 1,
158 crate::Expression::Load { .. } => 1,
162 _ => 2,
164 }
165 }
166}
167
168const fn binary_operation_str(op: crate::BinaryOperator) -> &'static str {
172 use crate::BinaryOperator as Bo;
173 match op {
174 Bo::Add => "+",
175 Bo::Subtract => "-",
176 Bo::Multiply => "*",
177 Bo::Divide => "/",
178 Bo::Modulo => "%",
179 Bo::Equal => "==",
180 Bo::NotEqual => "!=",
181 Bo::Less => "<",
182 Bo::LessEqual => "<=",
183 Bo::Greater => ">",
184 Bo::GreaterEqual => ">=",
185 Bo::And => "&",
186 Bo::ExclusiveOr => "^",
187 Bo::InclusiveOr => "|",
188 Bo::LogicalAnd => "&&",
189 Bo::LogicalOr => "||",
190 Bo::ShiftLeft => "<<",
191 Bo::ShiftRight => ">>",
192 }
193}
194
195const fn vector_size_str(size: crate::VectorSize) -> &'static str {
199 match size {
200 crate::VectorSize::Bi => "2",
201 crate::VectorSize::Tri => "3",
202 crate::VectorSize::Quad => "4",
203 }
204}
205
206impl crate::TypeInner {
207 const fn is_handle(&self) -> bool {
208 match *self {
209 crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } => true,
210 _ => false,
211 }
212 }
213}
214
215impl crate::Statement {
216 pub const fn is_terminator(&self) -> bool {
220 match *self {
221 crate::Statement::Break
222 | crate::Statement::Continue
223 | crate::Statement::Return { .. }
224 | crate::Statement::Kill => true,
225 _ => false,
226 }
227 }
228}
229
230bitflags::bitflags! {
231 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
240 pub struct RayFlag: u32 {
241 const OPAQUE = 0x01;
242 const NO_OPAQUE = 0x02;
243 const TERMINATE_ON_FIRST_HIT = 0x04;
244 const SKIP_CLOSEST_HIT_SHADER = 0x08;
245 const CULL_BACK_FACING = 0x10;
246 const CULL_FRONT_FACING = 0x20;
247 const CULL_OPAQUE = 0x40;
248 const CULL_NO_OPAQUE = 0x80;
249 const SKIP_TRIANGLES = 0x100;
250 const SKIP_AABBS = 0x200;
251 }
252}
253
254#[repr(u32)]
255enum RayIntersectionType {
256 Triangle = 1,
257 BoundingBox = 4,
258}