Skip to main content

spirv_webgpu_transform/
lib.rs

1//! # SPIRV WebGPU Transforms
2//!
3//! See [https://github.com/davnotdev/spirv-webgpu-transform](https://github.com/davnotdev/spirv-webgpu-transform) for more details.
4//!
5//! ## Features
6//!
7//! At the moment, the following transformations are supported:
8//!
9//! | Feature                           | `spirv-val` | `naga` | `tint` |
10//! | --------------------------------- | ----------- | ------ | ------ |
11//! | Combined Image Samplers           | ✅          | ✅     | ✅     |
12//! | Immediates (Push Constants)       | ✅          | ✅\*   | ✅     |
13//! | Binding Arrays                    | ✅          | ✅     | ✅     |
14//! | Mixed Depth / Comparison          | ✅          | ⚠️\*   | ❌     |
15//! | isnan / isinf Patching            | ✅          | ✅     | ✅     |
16//! | Storage Cube Patching             | ✅          | ✅     | ✅     |
17//! | Unused Image Sampler Pruning      | ✅          | ✅     | ✅     |
18//!
19//! > (1)\* 99% OK, just one very specific padding related `naga` bug.
20//!
21//! > (2)\* Simple cases are OK.
22//! > With some [special patches](https://github.com/davnotdev/wgpu/tree/trunk-naga-patches), `naga` can process these.
23//!
24//! ## Using the result
25//!
26//! After running an individual shader through one or multiple transformations, you will want to:
27//!
28//! 1. Know which set bindings were affected, use the output [`CorrectionMap`] for this purpose.
29//! 2. Ensure that your vertex and fragment shaders shader the same binding layout, use [`mirrorpatch`] for this purpose
30//!
31
32use std::collections::{HashMap, HashSet};
33
34mod correction;
35mod immediatespatch;
36mod isnanisinfpatch;
37mod mirrorpatch;
38mod pruneunuseddref;
39mod splitbindingarray;
40mod splitcombined;
41mod splitdref;
42mod spv;
43mod storagecubepatch;
44mod util;
45
46#[cfg(test)]
47mod test;
48
49use spv::*;
50use util::*;
51
52pub use correction::*;
53pub use immediatespatch::*;
54pub use isnanisinfpatch::*;
55pub use mirrorpatch::*;
56pub use pruneunuseddref::*;
57pub use splitbindingarray::*;
58pub use splitcombined::*;
59pub use splitdref::*;
60pub use storagecubepatch::*;
61
62#[derive(Debug, Clone)]
63struct InstructionInsert {
64    previous_spv_idx: usize,
65    instruction: Vec<u32>,
66}
67
68#[derive(Debug, Clone)]
69struct WordInsert {
70    idx: usize,
71    word: u32,
72    head_idx: usize,
73}
74
75/// Helper to convert a `&[u8]` into a `Vec<u32>`.
76pub fn u8_slice_to_u32_vec(vec: &[u8]) -> Vec<u32> {
77    assert_eq!(
78        vec.len() % 4,
79        0,
80        "Input slice length must be a multiple of 4."
81    );
82
83    vec.chunks_exact(4)
84        .map(|chunk| {
85            (chunk[0] as u32)
86                | ((chunk[1] as u32) << 8)
87                | ((chunk[2] as u32) << 16)
88                | ((chunk[3] as u32) << 24)
89        })
90        .collect::<Vec<_>>()
91}
92
93/// Helper to convert a `&[u32]` into a `Vec<u8>`.
94pub fn u32_slice_to_u8_vec(vec: &[u32]) -> Vec<u8> {
95    vec.iter()
96        .flat_map(|&num| {
97            vec![
98                (num & 0xFF) as u8,
99                ((num >> 8) & 0xFF) as u8,
100                ((num >> 16) & 0xFF) as u8,
101                ((num >> 24) & 0xFF) as u8,
102            ]
103        })
104        .collect::<Vec<u8>>()
105}