1mod atomic;
6pub mod behaviour;
7mod entry;
8mod mesh;
9pub mod structure;
10
11pub use entry::{EntryDecl, FunctionDecl};
12pub use mesh::MeshOutput;
13
14use naga::{
15 BinaryOperator, Block, Expression, Function, GlobalVariable, Handle, Literal, LocalVariable,
16 MathFunction, Module, Scalar, ScalarKind, Span, Statement, SwizzleComponent, Type, TypeInner,
17 UnaryOperator, VectorSize,
18};
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum Kind {
23 U,
25 I,
27 F,
29 B,
31}
32impl Kind {
33 pub fn scalar(self) -> Scalar {
35 match self {
36 Kind::U => Scalar::U32,
37 Kind::I => Scalar::I32,
38 Kind::F => Scalar::F32,
39 Kind::B => Scalar::BOOL,
40 }
41 }
42 pub fn kind(self) -> ScalarKind {
44 self.scalar().kind
45 }
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub enum Width {
52 One = 1,
54 Two = 2,
56 Three = 3,
58 Four = 4,
60}
61impl Width {
62 pub const ALL: [Width; 4] = [Width::One, Width::Two, Width::Three, Width::Four];
64
65 pub const fn new(lanes: u8) -> Option<Width> {
67 match lanes {
68 1 => Some(Width::One),
69 2 => Some(Width::Two),
70 3 => Some(Width::Three),
71 4 => Some(Width::Four),
72 _ => None,
73 }
74 }
75
76 pub fn of_count(lanes: usize) -> Option<Width> {
78 u8::try_from(lanes).ok().and_then(Width::new)
79 }
80
81 pub const fn of_vector(size: VectorSize) -> Width {
83 match size {
84 VectorSize::Bi => Width::Two,
85 VectorSize::Tri => Width::Three,
86 VectorSize::Quad => Width::Four,
87 }
88 }
89
90 pub const fn get(self) -> u8 {
92 self as u8
93 }
94
95 pub const fn count(self) -> usize {
97 self as usize
98 }
99
100 pub const fn vector_size(self) -> Option<VectorSize> {
102 match self {
103 Width::One => None,
104 Width::Two => Some(VectorSize::Bi),
105 Width::Three => Some(VectorSize::Tri),
106 Width::Four => Some(VectorSize::Quad),
107 }
108 }
109
110 pub fn lanes(self) -> std::ops::Range<u8> {
112 0..self.get()
113 }
114}
115impl From<Width> for u8 {
116 fn from(w: Width) -> u8 {
117 w.get()
118 }
119}
120impl From<Width> for u32 {
121 fn from(w: Width) -> u32 {
122 u32::from(w.get())
123 }
124}
125impl From<Width> for usize {
126 fn from(w: Width) -> usize {
127 w.count()
128 }
129}
130impl From<VectorSize> for Width {
131 fn from(size: VectorSize) -> Width {
132 Width::of_vector(size)
133 }
134}
135impl TryFrom<u8> for Width {
136 type Error = String;
137 fn try_from(lanes: u8) -> Result<Width, String> {
138 Width::new(lanes).ok_or_else(|| format!("a width of {lanes} lanes (a value has 1 to 4)"))
139 }
140}
141impl TryFrom<u32> for Width {
142 type Error = String;
143 fn try_from(lanes: u32) -> Result<Width, String> {
144 u8::try_from(lanes)
145 .ok()
146 .and_then(Width::new)
147 .ok_or_else(|| format!("a width of {lanes} lanes (a value has 1 to 4)"))
148 }
149}
150impl TryFrom<usize> for Width {
151 type Error = String;
152 fn try_from(lanes: usize) -> Result<Width, String> {
153 Width::of_count(lanes).ok_or_else(|| format!("a width of {lanes} lanes (a value has 1 to 4)"))
154 }
155}
156impl std::fmt::Display for Width {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 write!(f, "{}", self.get())
159 }
160}
161
162#[derive(Clone, Copy, Debug)]
164pub struct Val {
165 pub expr: Handle<Expression>,
167 pub kind: Kind,
169 pub width: Width,
171}
172
173pub(crate) fn align_up(offset: u32, align: u32) -> Result<u32, String> {
175 offset.checked_next_multiple_of(align).ok_or_else(|| {
176 format!("a layout offset of {offset} bytes aligned to {align} is over 4294967295 bytes")
177 })
178}
179
180pub(crate) fn fits(value: Option<u32>) -> Result<u32, String> {
182 value.ok_or_else(|| "a layout of over 4294967295 bytes".to_owned())
183}
184
185pub fn component(lane: u8) -> SwizzleComponent {
187 match lane {
188 0 => SwizzleComponent::X,
189 1 => SwizzleComponent::Y,
190 2 => SwizzleComponent::Z,
191 _ => SwizzleComponent::W,
192 }
193}
194
195#[derive(Debug)]
205pub struct Builder {
206 pub module: Module,
208 pub function: Function,
210 pub blocks: Vec<Block>,
212 pub workgroup_size: [u32; 3],
214 error: Option<String>,
218}
219impl Default for Builder {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224impl Builder {
225 pub fn new() -> Self {
227 Self {
228 module: Module::default(),
229 function: Function::default(),
230 blocks: vec![Block::new()],
231 workgroup_size: [0; 3],
232 error: None,
233 }
234 }
235
236 fn fail(&mut self, detail: impl Into<String>) {
238 self.error.get_or_insert_with(|| detail.into());
239 }
240
241 pub fn check(&mut self) -> Result<(), String> {
244 self.error.take().map_or(Ok(()), Err)
245 }
246
247 fn finishable(&mut self) -> Result<(), String> {
249 if self.blocks.len() != 1 {
250 return Err(format!(
251 "control flow left open: {} blocks open where the function's own is the one (a lifter bug)",
252 self.blocks.len()
253 ));
254 }
255 self.check()
256 .map_err(|fault| format!("a fault the lifter did not check before finishing: {fault}"))
257 }
258
259 pub fn ty(&mut self, inner: TypeInner) -> Handle<Type> {
261 self.module
262 .types
263 .insert(Type { name: None, inner }, Span::UNDEFINED)
264 }
265 pub fn ty_of(&mut self, kind: Kind, width: Width) -> Handle<Type> {
267 match width.vector_size() {
268 None => self.ty(TypeInner::Scalar(kind.scalar())),
269 Some(size) => self.ty(TypeInner::Vector {
270 size,
271 scalar: kind.scalar(),
272 }),
273 }
274 }
275
276 pub fn app(&mut self, e: Expression) -> Handle<Expression> {
279 let pre = e.needs_pre_emit();
280 let start = self.function.expressions.len();
281 let h = self.function.expressions.append(e, Span::UNDEFINED);
282 if !pre {
283 let range = self.function.expressions.range_from(start);
284 self.push(Statement::Emit(range));
285 }
286 h
287 }
288 pub fn atomic_quad(&mut self, scalar: naga::Scalar) -> Handle<Type> {
290 let atomic = self.ty(TypeInner::Atomic(scalar));
291 let members = (0..4u32)
292 .map(|k| naga::StructMember {
293 name: Some(format!("w{k}")),
294 ty: atomic,
295 binding: None,
296 offset: k.saturating_mul(4),
297 })
298 .collect();
299 self.ty(TypeInner::Struct { members, span: 16 })
300 }
301 pub fn result_expr(&mut self, e: Expression) -> Handle<Expression> {
303 self.function.expressions.append(e, Span::UNDEFINED)
304 }
305 pub fn when(&mut self, condition: Val, then: impl FnOnce(&mut Self)) {
307 self.blocks.push(Block::new());
308 then(self);
309 let accept = self.blocks.pop().expect("the block just pushed");
310 self.push(Statement::If {
311 condition: condition.expr,
312 accept,
313 reject: Block::new(),
314 });
315 }
316 pub fn begin_repeat(&mut self, count: u32) -> (Val, Handle<LocalVariable>) {
319 let ty = self.ty_of(Kind::U, Width::One);
320 let counter = self.local("i", ty);
321 let ptr = self.local_ptr(counter);
322 let zero = self.lit_u(0);
323 self.store(ptr, zero);
324 self.blocks.push(Block::new());
325 let i = self.load(ptr, Kind::U, Width::One);
326 let limit = self.lit_u(count);
327 let done = self.binary(BinaryOperator::GreaterEqual, i, limit);
328 self.when(done, |b| b.push(Statement::Break));
329 (i, counter)
330 }
331 pub fn end_repeat(&mut self, counter: Handle<LocalVariable>) {
333 let ptr = self.local_ptr(counter);
334 let again = self.load(ptr, Kind::U, Width::One);
335 let one = self.lit_u(1);
336 let next = self.binary(BinaryOperator::Add, again, one);
337 self.store(ptr, next);
338 let inner = self.blocks.pop().expect("the loop body opened by begin_repeat");
339 self.push(Statement::Loop {
340 body: inner,
341 continuing: Block::new(),
342 break_if: None,
343 });
344 }
345 pub fn push(&mut self, s: Statement) {
347 self.blocks
348 .last_mut()
349 .expect("a block is always open")
350 .push(s, Span::UNDEFINED);
351 }
352 pub fn local(&mut self, name: &str, ty: Handle<Type>) -> Handle<LocalVariable> {
354 self.function.local_variables.append(
355 LocalVariable {
356 name: Some(name.to_owned()),
357 ty,
358 init: None,
359 },
360 Span::UNDEFINED,
361 )
362 }
363 pub fn local_ptr(&mut self, l: Handle<LocalVariable>) -> Handle<Expression> {
365 self.app(Expression::LocalVariable(l))
366 }
367 pub fn global_ptr(&mut self, g: Handle<GlobalVariable>) -> Handle<Expression> {
369 self.app(Expression::GlobalVariable(g))
370 }
371 pub fn load(&mut self, ptr: Handle<Expression>, kind: Kind, width: Width) -> Val {
373 Val {
374 expr: self.app(Expression::Load { pointer: ptr }),
375 kind,
376 width,
377 }
378 }
379 pub fn store(&mut self, ptr: Handle<Expression>, v: Val) {
381 self.push(Statement::Store {
382 pointer: ptr,
383 value: v.expr,
384 });
385 }
386 pub fn global(&mut self, g: GlobalVariable) -> Handle<GlobalVariable> {
388 self.module.global_variables.append(g, Span::UNDEFINED)
389 }
390 pub fn global_expr(&mut self, e: Expression) -> Handle<Expression> {
392 self.module.global_expressions.append(e, Span::UNDEFINED)
393 }
394
395 pub fn lit_u(&mut self, x: u32) -> Val {
398 self.lit(Literal::U32(x), Kind::U)
399 }
400 pub fn lit_i(&mut self, x: i32) -> Val {
402 self.lit(Literal::I32(x), Kind::I)
403 }
404 pub fn lit_f(&mut self, x: f32) -> Val {
406 if x.is_finite() {
407 return self.lit(Literal::F32(x), Kind::F);
408 }
409 let bits = self.lit_u(x.to_bits());
410 self.bitcast(bits, Kind::F)
411 }
412 pub fn lit_b(&mut self, x: bool) -> Val {
414 self.lit(Literal::Bool(x), Kind::B)
415 }
416 fn lit(&mut self, l: Literal, kind: Kind) -> Val {
417 Val {
418 expr: self.app(Expression::Literal(l)),
419 kind,
420 width: Width::One,
421 }
422 }
423 pub fn lit_bits(&mut self, kind: Kind, bits: u32) -> Val {
425 match kind {
426 Kind::U => self.lit_u(bits),
427 Kind::I => self.lit_i(bits as i32),
428 Kind::F => self.lit_f(f32::from_bits(bits)),
429 Kind::B => self.lit_b(bits != 0),
430 }
431 }
432
433 pub fn splat(&mut self, v: Val, width: Width) -> Val {
436 if v.width == width {
437 return v;
438 }
439 let Some(size) = width.vector_size().filter(|_| v.width == Width::One) else {
440 self.fail(format!("a value of {} lanes where {width} are needed", v.width));
441 return v;
442 };
443 Val {
444 expr: self.app(Expression::Splat { size, value: v.expr }),
445 kind: v.kind,
446 width,
447 }
448 }
449 pub fn compose(&mut self, parts: &[Val]) -> Val {
451 if let [only] = parts {
452 return *only;
453 }
454 let Some(first) = parts.first() else {
455 self.fail("a vector of no lanes");
456 return self.lit_u(0);
457 };
458 let Some(width) = Width::of_count(parts.len()).filter(|_| {
459 parts
460 .iter()
461 .all(|p| p.width == Width::One && p.kind == first.kind)
462 }) else {
463 self.fail(format!(
464 "a vector of {} parts that are not scalars of one kind",
465 parts.len()
466 ));
467 return *first;
468 };
469 let kind = first.kind;
470 let ty = self.ty_of(kind, width);
471 Val {
472 expr: self.app(Expression::Compose {
473 ty,
474 components: parts.iter().map(|p| p.expr).collect(),
475 }),
476 kind,
477 width,
478 }
479 }
480 pub fn lane(&mut self, v: Val, i: u8) -> Val {
482 if i >= v.width.get() {
483 self.fail(format!("lane {i} of a value of {} lanes", v.width));
484 return v;
485 }
486 if v.width == Width::One {
487 return v;
488 }
489 Val {
490 expr: self.app(Expression::AccessIndex {
491 base: v.expr,
492 index: u32::from(i),
493 }),
494 kind: v.kind,
495 width: Width::One,
496 }
497 }
498 pub fn swizzle(&mut self, v: Val, lanes: &[u8]) -> Val {
500 if let [one] = lanes {
501 return self.lane(v, *one);
502 }
503 let Some(width) = Width::of_count(lanes.len()).filter(|_| lanes.iter().all(|l| *l < v.width.get()))
504 else {
505 self.fail(format!("lanes {lanes:?} of a value of {} lanes", v.width));
506 return v;
507 };
508 if v.width == Width::One {
509 return self.splat(v, width);
510 }
511 let Some(size) = width.vector_size() else {
512 return self.lane(v, lanes.first().copied().unwrap_or(0));
514 };
515 let mut pattern = [SwizzleComponent::X; 4];
516 for (slot, lane) in pattern.iter_mut().zip(lanes) {
517 *slot = component(*lane);
518 }
519 Val {
520 expr: self.app(Expression::Swizzle {
521 size,
522 vector: v.expr,
523 pattern,
524 }),
525 kind: v.kind,
526 width,
527 }
528 }
529 pub fn bitcast(&mut self, v: Val, kind: Kind) -> Val {
531 if v.kind == kind {
532 return v;
533 }
534 Val {
535 expr: self.app(Expression::As {
536 expr: v.expr,
537 kind: kind.kind(),
538 convert: None,
539 }),
540 kind,
541 width: v.width,
542 }
543 }
544 pub fn bitcast_to(&mut self, v: Val, kind: Kind) -> Val {
547 match (v.kind, kind) {
548 (a, b) if a == b => v,
549 (Kind::B, _) => {
550 let ones = self.lit_u(u32::MAX);
551 let zero = self.lit_u(0);
552 let word = self.select(v, ones, zero);
553 self.bitcast(word, kind)
554 }
555 (_, Kind::B) => {
556 let word = self.bitcast(v, Kind::U);
557 let zero = self.lit_u(0);
558 self.binary(BinaryOperator::NotEqual, word, zero)
559 }
560 _ => self.bitcast(v, kind),
561 }
562 }
563 pub fn convert(&mut self, v: Val, kind: Kind) -> Val {
566 Val {
567 expr: self.app(Expression::As {
568 expr: v.expr,
569 kind: kind.kind(),
570 convert: Some(4),
571 }),
572 kind,
573 width: v.width,
574 }
575 }
576 pub fn unary(&mut self, op: UnaryOperator, v: Val) -> Val {
578 Val {
579 expr: self.app(Expression::Unary { op, expr: v.expr }),
580 kind: v.kind,
581 width: v.width,
582 }
583 }
584 pub fn binary(&mut self, op: BinaryOperator, a: Val, b: Val) -> Val {
586 let width = a.width.max(b.width);
587 let (a, b) = (self.splat(a, width), self.splat(b, width));
588 let kind = match op {
589 BinaryOperator::Equal
590 | BinaryOperator::NotEqual
591 | BinaryOperator::Less
592 | BinaryOperator::LessEqual
593 | BinaryOperator::Greater
594 | BinaryOperator::GreaterEqual => Kind::B,
595 _ => a.kind,
596 };
597 Val {
598 expr: self.app(Expression::Binary {
599 op,
600 left: a.expr,
601 right: b.expr,
602 }),
603 kind,
604 width,
605 }
606 }
607 pub fn math(&mut self, fun: MathFunction, args: &[Val]) -> Val {
611 let Some(width) = args.iter().map(|a| a.width).max() else {
612 self.fail("a math function of no arguments");
613 return self.lit_u(0);
614 };
615 let args: Vec<Val> = args.iter().map(|a| self.splat(*a, width)).collect();
616 let Some(first) = args.first().copied() else {
617 self.fail("a math function of no arguments");
618 return self.lit_u(0);
619 };
620 let kind = first.kind;
621 let arg = |i: usize| args.get(i).map(|a| a.expr);
622 let (width, kind) = match fun {
623 MathFunction::Dot => (Width::One, kind),
624 MathFunction::Pack2x16float => (Width::One, Kind::U),
625 MathFunction::Unpack2x16float => (Width::Two, Kind::F),
626 _ => (width, kind),
627 };
628 Val {
629 expr: self.app(Expression::Math {
630 fun,
631 arg: first.expr,
632 arg1: arg(1),
633 arg2: arg(2),
634 arg3: arg(3),
635 }),
636 kind,
637 width,
638 }
639 }
640 pub fn select(&mut self, cond: Val, accept: Val, reject: Val) -> Val {
642 let width = accept.width.max(reject.width).max(cond.width);
643 let (accept, reject) = (self.splat(accept, width), self.splat(reject, width));
644 let cond = self.splat(cond, width);
645 Val {
646 expr: self.app(Expression::Select {
647 condition: cond.expr,
648 accept: accept.expr,
649 reject: reject.expr,
650 }),
651 kind: accept.kind,
652 width,
653 }
654 }
655 pub fn mask_of(&mut self, cond: Val) -> Val {
657 let ones = self.lit_u(u32::MAX);
658 let zero = self.lit_u(0);
659 self.select(cond, ones, zero)
660 }
661
662 pub fn end_function(&mut self, name: &str, decl: FunctionDecl) -> Result<Handle<naga::Function>, String> {
665 self.finishable()?;
666 let mut function = std::mem::take(&mut self.function);
667 function.name = Some(name.to_owned());
668 function.arguments = decl.arguments;
669 function.result = decl.result.map(|ty| naga::FunctionResult { ty, binding: None });
670 function.body = self.blocks.first_mut().map(std::mem::take).unwrap_or_default();
671 Ok(self.module.functions.append(function, Span::UNDEFINED))
672 }
673
674 pub fn declare_operation(
677 &mut self,
678 name: &str,
679 arguments: Vec<naga::FunctionArgument>,
680 returns_bool: bool,
681 ) -> Handle<naga::Function> {
682 let mut function = Function {
683 name: Some(name.to_owned()),
684 arguments,
685 ..Function::default()
686 };
687 if returns_bool {
688 let ty = self.ty_of(Kind::B, Width::One);
689 function.result = Some(naga::FunctionResult { ty, binding: None });
690 let value = function
691 .expressions
692 .append(Expression::Literal(naga::Literal::Bool(false)), Span::UNDEFINED);
693 function
694 .body
695 .push(Statement::Return { value: Some(value) }, Span::UNDEFINED);
696 }
697 self.module.functions.append(function, Span::UNDEFINED)
698 }
699
700 pub fn finish_functions(mut self) -> Result<Module, String> {
703 self.finishable()?;
704 Ok(self.module)
705 }
706
707 pub fn finish(
712 mut self,
713 name: &str,
714 stage: naga::ShaderStage,
715 arguments: Vec<naga::FunctionArgument>,
716 result: Option<Handle<Type>>,
717 early_depth_test: bool,
718 ) -> Result<Module, String> {
719 self.finishable()?;
720 let mut function = self.function;
721 function.name = Some(name.to_owned());
722 function.arguments = arguments;
723 function.result = result.map(|ty| naga::FunctionResult { ty, binding: None });
724 function.body = self.blocks.pop().unwrap_or_default();
725 self.module.entry_points.push(naga::EntryPoint {
726 name: name.to_owned(),
727 stage,
728 early_depth_test: early_depth_test.then_some(naga::EarlyDepthTest::Force),
729 workgroup_size: self.workgroup_size,
730 workgroup_size_overrides: None,
731 function,
732 mesh_info: None,
733 task_payload: None,
734 incoming_ray_payload: None,
735 });
736 Ok(self.module)
737 }
738}