1#![allow(dead_code)] use crate::proc::ExpressionKindTracker;
7
8#[cfg(dot_out)]
9pub mod dot;
10#[cfg(glsl_out)]
11pub mod glsl;
12#[cfg(hlsl_out)]
13pub mod hlsl;
14#[cfg(msl_out)]
15pub mod msl;
16#[cfg(spv_out)]
17pub mod spv;
18#[cfg(wgsl_out)]
19pub mod wgsl;
20
21#[cfg(any(hlsl_out, msl_out, spv_out, glsl_out))]
22pub mod pipeline_constants;
23
24#[cfg(any(hlsl_out, glsl_out))]
25mod continue_forward;
26
27pub const COMPONENTS: &[char] = &['x', 'y', 'z', 'w'];
29pub const INDENT: &str = " ";
31
32pub type NeedBakeExpressions = crate::FastHashSet<crate::Handle<crate::Expression>>;
34
35struct Baked(crate::Handle<crate::Expression>);
44
45impl std::fmt::Display for Baked {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 self.0.write_prefixed(f, "_e")
48 }
49}
50
51pub type PipelineConstants = std::collections::HashMap<String, f64>;
59
60#[derive(Clone, Copy)]
62pub struct Level(pub usize);
63
64impl Level {
65 const fn next(&self) -> Self {
66 Level(self.0 + 1)
67 }
68}
69
70impl std::fmt::Display for Level {
71 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
72 (0..self.0).try_for_each(|_| formatter.write_str(INDENT))
73 }
74}
75
76pub enum FunctionType {
92 Function(crate::Handle<crate::Function>),
94 EntryPoint(crate::proc::EntryPointIndex),
99}
100
101impl FunctionType {
102 pub fn is_compute_entry_point(&self, module: &crate::Module) -> bool {
104 match *self {
105 FunctionType::EntryPoint(index) => {
106 module.entry_points[index as usize].stage == crate::ShaderStage::Compute
107 }
108 FunctionType::Function(_) => false,
109 }
110 }
111}
112
113pub struct FunctionCtx<'a> {
115 pub ty: FunctionType,
117 pub info: &'a crate::valid::FunctionInfo,
119 pub expressions: &'a crate::Arena<crate::Expression>,
121 pub named_expressions: &'a crate::NamedExpressions,
123 pub expr_kind_tracker: ExpressionKindTracker,
125}
126
127impl FunctionCtx<'_> {
128 pub fn resolve_type<'a>(
130 &'a self,
131 handle: crate::Handle<crate::Expression>,
132 types: &'a crate::UniqueArena<crate::Type>,
133 ) -> &'a crate::TypeInner {
134 self.info[handle].ty.inner_with(types)
135 }
136
137 pub const fn name_key(
139 &self,
140 local: crate::Handle<crate::LocalVariable>,
141 ) -> crate::proc::NameKey {
142 match self.ty {
143 FunctionType::Function(handle) => crate::proc::NameKey::FunctionLocal(handle, local),
144 FunctionType::EntryPoint(idx) => crate::proc::NameKey::EntryPointLocal(idx, local),
145 }
146 }
147
148 pub const fn argument_key(&self, arg: u32) -> crate::proc::NameKey {
153 match self.ty {
154 FunctionType::Function(handle) => crate::proc::NameKey::FunctionArgument(handle, arg),
155 FunctionType::EntryPoint(ep_index) => {
156 crate::proc::NameKey::EntryPointArgument(ep_index, arg)
157 }
158 }
159 }
160
161 pub fn is_fixed_function_input(
163 &self,
164 mut expression: crate::Handle<crate::Expression>,
165 module: &crate::Module,
166 ) -> Option<crate::BuiltIn> {
167 let ep_function = match self.ty {
168 FunctionType::Function(_) => return None,
169 FunctionType::EntryPoint(ep_index) => &module.entry_points[ep_index as usize].function,
170 };
171 let mut built_in = None;
172 loop {
173 match self.expressions[expression] {
174 crate::Expression::FunctionArgument(arg_index) => {
175 return match ep_function.arguments[arg_index as usize].binding {
176 Some(crate::Binding::BuiltIn(bi)) => Some(bi),
177 _ => built_in,
178 };
179 }
180 crate::Expression::AccessIndex { base, index } => {
181 match *self.resolve_type(base, &module.types) {
182 crate::TypeInner::Struct { ref members, .. } => {
183 if let Some(crate::Binding::BuiltIn(bi)) =
184 members[index as usize].binding
185 {
186 built_in = Some(bi);
187 }
188 }
189 _ => return None,
190 }
191 expression = base;
192 }
193 _ => return None,
194 }
195 }
196 }
197}
198
199impl crate::Expression {
200 pub const fn bake_ref_count(&self) -> usize {
209 match *self {
210 crate::Expression::Access { .. } | crate::Expression::AccessIndex { .. } => usize::MAX,
212 crate::Expression::ImageSample { .. } | crate::Expression::ImageLoad { .. } => 1,
214 crate::Expression::Derivative { .. } => 1,
216 crate::Expression::Load { .. } => 1,
220 _ => 2,
222 }
223 }
224}
225
226pub const fn binary_operation_str(op: crate::BinaryOperator) -> &'static str {
228 use crate::BinaryOperator as Bo;
229 match op {
230 Bo::Add => "+",
231 Bo::Subtract => "-",
232 Bo::Multiply => "*",
233 Bo::Divide => "/",
234 Bo::Modulo => "%",
235 Bo::Equal => "==",
236 Bo::NotEqual => "!=",
237 Bo::Less => "<",
238 Bo::LessEqual => "<=",
239 Bo::Greater => ">",
240 Bo::GreaterEqual => ">=",
241 Bo::And => "&",
242 Bo::ExclusiveOr => "^",
243 Bo::InclusiveOr => "|",
244 Bo::LogicalAnd => "&&",
245 Bo::LogicalOr => "||",
246 Bo::ShiftLeft => "<<",
247 Bo::ShiftRight => ">>",
248 }
249}
250
251const fn vector_size_str(size: crate::VectorSize) -> &'static str {
253 match size {
254 crate::VectorSize::Bi => "2",
255 crate::VectorSize::Tri => "3",
256 crate::VectorSize::Quad => "4",
257 }
258}
259
260impl crate::TypeInner {
261 pub const fn is_handle(&self) -> bool {
263 match *self {
264 crate::TypeInner::Image { .. }
265 | crate::TypeInner::Sampler { .. }
266 | crate::TypeInner::AccelerationStructure { .. } => true,
267 _ => false,
268 }
269 }
270}
271
272impl crate::Statement {
273 pub const fn is_terminator(&self) -> bool {
277 match *self {
278 crate::Statement::Break
279 | crate::Statement::Continue
280 | crate::Statement::Return { .. }
281 | crate::Statement::Kill => true,
282 _ => false,
283 }
284 }
285}
286
287bitflags::bitflags! {
288 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
298 pub struct RayFlag: u32 {
299 const OPAQUE = 0x01;
300 const NO_OPAQUE = 0x02;
301 const TERMINATE_ON_FIRST_HIT = 0x04;
302 const SKIP_CLOSEST_HIT_SHADER = 0x08;
303 const CULL_BACK_FACING = 0x10;
304 const CULL_FRONT_FACING = 0x20;
305 const CULL_OPAQUE = 0x40;
306 const CULL_NO_OPAQUE = 0x80;
307 const SKIP_TRIANGLES = 0x100;
308 const SKIP_AABBS = 0x200;
309 }
310}
311
312#[repr(u32)]
314pub enum RayIntersectionType {
315 Triangle = 1,
316 BoundingBox = 4,
317}