├── .gitattributes
├── .github
├── FUNDING.yml
└── ci.yml
├── .gitignore
├── .gitmodules
├── .travis.yml
├── .travis
├── android_gcc.sh
├── linux_clang.sh
├── linux_gcc.sh
├── linux_wasm.sh
└── macos_clang.sh
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── appveyor.yml
├── bindings_generator
├── Cargo.toml
└── src
│ └── main.rs
├── bors.toml
├── examples
├── Cargo.toml
└── src
│ ├── glsl
│ └── main.rs
│ ├── hlsl
│ └── main.rs
│ ├── lib.rs
│ ├── msl
│ └── main.rs
│ └── vertex.spv
├── minify-spirv-cross.sh
├── spirv_cross
├── Cargo.toml
├── build.rs
├── src
│ ├── bindings_native.rs
│ ├── bindings_wasm.rs
│ ├── bindings_wasm_functions.rs
│ ├── compiler.rs
│ ├── emscripten.rs
│ ├── glsl.rs
│ ├── hlsl.rs
│ ├── lib.rs
│ ├── msl.rs
│ ├── ptr_util.rs
│ ├── spirv.rs
│ ├── wrapper.cpp
│ └── wrapper.hpp
└── tests
│ ├── common
│ └── mod.rs
│ ├── glsl_tests.rs
│ ├── hlsl_tests.rs
│ ├── msl_tests.rs
│ ├── shaders
│ ├── array.vert
│ ├── array.vert.spv
│ ├── const_array.vert
│ ├── const_array.vert.spv
│ ├── initialization.vert
│ ├── initialization.vert.spv
│ ├── multiple_entry_points.cl
│ ├── multiple_entry_points.cl.spv
│ ├── rasterize_disabled.vert
│ ├── rasterize_disabled.vert.spv
│ ├── sampler.frag
│ ├── sampler.frag.spv
│ ├── simple.vert
│ ├── simple.vert.spv
│ ├── specialization.comp
│ ├── specialization.comp.spv
│ ├── struct.frag
│ ├── struct.frag.spv
│ ├── struct.vert
│ ├── struct.vert.spv
│ ├── two_ubo.vert
│ ├── two_ubo.vert.spv
│ ├── vs_and_fs.asm
│ ├── vs_and_fs.asm.spv
│ ├── workgroup.comp
│ └── workgroup.comp.spv
│ └── spirv_tests.rs
└── wasm
├── Cargo.toml
├── spirv_cross_wrapper_glsl.js
├── spirv_cross_wrapper_glsl.wasm
└── src
└── main.rs
/.gitattributes:
--------------------------------------------------------------------------------
1 | [attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
2 |
3 | * text=auto eol=lf
4 | *.cpp rust
5 | *.hpp rust
6 | *.rs rust
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [grovesNL]
2 |
--------------------------------------------------------------------------------
/.github/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches-ignore:
7 | - 'dependabot/**'
8 | - staging-squash-merge.tmp
9 |
10 | env:
11 | CARGO_TERM_COLOR: always
12 |
13 | jobs:
14 | build:
15 | strategy:
16 | matrix:
17 | toolchain: [stable, nightly]
18 | os: [windows-latest, ubuntu-latest, macos-latest]
19 | exclude:
20 | - os: macos-latest
21 | toolchain: nightly
22 | - os: windows-latest
23 | toolchain: nightly
24 | runs-on: ${{ matrix.os }}
25 | steps:
26 | - uses: actions/checkout@v2
27 | with:
28 | submodules: true
29 | - uses: actions/cache@v2
30 | with:
31 | path: |
32 | ~/.cargo/bin/
33 | ~/.cargo/registry/index/
34 | ~/.cargo/registry/cache/
35 | ~/.cargo/git/db/
36 | target/
37 | key: ${{ runner.os }}-cargo-build-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.toml') }}
38 | - uses: actions-rs/toolchain@v1
39 | with:
40 | toolchain: ${{ matrix.toolchain }}
41 | override: true
42 | - name: Build & run tests
43 | run: cargo test --workspace
44 | env:
45 | CARGO_INCREMENTAL: 0
46 | RUSTFLAGS: "-C debuginfo=0 -D warnings"
47 | build-wasm:
48 | strategy:
49 | matrix:
50 | toolchain: [stable, nightly]
51 | os: [ubuntu-latest]
52 | runs-on: ${{ matrix.os }}
53 | steps:
54 | - uses: actions/checkout@v2
55 | with:
56 | submodules: true
57 | - uses: actions/cache@v2
58 | with:
59 | path: |
60 | ~/.cargo/bin/
61 | ~/.cargo/registry/index/
62 | ~/.cargo/registry/cache/
63 | ~/.cargo/git/db/
64 | target/
65 | key: ${{ runner.os }}-cargo-build-wasm-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.toml') }}
66 | - uses: actions-rs/toolchain@v1
67 | with:
68 | toolchain: ${{ matrix.toolchain }}
69 | target: wasm32-unknown-unknown
70 | override: true
71 | - name: Build
72 | run: (cd examples && cargo build --target=wasm32-unknown-unknown --verbose --bin glsl)
73 | env:
74 | CARGO_INCREMENTAL: 0
75 | RUSTFLAGS: "-C debuginfo=0 -D warnings"
76 | build-android:
77 | runs-on: ubuntu-latest
78 | steps:
79 | - uses: actions/checkout@v2
80 | with:
81 | submodules: true
82 | - uses: actions-rs/toolchain@v1
83 | with:
84 | toolchain: stable
85 | - uses: actions/cache@v2
86 | with:
87 | path: |
88 | ~/.cargo/bin/
89 | ~/.cargo/registry/index/
90 | ~/.cargo/registry/cache/
91 | ~/.cargo/git/db/
92 | target/
93 | key: ${{ runner.os }}-cargo-build-android-${{ hashFiles('**/Cargo.toml') }}
94 | - name: Uninstall android-31
95 | run: $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --uninstall "platforms;android-31"
96 | - name: Install Android targets
97 | run: rustup target add aarch64-linux-android armv7-linux-androideabi
98 | - name: Install Cargo APK
99 | run: cargo install --force cargo-apk
100 | - name: Build APK
101 | run: (cd examples && cargo apk build --bin glsl)
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | examples/target/
3 | spirv_cross/target/
4 | **/*.rs.bk
5 | Cargo.lock
6 | .vscode
7 | # Added in directory by bindgen
8 | flag_check.exe
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "spirv_cross/src/vendor/SPIRV-Cross"]
2 | path = spirv_cross/src/vendor/SPIRV-Cross
3 | url = https://github.com/grovesNL/SPIRV-Cross.git
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | rust:
3 | - stable
4 | cache:
5 | cargo: true
6 | branches:
7 | only:
8 | - staging
9 | - trying
10 | - master
11 | except:
12 | - staging.tmp
13 | matrix:
14 | include:
15 | #- os: linux
16 | # language: android
17 | # compiler: gcc
18 | # env:
19 | # - JOB="android_gcc"
20 | # android:
21 | # components:
22 | # - build-tools-26.0.1
23 | # - android-18
24 | # jdk: openjdk8
25 | - os: osx
26 | osx_image: xcode9
27 | compiler: clang
28 | env:
29 | - JOB="macos_clang"
30 | - os: linux
31 | compiler: gcc
32 | env:
33 | - JOB="linux_gcc"
34 | addons:
35 | apt:
36 | sources:
37 | - llvm-toolchain-precise
38 | - ubuntu-toolchain-r-test
39 | packages:
40 | - g++-5
41 | - os: linux
42 | compiler: clang
43 | env:
44 | - JOB="linux_clang"
45 | addons:
46 | apt:
47 | sources:
48 | - llvm-toolchain-precise
49 | - ubuntu-toolchain-r-test
50 | packages:
51 | - clang-5.0
52 | - os: linux
53 | compiler: clang
54 | env:
55 | - JOB="linux_wasm"
56 | addons:
57 | apt:
58 | sources:
59 | - llvm-toolchain-precise
60 | - ubuntu-toolchain-r-test
61 | packages:
62 | - clang-5.0
63 | notifications:
64 | webhooks:
65 | urls:
66 | - https://webhooks.gitter.im/e/c09595dea93d78afd940
67 | on_success: change
68 | on_failure: always
69 | on_start: never
70 | script:
71 | - cd .travis
72 | - chmod +x *.sh
73 | - cd $TRAVIS_BUILD_DIR
74 | - if [[ $JOB == "android_gcc" ]]; then .travis/android_gcc.sh; fi
75 | - if [[ $JOB == "macos_clang" ]]; then .travis/macos_clang.sh; fi
76 | - if [[ $JOB == "linux_gcc" ]]; then .travis/linux_gcc.sh; fi
77 | - if [[ $JOB == "linux_clang" ]]; then .travis/linux_clang.sh; fi
78 | - if [[ $JOB == "linux_wasm" ]]; then .travis/linux_wasm.sh; fi
79 |
--------------------------------------------------------------------------------
/.travis/android_gcc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Install Android NDK and create standalone toolchain
4 | export NDK_HOME=$TRAVIS_BUILD_DIR/android-ndk-r16b
5 | export ANDROID_TOOLCHAIN=$TRAVIS_BUILD_DIR/android-toolchain
6 | export PATH=$PATH:$ANDROID_TOOLCHAIN/bin
7 | export ANDROID_TARGET=arm-linux-androideabi
8 | export CXX_arm_linux_androideabi=$ANDROID_TARGET-gcc++
9 | rm -rf $NDK_HOME
10 | curl -L http://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip -O
11 | unzip -oq android-ndk-r16b-linux-x86_64.zip
12 | rm android-ndk-r16b-linux-x86_64.zip
13 | python $NDK_HOME/build/tools/make_standalone_toolchain.py --arch arm --api 21 --stl=libc++ --install-dir $ANDROID_TOOLCHAIN
14 |
15 | # Install Rust
16 | export RUSTFLAGS="-C link-args=-no-pie -C link-args=-Wl,-Bsymbolic"
17 | export PATH=$HOME/.cargo/bin/:$PATH
18 | curl https://sh.rustup.rs -o rustup.sh
19 | sh rustup.sh -y
20 | rustup target add arm-linux-androideabi
21 | cargo install cargo-apk
22 |
23 | # Build GLSL example
24 | cd examples
25 | export CPATH=$NDK_HOME/sources/cxx-stl/llvm-libc++/include:$NDK_HOME/sysroot/usr/include/arm-linux-androideabi:$JAVA_HOME/include:$JAVA_HOME/include/linux:$NDK_HOME/sysroot/usr/include:$CPATH
26 | cargo apk build --bin glsl
27 |
--------------------------------------------------------------------------------
/.travis/linux_clang.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export CXX=clang++
3 |
4 | cargo build --verbose --all --all-features
5 | cargo test --verbose --all --all-features
6 |
--------------------------------------------------------------------------------
/.travis/linux_gcc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export CXX=g++-5
3 |
4 | cargo build --verbose --all --all-features
5 | cargo test --verbose --all --all-features
6 |
--------------------------------------------------------------------------------
/.travis/linux_wasm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export CXX=clang++
3 |
4 | rustup target add wasm32-unknown-unknown
5 | (cd examples && cargo build --target=wasm32-unknown-unknown --verbose --bin glsl)
6 |
--------------------------------------------------------------------------------
/.travis/macos_clang.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export CXX=clang++
3 | export MACOSX_DEPLOYMENT_TARGET=10.7
4 |
5 | cargo build --verbose --all --all-features
6 | cargo test --verbose --all --all-features
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | `spirv_cross` is linked to the [`SPIRV-Cross`](https://github.com/KhronosGroup/SPIRV-Cross) library through git submodules. To receive changes from the upstream repository, update the submodule to track a different commit.
4 |
5 | `spirv_cross` provides a number of C externs to enable automatic bindings generation from [`bindgen`](https://rust-lang-nursery.github.io/rust-bindgen/). To expose additional capabilities, edit [`wrapper.cpp`](https://github.com/grovesNL/spirv_cross/blob/master/spirv_cross/src/wrapper.cpp) and [`wrapper.hpp`](https://github.com/grovesNL/spirv_cross/blob/master/spirv_cross/src/wrapper.hpp). Afterwards, run `cargo run` within the `bindings_generator` directory, which will generate an updated `bindings.rs`. Feel free to update [`bindings_generator/src/main.rs`](https://github.com/grovesNL/spirv_cross/blob/master/bindings_generator/src/main.rs) if changes are necessary to expose additional C++ types that are supported by `bindgen`.
6 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "spirv_cross",
4 | "examples",
5 | "bindings_generator",
6 | "wasm"
7 | ]
8 |
--------------------------------------------------------------------------------
/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Permission is hereby granted, free of charge, to any
2 | person obtaining a copy of this software and associated
3 | documentation files (the "Software"), to deal in the
4 | Software without restriction, including without
5 | limitation the rights to use, copy, modify, merge,
6 | publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software
8 | is furnished to do so, subject to the following
9 | conditions:
10 |
11 | The above copyright notice and this permission notice
12 | shall be included in all copies or substantial portions
13 | of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | spirv_cross
3 |
4 |
7 |
8 |
11 |
12 | ## Example
13 |
14 | `spirv_cross` provides a safe wrapper around [SPIRV-Cross](https://github.com/KhronosGroup/SPIRV-Cross) for use with Rust. For example, here is a simple function to parse a SPIR-V module and compile it to HLSL and MSL:
15 |
16 | ```rust
17 | extern crate spirv_cross;
18 | use spirv_cross::{spirv, hlsl, msl, ErrorCode};
19 |
20 | fn example(module: spirv::Module) -> Result<(), ErrorCode> {
21 | // Compile to HLSL
22 | let ast = spirv::Ast::::parse(&module)?;
23 | println!("{}", ast.compile()?);
24 |
25 | // Compile to MSL
26 | let ast = spirv::Ast::::parse(&module)?;
27 | println!("{}", ast.compile()?);
28 |
29 | Ok(())
30 | }
31 | ```
32 |
33 | ## License
34 |
35 | This project is licensed under either of [Apache License, Version
36 | 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT), at your option.
37 |
38 | ## Contribution
39 |
40 | Unless you explicitly state otherwise, any contribution intentionally submitted
41 | for inclusion in this project by you, as defined in the Apache 2.0 license,
42 | shall be dual licensed as above, without any additional terms or conditions.
43 |
44 | See [CONTRIBUTING.md](CONTRIBUTING.md).
45 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | os: Visual Studio 2015
2 |
3 | environment:
4 | global:
5 | CHANNEL: stable
6 | CRATE_NAME: spirv_cross
7 | matrix:
8 | - TARGET: x86_64-pc-windows-gnu
9 | - TARGET: x86_64-pc-windows-msvc
10 |
11 | install:
12 | - curl -sSf -o rustup-init.exe https://win.rustup.rs
13 | - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
14 | - set PATH=%PATH%;C:\msys64\mingw64\bin;C:\Users\appveyor\.cargo\bin
15 | - if "%TARGET%" == "x86_64-pc-windows-gnu" ( rustup component remove rust-mingw )
16 | - if "%TARGET%" == "x86_64-pc-windows-gnu" ( for %%I in (crt2.o dllcrt2.o libmingwex.a libmsvcrt.a) do xcopy /Y "C:\msys64\mingw64\x86_64-w64-mingw32\lib\%%I" "C:\Users\appveyor\.rustup\toolchains\stable-%TARGET%\lib\rustlib\%TARGET%\lib\" )
17 | - rustc -Vv
18 | - cargo -V
19 | - git submodule update --init --recursive
20 |
21 | build_script:
22 | - cargo build --verbose --all --target %TARGET% --all-features
23 |
24 | test_script:
25 | - cargo test --verbose --all --target %TARGET% --all-features
26 |
27 | branches:
28 | only:
29 | - staging
30 | - trying
31 | - master
32 | except:
33 | - staging.tmp
34 |
35 | notifications:
36 | - provider: Webhook
37 | url: https://webhooks.gitter.im/e/8748eda7974203c7a542
38 | on_build_success: false
39 | on_build_failure: true
40 | on_build_status_changed: true
41 |
42 | cache:
43 | - C:\Users\appveyor\.cargo
44 |
--------------------------------------------------------------------------------
/bindings_generator/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "bindings_generator"
3 | version = "0.1.0"
4 | authors = ["Joshua Groves "]
5 |
6 | [dependencies]
7 | bindgen = "0.52.0"
8 |
9 | [[bin]]
10 | name = "bindings_generator"
11 | path = "src/main.rs"
12 |
--------------------------------------------------------------------------------
/bindings_generator/src/main.rs:
--------------------------------------------------------------------------------
1 | extern crate bindgen;
2 |
3 | use std::env;
4 |
5 | fn main() {
6 | let out_path = env::current_dir().unwrap();
7 | // For native targets, include all types and functions
8 | bindgen::Builder::default()
9 | .header(
10 | out_path
11 | .join("../spirv_cross/src/wrapper.hpp")
12 | .to_str()
13 | .unwrap(),
14 | )
15 | .clang_args(["-x", "c++", "-std=c++14"].iter())
16 | .enable_cxx_namespaces()
17 | .whitelist_function("sc_internal.*")
18 | .whitelist_type("spv::.*")
19 | .whitelist_type("Sc.*")
20 | .bitfield_enum(".*(Mask|Flags)")
21 | .rustified_enum("spv::BuiltIn")
22 | .rustified_enum("spv::Decoration")
23 | .rustified_enum("spv::ExecutionModel")
24 | .rustified_enum("spv::ImageFormat")
25 | .rustified_enum("spv::Dim")
26 | .rustified_enum("spv::StorageClass")
27 | .rustified_enum("ScInternalResult")
28 | .rustified_enum("spirv_cross::SPIRType_BaseType")
29 | .rustified_enum("spirv_cross::MSLVertexFormat")
30 | .opaque_type("std::.*")
31 | .clang_args(vec![
32 | "-DSPIRV_CROSS_WRAPPER_GLSL",
33 | "-DSPIRV_CROSS_WRAPPER_MSL",
34 | "-DSPIRV_CROSS_WRAPPER_HLSL",
35 | ])
36 | .layout_tests(false)
37 | .generate()
38 | .expect("Unable to generate bindings")
39 | .write_to_file(out_path.join("../spirv_cross/src/bindings_native.rs"))
40 | .expect("Couldn't write bindings!");
41 | // For wasm targets, include all types, functions will be implemented manually
42 | bindgen::Builder::default()
43 | .header(
44 | out_path
45 | .join("../spirv_cross/src/wrapper.hpp")
46 | .to_str()
47 | .unwrap(),
48 | )
49 | .clang_args(["-x", "c++", "-std=c++14"].iter())
50 | .enable_cxx_namespaces()
51 | .whitelist_type("spv::.*")
52 | .whitelist_type("Sc.*")
53 | .bitfield_enum(".*(Mask|Flags)")
54 | .rustified_enum("spv::BuiltIn")
55 | .rustified_enum("spv::Decoration")
56 | .rustified_enum("spv::ExecutionModel")
57 | .rustified_enum("spv::ImageFormat")
58 | .rustified_enum("spv::Dim")
59 | .rustified_enum("ScInternalResult")
60 | .rustified_enum("spirv_cross::SPIRType_BaseType")
61 | .rustified_enum("spirv_cross::MSLVertexFormat")
62 | .opaque_type("std::.*")
63 | .clang_args(vec![
64 | "-DSPIRV_CROSS_WRAPPER_GLSL",
65 | "-DSPIRV_CROSS_WRAPPER_MSL",
66 | "-DSPIRV_CROSS_WRAPPER_HLSL",
67 | ])
68 | .layout_tests(false)
69 | .generate()
70 | .expect("Unable to generate bindings")
71 | .write_to_file(out_path.join("../spirv_cross/src/bindings_wasm.rs"))
72 | .expect("Couldn't write bindings!");
73 | }
74 |
--------------------------------------------------------------------------------
/bors.toml:
--------------------------------------------------------------------------------
1 | status = [
2 | "continuous-integration/travis-ci/push",
3 | "continuous-integration/appveyor/branch"
4 | ]
5 |
--------------------------------------------------------------------------------
/examples/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "examples"
3 | version = "0.1.0"
4 | authors = ["Joshua Groves "]
5 | edition = "2018"
6 |
7 | [dependencies]
8 | spirv_cross = { path = "../spirv_cross", features = ["hlsl", "msl", "glsl"] }
9 |
10 | [[bin]]
11 | name = "hlsl"
12 | path = "src/hlsl/main.rs"
13 |
14 | [[bin]]
15 | name = "msl"
16 | path = "src/msl/main.rs"
17 |
18 | [[bin]]
19 | name = "glsl"
20 | path = "src/glsl/main.rs"
21 |
--------------------------------------------------------------------------------
/examples/src/glsl/main.rs:
--------------------------------------------------------------------------------
1 | extern crate examples;
2 | extern crate spirv_cross;
3 | use examples::words_from_bytes;
4 | use spirv_cross::{glsl, spirv};
5 |
6 | fn main() {
7 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!("../vertex.spv")));
8 |
9 | // Parse a SPIR-V module
10 | let mut ast = spirv::Ast::::parse(&module).unwrap();
11 | let mut options = glsl::CompilerOptions::default();
12 | options.version = glsl::Version::V4_60;
13 | ast.set_compiler_options(&options).unwrap();
14 |
15 | // List all entry points
16 | for entry_point in &ast.get_entry_points().unwrap() {
17 | println!("{:?}", entry_point);
18 | }
19 |
20 | // Compile to GLSL
21 | let shader = ast.compile().unwrap();
22 | println!("{}", shader);
23 | }
24 |
--------------------------------------------------------------------------------
/examples/src/hlsl/main.rs:
--------------------------------------------------------------------------------
1 | extern crate examples;
2 | extern crate spirv_cross;
3 | use examples::words_from_bytes;
4 | use spirv_cross::{hlsl, spirv};
5 |
6 | fn main() {
7 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!("../vertex.spv")));
8 |
9 | // Parse a SPIR-V module
10 | let mut ast = spirv::Ast::::parse(&module).unwrap();
11 | let mut options = hlsl::CompilerOptions::default();
12 | options.shader_model = hlsl::ShaderModel::V5_1;
13 | options.point_size_compat = false;
14 | options.point_coord_compat = false;
15 | options.vertex = hlsl::CompilerVertexOptions::default();
16 | options.force_storage_buffer_as_uav = false;
17 | options.nonwritable_uav_texture_as_srv = false;
18 | options.force_zero_initialized_variables = true;
19 | options.entry_point = None;
20 | ast.set_compiler_options(&options).unwrap();
21 |
22 | // List all entry points
23 | for entry_point in &ast.get_entry_points().unwrap() {
24 | println!("{:?}", entry_point);
25 | }
26 |
27 | // Compile to HLSL
28 | let shader = ast.compile().unwrap();
29 | println!("{}", shader);
30 | }
31 |
--------------------------------------------------------------------------------
/examples/src/lib.rs:
--------------------------------------------------------------------------------
1 | #[allow(clippy::cast_ptr_alignment)]
2 | pub fn words_from_bytes(buf: &[u8]) -> &[u32] {
3 | unsafe {
4 | std::slice::from_raw_parts(
5 | buf.as_ptr() as *const u32,
6 | buf.len() / std::mem::size_of::(),
7 | )
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/examples/src/msl/main.rs:
--------------------------------------------------------------------------------
1 | extern crate examples;
2 | extern crate spirv_cross;
3 | use examples::words_from_bytes;
4 | use spirv_cross::{msl, spirv};
5 |
6 | fn main() {
7 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!("../vertex.spv")));
8 |
9 | // Parse a SPIR-V module
10 | let mut ast = spirv::Ast::::parse(&module).unwrap();
11 |
12 | let mut compiler_options = msl::CompilerOptions::default();
13 |
14 | // Set some overrides
15 | compiler_options.resource_binding_overrides.insert(
16 | msl::ResourceBindingLocation {
17 | stage: spirv::ExecutionModel::Vertex,
18 | desc_set: 0,
19 | binding: 0,
20 | },
21 | msl::ResourceBinding {
22 | buffer_id: 5,
23 | texture_id: 6,
24 | sampler_id: 7,
25 | count: 0,
26 | },
27 | );
28 |
29 | compiler_options.vertex_attribute_overrides.insert(
30 | msl::VertexAttributeLocation(1),
31 | msl::VertexAttribute {
32 | buffer_id: 1,
33 | format: msl::Format::Other,
34 | built_in: None,
35 | vecsize: 0,
36 | },
37 | );
38 |
39 | ast.set_compiler_options(&compiler_options).unwrap();
40 |
41 | // List all entry points
42 | for entry_point in &ast.get_entry_points().unwrap() {
43 | println!("{:?}", entry_point);
44 | }
45 |
46 | // Compile to MSL
47 | let shader = ast.compile().unwrap();
48 | println!("{}", shader);
49 | }
50 |
--------------------------------------------------------------------------------
/examples/src/vertex.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/examples/src/vertex.spv
--------------------------------------------------------------------------------
/minify-spirv-cross.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | cd spirv_cross/src/vendor/SPIRV-Cross \
3 | && rm -rf \
4 | cmake \
5 | gn \
6 | samples \
7 | shaders* \
8 | reference \
9 | tests* \
10 | *.sh \
11 | *.py
12 |
--------------------------------------------------------------------------------
/spirv_cross/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "spirv_cross"
3 | version = "0.23.1"
4 | authors = ["Joshua Groves "]
5 | description = "Safe wrapper around SPIRV-Cross"
6 | license = "MIT/Apache-2.0"
7 | homepage = "https://github.com/grovesNL/spirv_cross"
8 | repository = "https://github.com/grovesNL/spirv_cross"
9 | readme = "../README.md"
10 | keywords = ["spirv", "cross"]
11 | build = "build.rs"
12 | edition = "2018"
13 |
14 | [features]
15 | default = []
16 | glsl = []
17 | hlsl = []
18 | msl = []
19 |
20 | [target.'cfg(not(target_arch = "wasm32"))'.build-dependencies]
21 | cc = { version = "1", features = ["parallel"] }
22 |
23 | [target.wasm32-unknown-unknown.dependencies]
24 | wasm-bindgen = "0.2.33"
25 | js-sys = "0.3.10"
26 |
--------------------------------------------------------------------------------
/spirv_cross/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | // Prevent building SPIRV-Cross on wasm32 target
3 | let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH");
4 | if let Ok(arch) = target_arch {
5 | if "wasm32" == arch {
6 | return;
7 | }
8 | }
9 |
10 | let target_vendor = std::env::var("CARGO_CFG_TARGET_VENDOR");
11 | let is_apple = target_vendor.is_ok() && target_vendor.unwrap() == "apple";
12 |
13 | let target_os = std::env::var("CARGO_CFG_TARGET_OS");
14 | let is_ios = target_os.is_ok() && target_os.unwrap() == "ios";
15 |
16 | let mut build = cc::Build::new();
17 | build.cpp(true);
18 |
19 | let compiler = build.try_get_compiler();
20 | let is_clang = compiler.is_ok() && compiler.unwrap().is_like_clang();
21 |
22 | if is_apple && (is_clang || is_ios) {
23 | build.flag("-std=c++14").cpp_set_stdlib("c++");
24 | } else {
25 | build.flag_if_supported("-std=c++14");
26 | }
27 |
28 | build
29 | .flag("-DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS")
30 | .flag("-DSPIRV_CROSS_WRAPPER_NO_EXCEPTIONS");
31 |
32 | build
33 | .file("src/wrapper.cpp")
34 | .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
35 | .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
36 | .file("src/vendor/SPIRV-Cross/spirv_cross_parsed_ir.cpp")
37 | .file("src/vendor/SPIRV-Cross/spirv_parser.cpp")
38 | .file("src/vendor/SPIRV-Cross/spirv_cross_util.cpp");
39 |
40 | // Ideally the GLSL compiler would be omitted here, but the HLSL and MSL compiler
41 | // currently inherit from it. So it's necessary to unconditionally include it here.
42 | build
43 | .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
44 | .flag("-DSPIRV_CROSS_WRAPPER_GLSL");
45 |
46 | #[cfg(feature = "hlsl")]
47 | build
48 | .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
49 | .flag("-DSPIRV_CROSS_WRAPPER_HLSL");
50 |
51 | #[cfg(feature = "msl")]
52 | build
53 | .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
54 | .flag("-DSPIRV_CROSS_WRAPPER_MSL");
55 |
56 | build.compile("spirv-cross-rust-wrapper");
57 | }
58 |
--------------------------------------------------------------------------------
/spirv_cross/src/bindings_wasm_functions.rs:
--------------------------------------------------------------------------------
1 | //! These are manually implemented wrappers that accept the same signatures generated by bindgen
2 | //! and instead forward the calls onto the raw Emscripten bindings. Any necessary type conversions,
3 | //! copying, etc. are performed internally, so higher level code (such as `Compiler`) is mostly
4 | //! unaware whether native or web code is being called. Some exceptions are places where pointers
5 | //! would consumed directly (i.e. reading a string from a pointer), so `ptr_util` is provided for
6 | //! those cases.
7 |
8 | use crate::emscripten;
9 | use crate::{bindings};
10 | use js_sys::{global, Object, Reflect, Uint32Array, Uint8Array};
11 | use std::ffi::CStr;
12 | use wasm_bindgen::prelude::*;
13 |
14 | const U32_SIZE: u32 = std::mem::size_of::() as u32;
15 |
16 | #[wasm_bindgen]
17 | extern "C" {
18 | // Raw SPIRV-Cross bindings
19 | // Pointers and the result type are replaced with `u32`
20 | #[wasm_bindgen(js_namespace = sc_internal)]
21 | fn _sc_internal_compiler_glsl_new(compiler: u32, ir: u32, size: u32) -> u32;
22 |
23 | #[wasm_bindgen(js_namespace = sc_internal)]
24 | fn _sc_internal_compiler_glsl_set_options(compiler: u32, options: u32) -> u32;
25 |
26 | #[wasm_bindgen(js_namespace = sc_internal)]
27 | fn _sc_internal_compiler_glsl_build_combined_image_samplers(compiler: u32) -> u32;
28 |
29 | #[wasm_bindgen(js_namespace = sc_internal)]
30 | fn _sc_internal_compiler_glsl_get_combined_image_samplers(
31 | compiler: u32,
32 | samplers: u32,
33 | size: u32,
34 | ) -> u32;
35 |
36 | #[wasm_bindgen(js_namespace = sc_internal)]
37 | fn _sc_internal_compiler_glsl_add_header_line(compiler: u32, str: u32) -> u32;
38 |
39 | #[wasm_bindgen(js_namespace = sc_internal)]
40 | fn _sc_internal_compiler_glsl_flatten_buffer_block(compiler: u32, id: u32) -> u32;
41 |
42 | #[wasm_bindgen(js_namespace = sc_internal)]
43 | fn _sc_internal_compiler_get_decoration(
44 | compiler: u32,
45 | result: u32,
46 | id: u32,
47 | decoration: u32,
48 | ) -> u32;
49 |
50 | #[wasm_bindgen(js_namespace = sc_internal)]
51 | fn _sc_internal_compiler_set_decoration(
52 | compiler: u32,
53 | id: u32,
54 | decoration: u32,
55 | argument: u32,
56 | ) -> u32;
57 |
58 | #[wasm_bindgen(js_namespace = sc_internal)]
59 | fn _sc_internal_compiler_unset_decoration(compiler: u32, id: u32, decoration: u32) -> u32;
60 |
61 | #[wasm_bindgen(js_namespace = sc_internal)]
62 | fn _sc_internal_compiler_get_name(compiler: u32, id: u32, name: u32) -> u32;
63 |
64 | #[wasm_bindgen(js_namespace = sc_internal)]
65 | fn _sc_internal_compiler_set_name(compiler: u32, id: u32, name: u32) -> u32;
66 |
67 | #[wasm_bindgen(js_namespace = sc_internal)]
68 | fn _sc_internal_compiler_set_member_name(compiler: u32, id: u32, index: u32, name: u32) -> u32;
69 |
70 | #[wasm_bindgen(js_namespace = sc_internal)]
71 | fn _sc_internal_compiler_get_entry_points(compiler: u32, entry_points: u32, size: u32) -> u32;
72 |
73 | #[wasm_bindgen(js_namespace = sc_internal)]
74 | fn _sc_internal_compiler_get_active_buffer_ranges(
75 | compiler: u32,
76 | id: u32,
77 | active_buffer_ranges: u32,
78 | size: u32,
79 | ) -> u32;
80 |
81 | #[wasm_bindgen(js_namespace = sc_internal)]
82 | fn _sc_internal_compiler_get_cleansed_entry_point_name(
83 | compiler: u32,
84 | original_entry_point_name: u32,
85 | execution_model: u32,
86 | compiled_entry_point_name: u32,
87 | ) -> u32;
88 |
89 | #[wasm_bindgen(js_namespace = sc_internal)]
90 | fn _sc_internal_compiler_get_shader_resources(compiler: u32, shader_resources: u32) -> u32;
91 |
92 | #[wasm_bindgen(js_namespace = sc_internal)]
93 | fn _sc_internal_compiler_get_specialization_constants(
94 | compiler: u32,
95 | constants: u32,
96 | size: u32,
97 | ) -> u32;
98 |
99 | #[wasm_bindgen(js_namespace = sc_internal)]
100 | fn _sc_internal_compiler_set_scalar_constant(
101 | compiler: u32,
102 | id: u32,
103 | constant_high_bits: u32,
104 | constant_low_bits: u32,
105 | ) -> u32;
106 |
107 | #[wasm_bindgen(js_namespace = sc_internal)]
108 | fn _sc_internal_compiler_get_type(compiler: u32, id: u32, spirv_type: u32) -> u32;
109 |
110 | #[wasm_bindgen(js_namespace = sc_internal)]
111 | fn _sc_internal_compiler_get_member_name(compiler: u32, id: u32, index: u32, name: u32) -> u32;
112 |
113 | #[wasm_bindgen(js_namespace = sc_internal)]
114 | fn _sc_internal_compiler_get_member_decoration(
115 | compiler: u32,
116 | id: u32,
117 | index: u32,
118 | decoration: u32,
119 | result: u32,
120 | ) -> u32;
121 |
122 | #[wasm_bindgen(js_namespace = sc_internal)]
123 | fn _sc_internal_compiler_set_member_decoration(
124 | compiler: u32,
125 | id: u32,
126 | index: u32,
127 | decoration: u32,
128 | argument: u32,
129 | ) -> u32;
130 |
131 | #[wasm_bindgen(js_namespace = sc_internal)]
132 | fn _sc_internal_compiler_get_declared_struct_size(compiler: u32, id: u32, result: u32) -> u32;
133 |
134 | #[wasm_bindgen(js_namespace = sc_internal)]
135 | fn _sc_internal_compiler_get_declared_struct_member_size(
136 | compiler: u32,
137 | id: u32,
138 | index: u32,
139 | result: u32,
140 | ) -> u32;
141 |
142 | #[wasm_bindgen(js_namespace = sc_internal)]
143 | fn _sc_internal_compiler_rename_interface_variable(
144 | compiler: u32,
145 | resources: u32,
146 | resources_size: u32,
147 | location: u32,
148 | name: u32,
149 | ) -> u32;
150 |
151 | #[wasm_bindgen(js_namespace = sc_internal)]
152 | fn _sc_internal_compiler_get_work_group_size_specialization_constants(
153 | compiler: u32,
154 | constants: u32,
155 | ) -> u32;
156 |
157 | #[wasm_bindgen(js_namespace = sc_internal)]
158 | fn _sc_internal_compiler_set_entry_point(compiler: u32, name: u32, execution_model: u32)
159 | -> u32;
160 |
161 | #[wasm_bindgen(js_namespace = sc_internal)]
162 | fn _sc_internal_compiler_compile(compiler: u32, shader: u32) -> u32;
163 |
164 | #[wasm_bindgen(js_namespace = sc_internal)]
165 | fn _sc_internal_compiler_delete(compiler: u32) -> u32;
166 |
167 | #[wasm_bindgen(js_namespace = sc_internal)]
168 | fn _sc_internal_free_pointer(pointer: u32) -> u32;
169 | }
170 |
171 | fn map_internal_result(result: u32) -> bindings::ScInternalResult {
172 | match result {
173 | 0 => bindings::ScInternalResult::Success,
174 | 1 => bindings::ScInternalResult::Unhandled,
175 | 2 => bindings::ScInternalResult::CompilationError,
176 | _ => unreachable!(),
177 | }
178 | }
179 |
180 | pub fn sc_internal_get_latest_exception_message(
181 | message: *mut *const ::std::os::raw::c_char,
182 | ) -> bindings::ScInternalResult {
183 | // This is unhandled for now
184 | // Exceptions are disabled and assertions are used instead
185 | bindings::ScInternalResult::Success
186 | }
187 |
188 | pub fn sc_internal_compiler_glsl_new(
189 | compiler: *mut *mut bindings::ScInternalCompilerGlsl,
190 | ir: *const u32,
191 | size: usize,
192 | ) -> bindings::ScInternalResult {
193 | let spirv_bytes = size * (U32_SIZE as usize);
194 | unsafe {
195 | let spirv = std::slice::from_raw_parts(ir as *const u8, spirv_bytes);
196 | let module = emscripten::get_module();
197 | let spirv_ptr = module.allocate(spirv_bytes as u32);
198 | module.set_from_u8_slice(spirv_ptr, spirv);
199 | let compiler_ptr_to_ptr = module.allocate(U32_SIZE);
200 | let result = map_internal_result(_sc_internal_compiler_glsl_new(
201 | compiler_ptr_to_ptr.as_offset(),
202 | spirv_ptr.as_offset(),
203 | size as u32,
204 | ));
205 | *compiler = module.get_u32(compiler_ptr_to_ptr) as *mut bindings::ScInternalCompilerGlsl;
206 | module.free(compiler_ptr_to_ptr);
207 | module.free(spirv_ptr);
208 | result
209 | }
210 | }
211 |
212 | pub fn sc_internal_compiler_glsl_set_options(
213 | compiler: *const bindings::ScInternalCompilerGlsl,
214 | options: *const bindings::ScGlslCompilerOptions,
215 | ) -> bindings::ScInternalResult {
216 | // For native usage, we expect Rust to manage the memory of options
217 | // For web usage, we have to copy it to the Emscripten heap temporarily
218 | // Alternatively, we could allow C++ and Emscripten to provide a pointer, then fill out
219 | // the struct fields on the Rust side instead - this already happens in some of the bindings
220 | let module = emscripten::get_module();
221 | let compiler_options_size = std::mem::size_of::();
222 |
223 | unsafe {
224 | let bytes = std::slice::from_raw_parts(options as *const u8, compiler_options_size);
225 | let copied_options_ptr = module.allocate(compiler_options_size as u32);
226 | module.set_from_u8_slice(copied_options_ptr, bytes);
227 | let result = map_internal_result(_sc_internal_compiler_glsl_set_options(
228 | compiler as u32,
229 | copied_options_ptr.as_offset(),
230 | ));
231 | module.free(copied_options_ptr);
232 | result
233 | }
234 | }
235 |
236 | pub fn sc_internal_compiler_glsl_build_combined_image_samplers(
237 | compiler: *const bindings::ScInternalCompilerBase,
238 | ) -> bindings::ScInternalResult {
239 | map_internal_result(_sc_internal_compiler_glsl_build_combined_image_samplers(
240 | compiler as u32,
241 | ))
242 | }
243 |
244 | pub fn sc_internal_compiler_glsl_get_combined_image_samplers(
245 | compiler: *const bindings::ScInternalCompilerBase,
246 | samplers: *mut *const bindings::ScCombinedImageSampler,
247 | size: *mut usize,
248 | ) -> bindings::ScInternalResult {
249 | let module = emscripten::get_module();
250 | unsafe {
251 | let samplers_ptr_to_ptr = module.allocate(U32_SIZE);
252 | let size_ptr = module.allocate(U32_SIZE);
253 | let result = map_internal_result(_sc_internal_compiler_glsl_get_combined_image_samplers(
254 | compiler as u32,
255 | samplers_ptr_to_ptr.as_offset(),
256 | size_ptr.as_offset(),
257 | ));
258 |
259 | *samplers = module.get_u32(samplers_ptr_to_ptr) as *const bindings::ScCombinedImageSampler;
260 | *size = module.get_u32(size_ptr) as usize;
261 |
262 | module.free(samplers_ptr_to_ptr);
263 | module.free(size_ptr);
264 |
265 | result
266 | }
267 | }
268 |
269 | pub fn sc_internal_compiler_glsl_add_header_line(
270 | compiler: *const bindings::ScInternalCompilerBase,
271 | str: *const ::std::os::raw::c_char,
272 | ) -> bindings::ScInternalResult {
273 | let module = emscripten::get_module();
274 | unsafe {
275 | let str_bytes = CStr::from_ptr(str).to_bytes();
276 | let str_ptr = module.allocate(str_bytes.len() as u32);
277 | module.set_from_u8_slice(str_ptr, str_bytes);
278 | let result = map_internal_result(_sc_internal_compiler_glsl_add_header_line(
279 | compiler as u32,
280 | str_ptr.as_offset(),
281 | ));
282 | module.free(str_ptr);
283 | result
284 | }
285 | }
286 |
287 | pub fn sc_internal_compiler_glsl_flatten_buffer_block(
288 | compiler: *const bindings::ScInternalCompilerBase,
289 | id: u32,
290 | ) -> bindings::ScInternalResult {
291 | let module = emscripten::get_module();
292 | unsafe {
293 | let result = map_internal_result(_sc_internal_compiler_glsl_flatten_buffer_block(
294 | compiler as u32,
295 | id,
296 | ));
297 | result
298 | }
299 | }
300 |
301 | pub fn sc_internal_compiler_get_decoration(
302 | compiler: *const bindings::ScInternalCompilerBase,
303 | result: *mut u32,
304 | id: u32,
305 | decoration: bindings::spv::Decoration,
306 | ) -> bindings::ScInternalResult {
307 | let module = emscripten::get_module();
308 | unsafe {
309 | let result_ptr = module.allocate(U32_SIZE);
310 | let ret = map_internal_result(_sc_internal_compiler_get_decoration(
311 | compiler as u32,
312 | result_ptr.as_offset(),
313 | id,
314 | decoration as u32,
315 | ));
316 | *result = module.get_u32(result_ptr) as u32;
317 | module.free(result_ptr);
318 | ret
319 | }
320 | }
321 |
322 | pub fn sc_internal_compiler_set_decoration(
323 | compiler: *const bindings::ScInternalCompilerBase,
324 | id: u32,
325 | decoration: bindings::spv::Decoration,
326 | argument: u32,
327 | ) -> bindings::ScInternalResult {
328 | map_internal_result(_sc_internal_compiler_set_decoration(
329 | compiler as u32,
330 | id,
331 | decoration as u32,
332 | argument,
333 | ))
334 | }
335 |
336 | pub fn sc_internal_compiler_unset_decoration(
337 | compiler: *const bindings::ScInternalCompilerBase,
338 | id: u32,
339 | decoration: bindings::spv::Decoration,
340 | ) -> bindings::ScInternalResult {
341 | map_internal_result(_sc_internal_compiler_unset_decoration(
342 | compiler as u32,
343 | id,
344 | decoration as u32,
345 | ))
346 | }
347 |
348 | pub fn sc_internal_compiler_get_name(
349 | compiler: *const bindings::ScInternalCompilerBase,
350 | id: u32,
351 | name: *mut *const ::std::os::raw::c_char,
352 | ) -> bindings::ScInternalResult {
353 | let module = emscripten::get_module();
354 | unsafe {
355 | let name_ptr_to_ptr = module.allocate(U32_SIZE);
356 | let result = map_internal_result(_sc_internal_compiler_get_name(
357 | compiler as u32,
358 | id,
359 | name_ptr_to_ptr.as_offset(),
360 | ));
361 | let name_ptr = module.get_u32(name_ptr_to_ptr);
362 | *name = name_ptr as *const ::std::os::raw::c_char;
363 | module.free(name_ptr_to_ptr);
364 | result
365 | }
366 | }
367 |
368 | pub fn sc_internal_compiler_set_name(
369 | compiler: *const bindings::ScInternalCompilerBase,
370 | id: u32,
371 | name: *const ::std::os::raw::c_char,
372 | ) -> bindings::ScInternalResult {
373 | let module = emscripten::get_module();
374 | unsafe {
375 | let name_bytes = CStr::from_ptr(name).to_bytes();
376 | let name_ptr = module.allocate(name_bytes.len() as u32);
377 | module.set_from_u8_slice(name_ptr, name_bytes);
378 | let result = map_internal_result(_sc_internal_compiler_set_name(
379 | compiler as u32,
380 | id,
381 | name_ptr.as_offset(),
382 | ));
383 | module.free(name_ptr);
384 | result
385 | }
386 | }
387 |
388 | pub fn sc_internal_compiler_set_member_name(
389 | compiler: *const bindings::ScInternalCompilerBase,
390 | id: u32,
391 | index: u32,
392 | name: *const ::std::os::raw::c_char,
393 | ) -> bindings::ScInternalResult {
394 | let module = emscripten::get_module();
395 | unsafe {
396 | let name_bytes = CStr::from_ptr(name).to_bytes();
397 | let name_ptr = module.allocate(name_bytes.len() as u32);
398 | module.set_from_u8_slice(name_ptr, name_bytes);
399 | let result = map_internal_result(_sc_internal_compiler_set_member_name(
400 | compiler as u32,
401 | id,
402 | index,
403 | name_ptr.as_offset(),
404 | ));
405 | module.free(name_ptr);
406 | result
407 | }
408 | }
409 |
410 | pub fn sc_internal_compiler_get_entry_points(
411 | compiler: *const bindings::ScInternalCompilerBase,
412 | entry_points: *mut *mut bindings::ScEntryPoint,
413 | size: *mut usize,
414 | ) -> bindings::ScInternalResult {
415 | let module = emscripten::get_module();
416 | unsafe {
417 | let entry_points_ptr_to_ptr = module.allocate(U32_SIZE);
418 | let size_ptr = module.allocate(U32_SIZE);
419 |
420 | let result = map_internal_result(_sc_internal_compiler_get_entry_points(
421 | compiler as u32,
422 | entry_points_ptr_to_ptr.as_offset(),
423 | size_ptr.as_offset(),
424 | ));
425 |
426 | *entry_points = module.get_u32(entry_points_ptr_to_ptr) as *mut bindings::ScEntryPoint;
427 | *size = module.get_u32(size_ptr) as usize;
428 |
429 | module.free(size_ptr);
430 | module.free(entry_points_ptr_to_ptr);
431 |
432 | result
433 | }
434 | }
435 |
436 | pub fn sc_internal_compiler_get_active_buffer_ranges(
437 | compiler: *const bindings::ScInternalCompilerBase,
438 | id: u32,
439 | active_buffer_ranges: *mut *mut bindings::ScBufferRange,
440 | size: *mut usize,
441 | ) -> bindings::ScInternalResult {
442 | let module = emscripten::get_module();
443 | unsafe {
444 | let active_buffer_ranges_ptr_to_ptr = module.allocate(U32_SIZE);
445 | let size_ptr = module.allocate(U32_SIZE);
446 |
447 | let result = map_internal_result(_sc_internal_compiler_get_active_buffer_ranges(
448 | compiler as u32,
449 | id,
450 | active_buffer_ranges_ptr_to_ptr.as_offset(),
451 | size_ptr.as_offset(),
452 | ));
453 |
454 | *active_buffer_ranges =
455 | module.get_u32(active_buffer_ranges_ptr_to_ptr) as *mut bindings::ScBufferRange;
456 | *size = module.get_u32(size_ptr) as usize;
457 |
458 | module.free(size_ptr);
459 | module.free(active_buffer_ranges_ptr_to_ptr);
460 |
461 | result
462 | }
463 | }
464 |
465 | pub fn sc_internal_compiler_get_cleansed_entry_point_name(
466 | compiler: *const bindings::ScInternalCompilerBase,
467 | original_entry_point_name: *const ::std::os::raw::c_char,
468 | execution_model: bindings::spv::ExecutionModel,
469 | compiled_entry_point_name: *mut *const ::std::os::raw::c_char,
470 | ) -> bindings::ScInternalResult {
471 | let module = emscripten::get_module();
472 | unsafe {
473 | let original_name_bytes = CStr::from_ptr(original_entry_point_name).to_bytes_with_nul();
474 | let original_name_ptr = module.allocate(original_name_bytes.len() as u32);
475 | module.set_from_u8_slice(original_name_ptr, original_name_bytes);
476 |
477 | let compiled_name_ptr_to_ptr = module.allocate(U32_SIZE);
478 | let result = map_internal_result(_sc_internal_compiler_get_cleansed_entry_point_name(
479 | compiler as u32,
480 | original_name_ptr.as_offset(),
481 | execution_model as u32,
482 | compiled_name_ptr_to_ptr.as_offset(),
483 | ));
484 | let compiled_name_ptr = module.get_u32(compiled_name_ptr_to_ptr);
485 | *compiled_entry_point_name = compiled_name_ptr as *const ::std::os::raw::c_char;
486 |
487 | module.free(compiled_name_ptr_to_ptr);
488 | module.free(original_name_ptr);
489 |
490 | result
491 | }
492 | }
493 |
494 | pub fn sc_internal_compiler_get_shader_resources(
495 | compiler: *const bindings::ScInternalCompilerBase,
496 | shader_resources: *mut bindings::ScShaderResources,
497 | ) -> bindings::ScInternalResult {
498 | let module = emscripten::get_module();
499 | unsafe {
500 | let num_bytes = std::mem::size_of::();
501 | let shader_resources_ptr = module.allocate(num_bytes as u32);
502 | let result = map_internal_result(_sc_internal_compiler_get_shader_resources(
503 | compiler as u32,
504 | shader_resources_ptr.as_offset(),
505 | ));
506 | module.read_bytes_into_pointer_while(
507 | shader_resources_ptr,
508 | |byte, bytes_read| bytes_read < num_bytes,
509 | false,
510 | shader_resources as *mut u8,
511 | );
512 | module.free(shader_resources_ptr);
513 | result
514 | }
515 | }
516 |
517 | pub fn sc_internal_compiler_get_specialization_constants(
518 | compiler: *const bindings::ScInternalCompilerBase,
519 | constants: *mut *mut bindings::ScSpecializationConstant,
520 | size: *mut usize,
521 | ) -> bindings::ScInternalResult {
522 | let module = emscripten::get_module();
523 | unsafe {
524 | let constants_ptr_to_ptr = module.allocate(U32_SIZE);
525 | let constants_size_ptr = module.allocate(U32_SIZE);
526 | let result = map_internal_result(_sc_internal_compiler_get_specialization_constants(
527 | compiler as u32,
528 | constants_ptr_to_ptr.as_offset(),
529 | constants_size_ptr.as_offset() as u32,
530 | ));
531 | *constants =
532 | module.get_u32(constants_ptr_to_ptr) as *mut bindings::ScSpecializationConstant;
533 | *size = module.get_u32(constants_size_ptr) as usize;
534 | module.free(constants_size_ptr);
535 | module.free(constants_ptr_to_ptr);
536 | result
537 | }
538 | }
539 |
540 | pub fn sc_internal_compiler_set_scalar_constant(
541 | compiler: *const bindings::ScInternalCompilerBase,
542 | id: u32,
543 | constant_high_bits: u32,
544 | constant_low_bits: u32,
545 | ) -> bindings::ScInternalResult {
546 | map_internal_result(_sc_internal_compiler_set_scalar_constant(
547 | compiler as u32,
548 | id,
549 | constant_high_bits,
550 | constant_low_bits,
551 | ))
552 | }
553 |
554 | pub fn sc_internal_compiler_get_type(
555 | compiler: *const bindings::ScInternalCompilerBase,
556 | id: u32,
557 | spirv_type: *mut *const bindings::ScType,
558 | ) -> bindings::ScInternalResult {
559 | let module = emscripten::get_module();
560 | unsafe {
561 | let type_ptr_to_ptr = module.allocate(U32_SIZE);
562 | let result = map_internal_result(_sc_internal_compiler_get_type(
563 | compiler as u32,
564 | id,
565 | type_ptr_to_ptr.as_offset(),
566 | ));
567 | let type_ptr = module.get_u32(type_ptr_to_ptr);
568 | *spirv_type = type_ptr as *const bindings::ScType;
569 | module.free(type_ptr_to_ptr);
570 | result
571 | }
572 | }
573 |
574 | pub fn sc_internal_compiler_get_member_name(
575 | compiler: *const bindings::ScInternalCompilerBase,
576 | id: u32,
577 | index: u32,
578 | name: *mut *const ::std::os::raw::c_char,
579 | ) -> bindings::ScInternalResult {
580 | let module = emscripten::get_module();
581 | unsafe {
582 | let name_ptr_to_ptr = module.allocate(U32_SIZE);
583 | let result = map_internal_result(_sc_internal_compiler_get_member_name(
584 | compiler as u32,
585 | id,
586 | index,
587 | name_ptr_to_ptr.as_offset(),
588 | ));
589 | let name_ptr = module.get_u32(name_ptr_to_ptr);
590 | *name = name_ptr as *const ::std::os::raw::c_char;
591 | module.free(name_ptr_to_ptr);
592 | result
593 | }
594 | }
595 |
596 | pub fn sc_internal_compiler_get_member_decoration(
597 | compiler: *const bindings::ScInternalCompilerBase,
598 | id: u32,
599 | index: u32,
600 | decoration: bindings::spv::Decoration,
601 | result: *mut u32,
602 | ) -> bindings::ScInternalResult {
603 | let module = emscripten::get_module();
604 | unsafe {
605 | let result_ptr = module.allocate(U32_SIZE);
606 | let ret = map_internal_result(_sc_internal_compiler_get_member_decoration(
607 | compiler as u32,
608 | id,
609 | index,
610 | decoration as u32,
611 | result_ptr.as_offset(),
612 | ));
613 | *result = module.get_u32(result_ptr) as u32;
614 | module.free(result_ptr);
615 | ret
616 | }
617 | }
618 |
619 | pub fn sc_internal_compiler_set_member_decoration(
620 | compiler: *const bindings::ScInternalCompilerBase,
621 | id: u32,
622 | index: u32,
623 | decoration: bindings::spv::Decoration,
624 | argument: u32,
625 | ) -> bindings::ScInternalResult {
626 | map_internal_result(_sc_internal_compiler_set_member_decoration(
627 | compiler as u32,
628 | id,
629 | index,
630 | decoration as u32,
631 | argument,
632 | ))
633 | }
634 |
635 | pub fn sc_internal_compiler_get_declared_struct_size(
636 | compiler: *const bindings::ScInternalCompilerBase,
637 | id: u32,
638 | result: *mut u32,
639 | ) -> bindings::ScInternalResult {
640 | let module = emscripten::get_module();
641 | unsafe {
642 | let result_ptr = module.allocate(U32_SIZE);
643 | let ret = map_internal_result(_sc_internal_compiler_get_declared_struct_size(
644 | compiler as u32,
645 | id,
646 | result_ptr.as_offset(),
647 | ));
648 | *result = module.get_u32(result_ptr) as u32;
649 | module.free(result_ptr);
650 | ret
651 | }
652 | }
653 |
654 | pub fn sc_internal_compiler_get_declared_struct_member_size(
655 | compiler: *const bindings::ScInternalCompilerBase,
656 | id: u32,
657 | index: u32,
658 | result: *mut u32,
659 | ) -> bindings::ScInternalResult {
660 | let module = emscripten::get_module();
661 | unsafe {
662 | let result_ptr = module.allocate(U32_SIZE);
663 | let ret = map_internal_result(_sc_internal_compiler_get_declared_struct_member_size(
664 | compiler as u32,
665 | id,
666 | index,
667 | result_ptr.as_offset(),
668 | ));
669 | *result = module.get_u32(result_ptr) as u32;
670 | module.free(result_ptr);
671 | ret
672 | }
673 | }
674 |
675 | pub fn sc_internal_compiler_rename_interface_variable(
676 | compiler: *const bindings::ScInternalCompilerBase,
677 | resources: *const bindings::ScResource,
678 | resources_size: usize,
679 | location: u32,
680 | name: *const ::std::os::raw::c_char,
681 | ) -> bindings::ScInternalResult {
682 | let module = emscripten::get_module();
683 | unsafe {
684 | let mut resources_copied = std::slice::from_raw_parts(resources, resources_size).to_vec();
685 |
686 | for mut resource in &mut resources_copied {
687 | // Update resource name to point to Emscripten heap instead
688 | let resource_name_bytes = CStr::from_ptr(resource.name).to_bytes();
689 | let resource_name_ptr = module.allocate(resource_name_bytes.len() as u32);
690 | module.set_from_u8_slice(resource_name_ptr, resource_name_bytes);
691 | resource.name = resource_name_ptr.as_offset() as *mut std::os::raw::c_char;
692 | }
693 |
694 | let resources_ptr = module.allocate(std::mem::size_of::() as u32);
695 | module.set_from_u8_slice(
696 | resources_ptr,
697 | std::slice::from_raw_parts(
698 | resources_copied.as_ptr() as *const u8,
699 | resources_size * std::mem::size_of::(),
700 | ),
701 | );
702 | let name_bytes = CStr::from_ptr(name).to_bytes();
703 | let name_ptr = module.allocate(name_bytes.len() as u32);
704 | module.set_from_u8_slice(name_ptr, name_bytes);
705 | let result = map_internal_result(_sc_internal_compiler_rename_interface_variable(
706 | compiler as u32,
707 | resources_ptr.as_offset(),
708 | resources_size as u32,
709 | location,
710 | name_ptr.as_offset(),
711 | ));
712 |
713 | for resource in resources_copied {
714 | module.free(emscripten::Pointer::from_offset(resource.name as u32));
715 | }
716 |
717 | module.free(name_ptr);
718 | result
719 | }
720 | }
721 |
722 | pub fn sc_internal_compiler_get_work_group_size_specialization_constants(
723 | compiler: *const bindings::ScInternalCompilerBase,
724 | constants: *mut *mut bindings::ScSpecializationConstant,
725 | ) -> bindings::ScInternalResult {
726 | let module = emscripten::get_module();
727 | let constants_length = 3; // x, y, z
728 | unsafe {
729 | let constants_ptr_to_ptr = module.allocate(
730 | std::mem::size_of::() as u32 * constants_length,
731 | );
732 | let result = map_internal_result(
733 | _sc_internal_compiler_get_work_group_size_specialization_constants(
734 | compiler as u32,
735 | constants_ptr_to_ptr.as_offset(),
736 | ),
737 | );
738 | let constants_ptr = module.get_u32(constants_ptr_to_ptr);
739 | *constants = constants_ptr as *mut bindings::ScSpecializationConstant;
740 | module.free(constants_ptr_to_ptr);
741 | result
742 | }
743 | }
744 |
745 | pub fn sc_internal_compiler_set_entry_point(
746 | compiler: *const bindings::ScInternalCompilerBase,
747 | name: *const ::std::os::raw::c_char,
748 | execution_model: bindings::spv::ExecutionModel,
749 | ) -> bindings::ScInternalResult {
750 | let module = emscripten::get_module();
751 | unsafe {
752 | let name_bytes = CStr::from_ptr(name).to_bytes_with_nul();
753 | let name_ptr = module.allocate(name_bytes.len() as u32);
754 | module.set_from_u8_slice(name_ptr, name_bytes);
755 |
756 | let result = map_internal_result(_sc_internal_compiler_set_entry_point(
757 | compiler as u32,
758 | name_ptr.as_offset(),
759 | execution_model as u32,
760 | ));
761 |
762 | module.free(name_ptr);
763 |
764 | result
765 | }
766 | }
767 |
768 | pub fn sc_internal_compiler_compile(
769 | compiler: *const bindings::ScInternalCompilerBase,
770 | shader: *mut *const ::std::os::raw::c_char,
771 | ) -> bindings::ScInternalResult {
772 | let module = emscripten::get_module();
773 | unsafe {
774 | let shader_ptr_to_ptr = module.allocate(U32_SIZE);
775 | let result = map_internal_result(_sc_internal_compiler_compile(
776 | compiler as u32,
777 | shader_ptr_to_ptr.as_offset(),
778 | ));
779 | let shader_ptr = module.get_u32(shader_ptr_to_ptr);
780 | *shader = shader_ptr as *const ::std::os::raw::c_char;
781 | module.free(shader_ptr_to_ptr);
782 | result
783 | }
784 | }
785 |
786 | pub fn sc_internal_compiler_delete(
787 | compiler: *mut bindings::ScInternalCompilerBase,
788 | ) -> bindings::ScInternalResult {
789 | map_internal_result(_sc_internal_compiler_delete(compiler as u32))
790 | }
791 |
792 | pub fn sc_internal_free_pointer(
793 | pointer: *mut ::std::os::raw::c_void,
794 | ) -> bindings::ScInternalResult {
795 | map_internal_result(_sc_internal_free_pointer(pointer as u32))
796 | }
797 |
--------------------------------------------------------------------------------
/spirv_cross/src/emscripten.rs:
--------------------------------------------------------------------------------
1 | //! Utilities for interacting with the generated Emscripten module.
2 | //! Most functionality is generalized, but some functionality is specific to SPIRV-Cross.
3 |
4 | use crate::{bindings, ErrorCode};
5 | use js_sys::{global, Object, Reflect, Uint32Array, Uint8Array};
6 | use wasm_bindgen::prelude::*;
7 |
8 | #[wasm_bindgen]
9 | extern "C" {
10 | // Raw Emscripten bindings
11 | #[wasm_bindgen(js_namespace = sc_internal)]
12 | fn _malloc(size: u32) -> u32;
13 |
14 | #[wasm_bindgen(js_namespace = sc_internal)]
15 | fn _free(offset: u32);
16 | }
17 |
18 | pub fn get_module() -> Module {
19 | const MODULE_NAME: &'static str = "sc_internal";
20 | let module = Reflect::get(&global(), &JsValue::from_str(MODULE_NAME))
21 | .unwrap()
22 | .into();
23 | Module { module }
24 | }
25 |
26 | const U32_SIZE: u32 = std::mem::size_of::() as u32;
27 |
28 | fn get_value(object: &Object, key: &str) -> T
29 | where
30 | T: std::convert::From,
31 | {
32 | Reflect::get(object, &JsValue::from_str(key))
33 | .unwrap()
34 | .into()
35 | }
36 |
37 | /// An Emscripten pointer.
38 | /// Internally stores an offset to a location on the Emscripten `u8` heap.
39 | #[derive(Clone, Copy)]
40 | pub struct Pointer {
41 | offset: u32,
42 | }
43 |
44 | impl Pointer {
45 | pub fn from_offset(offset: u32) -> Self {
46 | Pointer { offset }
47 | }
48 |
49 | pub fn as_offset(&self) -> u32 {
50 | self.offset
51 | }
52 | }
53 |
54 | pub struct Module {
55 | module: Object,
56 | }
57 |
58 | impl Module {
59 | /// Allocate memory on the heap.
60 | pub unsafe fn allocate(&self, byte_len: u32) -> Pointer {
61 | Pointer {
62 | offset: _malloc(byte_len),
63 | }
64 | }
65 |
66 | pub unsafe fn free(&self, pointer: Pointer) {
67 | _free(pointer.as_offset())
68 | }
69 |
70 | // Read a `u32` value from the heap.
71 | pub unsafe fn get_u32(&self, pointer: Pointer) -> u32 {
72 | let offset = &JsValue::from_f64((pointer.offset / U32_SIZE) as f64);
73 | // TODO: Remove Reflect
74 | Reflect::get(&self.heap_u32(), offset)
75 | .unwrap()
76 | .as_f64()
77 | .unwrap() as u32
78 | }
79 |
80 | /// Set memory on the heap to `bytes`.
81 | pub unsafe fn set_from_u8_typed_array(&self, pointer: Pointer, bytes: Uint8Array) {
82 | let buffer: JsValue = self.heap_u8().buffer().into();
83 | let memory =
84 | Uint8Array::new_with_byte_offset_and_length(&buffer, pointer.offset, bytes.length());
85 | memory.set(&bytes, 0);
86 | }
87 |
88 | /// Set memory on the heap to `bytes`.
89 | pub unsafe fn set_from_u8_slice(&self, pointer: Pointer, bytes: &[u8]) {
90 | self.set_from_u8_typed_array(pointer, Uint8Array::view(bytes));
91 | }
92 |
93 | fn heap_u8(&self) -> Uint8Array {
94 | const HEAP_U8: &'static str = "HEAPU8";
95 | get_value(&self.module, HEAP_U8)
96 | }
97 |
98 | fn heap_u32(&self) -> Uint32Array {
99 | const HEAP_U32: &'static str = "HEAPU32";
100 | get_value(&self.module, HEAP_U32)
101 | }
102 |
103 | /// Clones all bytes from the heap into a `Vec` while `should_continue` returns `true`.
104 | /// Optionally include the last byte (i.e. to support peeking the final byte for nul-terminated strings).
105 | pub unsafe fn read_bytes_into_vec_while(
106 | &self,
107 | pointer: Pointer,
108 | should_continue: F,
109 | include_last_byte: bool,
110 | ) -> Vec
111 | where
112 | F: Fn(u8, usize) -> bool,
113 | {
114 | let mut bytes = Vec::new();
115 | let heap = &self.heap_u8();
116 | let start_offset = pointer.offset as usize;
117 | loop {
118 | let bytes_read = bytes.len();
119 | let offset = &JsValue::from_f64((start_offset + bytes_read) as f64);
120 | let byte = Reflect::get(heap, offset).unwrap().as_f64().unwrap() as u8;
121 | if should_continue(byte, bytes_read) {
122 | bytes.push(byte);
123 | continue;
124 | }
125 | if include_last_byte {
126 | bytes.push(byte);
127 | }
128 | break;
129 | }
130 | bytes
131 | }
132 |
133 | /// Clones all bytes from the heap into the pointer provided while `should_continue` returns `true`.
134 | /// Optionally include the last byte (i.e. to support peeking the final byte for nul-terminated strings).
135 | /// Assumes the memory at the pointer is large enough to hold all bytes read (based on when `should_continue` terminates).
136 | pub unsafe fn read_bytes_into_pointer_while(
137 | &self,
138 | pointer: Pointer,
139 | should_continue: F,
140 | include_last_byte: bool,
141 | into_pointer: *mut u8,
142 | ) where
143 | F: Fn(u8, usize) -> bool,
144 | {
145 | let heap = &self.heap_u8();
146 | let start_offset = pointer.offset as usize;
147 | let mut bytes_read = 0;
148 | loop {
149 | let offset = &JsValue::from_f64((start_offset + bytes_read) as f64);
150 | let byte = Reflect::get(heap, offset).unwrap().as_f64().unwrap() as u8;
151 | if should_continue(byte, bytes_read) {
152 | *into_pointer.offset(bytes_read as isize) = byte;
153 | bytes_read += 1;
154 | continue;
155 | }
156 | if include_last_byte {
157 | *into_pointer.offset(bytes_read as isize) = byte;
158 | }
159 | break;
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/spirv_cross/src/glsl.rs:
--------------------------------------------------------------------------------
1 | use crate::bindings as br;
2 | use crate::ptr_util::read_into_vec_from_ptr;
3 | use crate::{compiler, spirv, ErrorCode};
4 | use std::ffi::CString;
5 | use std::marker::PhantomData;
6 | use std::ptr;
7 |
8 | /// A GLSL target.
9 | #[derive(Debug, Clone)]
10 | pub enum Target {}
11 |
12 | pub struct TargetData {
13 | combined_image_samplers_built: bool,
14 | }
15 |
16 | impl spirv::Target for Target {
17 | type Data = TargetData;
18 | }
19 |
20 | #[allow(non_snake_case, non_camel_case_types)]
21 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
22 | #[non_exhaustive]
23 | pub enum Version {
24 | V1_10,
25 | V1_20,
26 | V1_30,
27 | V1_40,
28 | V1_50,
29 | V3_30,
30 | V4_00,
31 | V4_10,
32 | V4_20,
33 | V4_30,
34 | V4_40,
35 | V4_50,
36 | V4_60,
37 | V1_00Es,
38 | V3_00Es,
39 | V3_10Es,
40 | V3_20Es,
41 | }
42 |
43 | #[derive(Debug, Clone)]
44 | pub struct CompilerVertexOptions {
45 | pub invert_y: bool,
46 | pub transform_clip_space: bool,
47 | pub support_nonzero_base_instance: bool,
48 | }
49 |
50 | impl Default for CompilerVertexOptions {
51 | fn default() -> CompilerVertexOptions {
52 | CompilerVertexOptions {
53 | invert_y: false,
54 | transform_clip_space: false,
55 | support_nonzero_base_instance: true,
56 | }
57 | }
58 | }
59 |
60 | // Note: These values should match with `CompilerGLSL::Options::Precision`.
61 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
62 | #[repr(u8)]
63 | pub enum Precision {
64 | DontCare = 0,
65 | Low = 1,
66 | Medium = 2,
67 | High = 3,
68 | }
69 |
70 | #[derive(Debug, Clone)]
71 | pub struct CompilerFragmentOptions {
72 | pub default_float_precision: Precision,
73 | pub default_int_precision: Precision,
74 | }
75 |
76 | impl Default for CompilerFragmentOptions {
77 | fn default() -> CompilerFragmentOptions {
78 | CompilerFragmentOptions {
79 | default_float_precision: Precision::Medium,
80 | default_int_precision: Precision::High,
81 | }
82 | }
83 | }
84 |
85 | /// GLSL compiler options.
86 | #[non_exhaustive]
87 | #[derive(Debug, Clone)]
88 | pub struct CompilerOptions {
89 | pub version: Version,
90 | pub force_temporary: bool,
91 | pub vulkan_semantics: bool,
92 | pub separate_shader_objects: bool,
93 | pub flatten_multidimensional_arrays: bool,
94 | pub enable_420_pack_extension: bool,
95 | pub emit_push_constant_as_uniform_buffer: bool,
96 | pub emit_uniform_buffer_as_plain_uniforms: bool,
97 | pub emit_line_directives: bool,
98 | pub enable_storage_image_qualifier_deduction: bool,
99 | /// Whether to force all uninitialized variables to be initialized to zero.
100 | pub force_zero_initialized_variables: bool,
101 | pub vertex: CompilerVertexOptions,
102 | pub fragment: CompilerFragmentOptions,
103 | /// The name and execution model of the entry point to use. If no entry
104 | /// point is specified, then the first entry point found will be used.
105 | pub entry_point: Option<(String, spirv::ExecutionModel)>,
106 | }
107 |
108 | impl Default for CompilerOptions {
109 | fn default() -> CompilerOptions {
110 | CompilerOptions {
111 | version: Version::V4_50,
112 | force_temporary: false,
113 | vulkan_semantics: false,
114 | separate_shader_objects: false,
115 | flatten_multidimensional_arrays: false,
116 | enable_420_pack_extension: true,
117 | emit_push_constant_as_uniform_buffer: false,
118 | emit_uniform_buffer_as_plain_uniforms: false,
119 | emit_line_directives: false,
120 | enable_storage_image_qualifier_deduction: true,
121 | force_zero_initialized_variables: false,
122 | vertex: CompilerVertexOptions::default(),
123 | fragment: CompilerFragmentOptions::default(),
124 | entry_point: None,
125 | }
126 | }
127 | }
128 |
129 | impl spirv::Parse for spirv::Ast {
130 | fn parse(module: &spirv::Module) -> Result {
131 | let compiler = {
132 | let mut compiler = ptr::null_mut();
133 | unsafe {
134 | check!(br::sc_internal_compiler_glsl_new(
135 | &mut compiler,
136 | module.words.as_ptr() as *const u32,
137 | module.words.len() as usize,
138 | ));
139 | }
140 |
141 | compiler::Compiler {
142 | sc_compiler: compiler,
143 | target_data: TargetData {
144 | combined_image_samplers_built: false,
145 | },
146 | has_been_compiled: false,
147 | }
148 | };
149 |
150 | Ok(spirv::Ast {
151 | compiler,
152 | target_type: PhantomData,
153 | })
154 | }
155 | }
156 |
157 | impl spirv::Compile for spirv::Ast {
158 | type CompilerOptions = CompilerOptions;
159 |
160 | /// Set GLSL compiler specific compilation settings.
161 | fn set_compiler_options(&mut self, options: &CompilerOptions) -> Result<(), ErrorCode> {
162 | if let Some((name, model)) = &options.entry_point {
163 | let name_raw = CString::new(name.as_str()).map_err(|_| ErrorCode::Unhandled)?;
164 | let model = model.as_raw();
165 | unsafe {
166 | check!(br::sc_internal_compiler_set_entry_point(
167 | self.compiler.sc_compiler,
168 | name_raw.as_ptr(),
169 | model,
170 | ));
171 | }
172 |
173 | self.compiler.target_data.combined_image_samplers_built = false;
174 | };
175 |
176 | use self::Version::*;
177 | let (version, es) = match options.version {
178 | V1_10 => (1_10, false),
179 | V1_20 => (1_20, false),
180 | V1_30 => (1_30, false),
181 | V1_40 => (1_40, false),
182 | V1_50 => (1_50, false),
183 | V3_30 => (3_30, false),
184 | V4_00 => (4_00, false),
185 | V4_10 => (4_10, false),
186 | V4_20 => (4_20, false),
187 | V4_30 => (4_30, false),
188 | V4_40 => (4_40, false),
189 | V4_50 => (4_50, false),
190 | V4_60 => (4_60, false),
191 | V1_00Es => (1_00, true),
192 | V3_00Es => (3_00, true),
193 | V3_10Es => (3_10, true),
194 | V3_20Es => (3_20, true),
195 | };
196 | let raw_options = br::ScGlslCompilerOptions {
197 | vertex_invert_y: options.vertex.invert_y,
198 | vertex_transform_clip_space: options.vertex.transform_clip_space,
199 | version,
200 | es,
201 | vertex_support_nonzero_base_instance: options.vertex.support_nonzero_base_instance,
202 | fragment_default_float_precision: options.fragment.default_float_precision as u8,
203 | fragment_default_int_precision: options.fragment.default_int_precision as u8,
204 | force_temporary: options.force_temporary,
205 | vulkan_semantics: options.vulkan_semantics,
206 | separate_shader_objects: options.separate_shader_objects,
207 | flatten_multidimensional_arrays: options.flatten_multidimensional_arrays,
208 | enable_420_pack_extension: options.enable_420_pack_extension,
209 | emit_push_constant_as_uniform_buffer: options.emit_push_constant_as_uniform_buffer,
210 | emit_uniform_buffer_as_plain_uniforms: options.emit_uniform_buffer_as_plain_uniforms,
211 | emit_line_directives: options.emit_line_directives,
212 | enable_storage_image_qualifier_deduction: options
213 | .enable_storage_image_qualifier_deduction,
214 | force_zero_initialized_variables: options.force_zero_initialized_variables,
215 | };
216 | unsafe {
217 | check!(br::sc_internal_compiler_glsl_set_options(
218 | self.compiler.sc_compiler,
219 | &raw_options,
220 | ));
221 | }
222 |
223 | Ok(())
224 | }
225 |
226 | /// Generate GLSL shader from the AST.
227 | fn compile(&mut self) -> Result {
228 | self.build_combined_image_samplers()?;
229 | self.compiler.compile()
230 | }
231 | }
232 |
233 | impl spirv::Ast {
234 | pub fn build_combined_image_samplers(&mut self) -> Result<(), ErrorCode> {
235 | unsafe {
236 | if !self.compiler.target_data.combined_image_samplers_built {
237 | check!(br::sc_internal_compiler_glsl_build_combined_image_samplers(
238 | self.compiler.sc_compiler
239 | ));
240 | self.compiler.target_data.combined_image_samplers_built = true
241 | }
242 | }
243 |
244 | Ok(())
245 | }
246 |
247 | pub fn get_combined_image_samplers(
248 | &mut self,
249 | ) -> Result, ErrorCode> {
250 | self.build_combined_image_samplers()?;
251 | unsafe {
252 | let mut samplers_raw: *const br::ScCombinedImageSampler = std::ptr::null();
253 | let mut samplers_raw_length: usize = 0;
254 |
255 | check!(br::sc_internal_compiler_glsl_get_combined_image_samplers(
256 | self.compiler.sc_compiler,
257 | &mut samplers_raw as _,
258 | &mut samplers_raw_length as _,
259 | ));
260 |
261 | let samplers = read_into_vec_from_ptr(samplers_raw, samplers_raw_length)
262 | .iter()
263 | .map(|sc| spirv::CombinedImageSampler {
264 | combined_id: sc.combined_id,
265 | image_id: sc.image_id,
266 | sampler_id: sc.sampler_id,
267 | })
268 | .collect();
269 |
270 | Ok(samplers)
271 | }
272 | }
273 |
274 | pub fn add_header_line(&mut self, line: &str) -> Result<(), ErrorCode> {
275 | unsafe {
276 | let line = CString::new(line);
277 | match line {
278 | Ok(line) => {
279 | check!(br::sc_internal_compiler_glsl_add_header_line(
280 | self.compiler.sc_compiler,
281 | line.as_ptr(),
282 | ));
283 | }
284 | _ => return Err(ErrorCode::Unhandled),
285 | }
286 |
287 | Ok(())
288 | }
289 | }
290 |
291 | pub fn flatten_buffer_block(&mut self, id: u32) -> Result<(), ErrorCode> {
292 | unsafe {
293 | check!(br::sc_internal_compiler_glsl_flatten_buffer_block(
294 | self.compiler.sc_compiler,
295 | id,
296 | ));
297 |
298 | Ok(())
299 | }
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/spirv_cross/src/hlsl.rs:
--------------------------------------------------------------------------------
1 | use crate::bindings as br;
2 | use crate::{compiler, spirv, ErrorCode};
3 | use std::ffi::CString;
4 | use std::marker::PhantomData;
5 | use std::ptr;
6 |
7 | pub use crate::bindings::root::ScHlslRootConstant as RootConstant;
8 |
9 | /// A HLSL target.
10 | #[derive(Debug, Clone)]
11 | pub enum Target {}
12 |
13 | impl spirv::Target for Target {
14 | type Data = ();
15 | }
16 |
17 | /// A HLSL shader model version.
18 | #[allow(non_snake_case, non_camel_case_types)]
19 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
20 | #[non_exhaustive]
21 | pub enum ShaderModel {
22 | V3_0,
23 | V4_0,
24 | V4_0L9_0,
25 | V4_0L9_1,
26 | V4_0L9_3,
27 | V4_1,
28 | V5_0,
29 | V5_1,
30 | V6_0,
31 | }
32 |
33 | #[allow(non_snake_case, non_camel_case_types)]
34 | impl ShaderModel {
35 | fn as_raw(self) -> i32 {
36 | use self::ShaderModel::*;
37 | match self {
38 | V3_0 => 30,
39 | V4_0 => 40,
40 | V4_0L9_0 => 40,
41 | V4_0L9_1 => 40,
42 | V4_0L9_3 => 40,
43 | V4_1 => 41,
44 | V5_0 => 50,
45 | V5_1 => 51,
46 | V6_0 => 60,
47 | }
48 | }
49 | }
50 |
51 | #[derive(Debug, Clone)]
52 | pub struct CompilerVertexOptions {
53 | pub invert_y: bool,
54 | pub transform_clip_space: bool,
55 | }
56 |
57 | impl Default for CompilerVertexOptions {
58 | fn default() -> CompilerVertexOptions {
59 | CompilerVertexOptions {
60 | invert_y: false,
61 | transform_clip_space: false,
62 | }
63 | }
64 | }
65 |
66 | /// HLSL compiler options.
67 | #[non_exhaustive]
68 | #[derive(Debug, Clone)]
69 | pub struct CompilerOptions {
70 | pub shader_model: ShaderModel,
71 | /// Support point size builtin but ignore the value.
72 | pub point_size_compat: bool,
73 | /// Support point coordinate builtin but ignore the value.
74 | pub point_coord_compat: bool,
75 | pub vertex: CompilerVertexOptions,
76 | pub force_storage_buffer_as_uav: bool,
77 | pub nonwritable_uav_texture_as_srv: bool,
78 | /// Whether to force all uninitialized variables to be initialized to zero.
79 | pub force_zero_initialized_variables: bool,
80 | /// The name and execution model of the entry point to use. If no entry
81 | /// point is specified, then the first entry point found will be used.
82 | pub entry_point: Option<(String, spirv::ExecutionModel)>,
83 | }
84 |
85 | impl Default for CompilerOptions {
86 | fn default() -> CompilerOptions {
87 | CompilerOptions {
88 | shader_model: ShaderModel::V3_0,
89 | point_size_compat: false,
90 | point_coord_compat: false,
91 | vertex: CompilerVertexOptions::default(),
92 | force_storage_buffer_as_uav: false,
93 | nonwritable_uav_texture_as_srv: false,
94 | force_zero_initialized_variables: false,
95 | entry_point: None,
96 | }
97 | }
98 | }
99 |
100 | impl spirv::Parse for spirv::Ast {
101 | fn parse(module: &spirv::Module) -> Result {
102 | let compiler = {
103 | let mut compiler = ptr::null_mut();
104 | unsafe {
105 | check!(br::sc_internal_compiler_hlsl_new(
106 | &mut compiler,
107 | module.words.as_ptr() as *const u32,
108 | module.words.len() as usize,
109 | ));
110 | }
111 |
112 | compiler::Compiler {
113 | sc_compiler: compiler,
114 | target_data: (),
115 | has_been_compiled: false,
116 | }
117 | };
118 |
119 | Ok(spirv::Ast {
120 | compiler,
121 | target_type: PhantomData,
122 | })
123 | }
124 | }
125 |
126 | impl spirv::Compile for spirv::Ast {
127 | type CompilerOptions = CompilerOptions;
128 |
129 | /// Set HLSL compiler specific compilation settings.
130 | fn set_compiler_options(&mut self, options: &CompilerOptions) -> Result<(), ErrorCode> {
131 | if let Some((name, model)) = &options.entry_point {
132 | let name_raw = CString::new(name.as_str()).map_err(|_| ErrorCode::Unhandled)?;
133 | let model = model.as_raw();
134 | unsafe {
135 | check!(br::sc_internal_compiler_set_entry_point(
136 | self.compiler.sc_compiler,
137 | name_raw.as_ptr(),
138 | model,
139 | ));
140 | }
141 | };
142 | let raw_options = br::ScHlslCompilerOptions {
143 | shader_model: options.shader_model.as_raw(),
144 | point_size_compat: options.point_size_compat,
145 | point_coord_compat: options.point_coord_compat,
146 | vertex_invert_y: options.vertex.invert_y,
147 | vertex_transform_clip_space: options.vertex.transform_clip_space,
148 | force_storage_buffer_as_uav: options.force_storage_buffer_as_uav,
149 | nonwritable_uav_texture_as_srv: options.nonwritable_uav_texture_as_srv,
150 | force_zero_initialized_variables: options.force_zero_initialized_variables,
151 | };
152 | unsafe {
153 | check!(br::sc_internal_compiler_hlsl_set_options(
154 | self.compiler.sc_compiler,
155 | &raw_options,
156 | ));
157 | }
158 |
159 | Ok(())
160 | }
161 |
162 | /// Generate HLSL shader from the AST.
163 | fn compile(&mut self) -> Result {
164 | self.compiler.compile()
165 | }
166 | }
167 |
168 | impl spirv::Ast {
169 | ///
170 | pub fn set_root_constant_layout(&mut self, layout: Vec) -> Result<(), ErrorCode> {
171 | unsafe {
172 | check!(br::sc_internal_compiler_hlsl_set_root_constant_layout(
173 | self.compiler.sc_compiler,
174 | layout.as_ptr(),
175 | layout.len() as _,
176 | ));
177 | }
178 |
179 | Ok(())
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/spirv_cross/src/lib.rs:
--------------------------------------------------------------------------------
1 | #[cfg(target_arch = "wasm32")]
2 | macro_rules! check {
3 | ($check:expr) => {{
4 | $check
5 | }};
6 | }
7 |
8 | #[cfg(not(target_arch = "wasm32"))]
9 | macro_rules! check {
10 | ($check:expr) => {{
11 | let result = $check;
12 | if br::ScInternalResult::Success != result {
13 | if br::ScInternalResult::CompilationError == result {
14 | let mut message_ptr = ptr::null();
15 |
16 | if br::ScInternalResult::Success
17 | != br::sc_internal_get_latest_exception_message(&mut message_ptr)
18 | {
19 | return Err(ErrorCode::Unhandled);
20 | }
21 |
22 | let message = match std::ffi::CStr::from_ptr(message_ptr)
23 | .to_owned()
24 | .into_string()
25 | {
26 | Err(_) => return Err(ErrorCode::Unhandled),
27 | Ok(v) => v,
28 | };
29 |
30 | if br::ScInternalResult::Success
31 | != br::sc_internal_free_pointer(message_ptr as *mut std::os::raw::c_void)
32 | {
33 | return Err(ErrorCode::Unhandled);
34 | }
35 |
36 | return Err(ErrorCode::CompilationError(message));
37 | }
38 |
39 | return Err(ErrorCode::Unhandled);
40 | }
41 | }};
42 | }
43 |
44 | mod compiler;
45 |
46 | #[cfg(feature = "glsl")]
47 | pub mod glsl;
48 | #[cfg(all(feature = "hlsl", not(target_arch = "wasm32")))]
49 | pub mod hlsl;
50 | #[cfg(all(feature = "msl", not(target_arch = "wasm32")))]
51 | pub mod msl;
52 |
53 | pub mod spirv;
54 |
55 | #[cfg(target_arch = "wasm32")]
56 | pub(crate) mod emscripten;
57 | pub(crate) mod ptr_util;
58 |
59 | #[cfg(target_arch = "wasm32")]
60 | mod bindings_wasm_functions;
61 |
62 | #[cfg(target_arch = "wasm32")]
63 | mod bindings {
64 | #![allow(dead_code)]
65 | #![allow(non_upper_case_globals)]
66 | #![allow(non_camel_case_types)]
67 | #![allow(non_snake_case)]
68 | include!(concat!("bindings_wasm.rs"));
69 | pub use crate::bindings_wasm_functions::*;
70 | pub use root::*;
71 | }
72 |
73 | #[cfg(not(target_arch = "wasm32"))]
74 | mod bindings {
75 | #![allow(dead_code)]
76 | #![allow(non_upper_case_globals)]
77 | #![allow(non_camel_case_types)]
78 | #![allow(non_snake_case)]
79 | include!(concat!("bindings_native.rs"));
80 | pub use root::*;
81 | }
82 |
83 | #[derive(Clone, Debug, Hash, Eq, PartialEq)]
84 | pub enum ErrorCode {
85 | Unhandled,
86 | CompilationError(String),
87 | }
88 |
89 | impl std::fmt::Display for ErrorCode {
90 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
91 | write!(f, "{:?}", self)
92 | }
93 | }
94 |
95 | impl std::error::Error for ErrorCode {}
96 |
--------------------------------------------------------------------------------
/spirv_cross/src/msl.rs:
--------------------------------------------------------------------------------
1 | use crate::bindings as br;
2 | use crate::{compiler, spirv, ErrorCode};
3 |
4 | use std::collections::BTreeMap;
5 | use std::ffi::{CStr, CString};
6 | use std::marker::PhantomData;
7 | use std::ptr;
8 | use std::u8;
9 |
10 | /// A MSL target.
11 | #[derive(Debug, Clone)]
12 | pub enum Target {}
13 |
14 | pub struct TargetData {
15 | vertex_attribute_overrides: Vec,
16 | resource_binding_overrides: Vec,
17 | const_samplers: Vec,
18 | }
19 |
20 | impl spirv::Target for Target {
21 | type Data = TargetData;
22 | }
23 |
24 | /// Location of a vertex attribute to override
25 | #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
26 | pub struct VertexAttributeLocation(pub u32);
27 |
28 | /// Format of the vertex attribute
29 | #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
30 | pub enum Format {
31 | Other,
32 | Uint8,
33 | Uint16,
34 | }
35 |
36 | impl Format {
37 | fn as_raw(&self) -> br::spirv_cross::MSLShaderInputFormat {
38 | use self::Format::*;
39 | match self {
40 | Other => br::spirv_cross::MSLShaderInputFormat_MSL_SHADER_INPUT_FORMAT_OTHER,
41 | Uint8 => br::spirv_cross::MSLShaderInputFormat_MSL_SHADER_INPUT_FORMAT_UINT8,
42 | Uint16 => br::spirv_cross::MSLShaderInputFormat_MSL_SHADER_INPUT_FORMAT_UINT16,
43 | }
44 | }
45 | }
46 |
47 | /// Vertex attribute description for overriding
48 | #[derive(Debug, Clone, Hash, Eq, PartialEq)]
49 | pub struct VertexAttribute {
50 | pub buffer_id: u32,
51 | pub format: Format,
52 | pub built_in: Option,
53 | pub vecsize: u32,
54 | }
55 |
56 | /// Location of a resource binding to override
57 | #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
58 | pub struct ResourceBindingLocation {
59 | pub stage: spirv::ExecutionModel,
60 | pub desc_set: u32,
61 | pub binding: u32,
62 | }
63 |
64 | /// Resource binding description for overriding
65 | #[derive(Debug, Clone, Hash, Eq, PartialEq)]
66 | pub struct ResourceBinding {
67 | pub buffer_id: u32,
68 | pub texture_id: u32,
69 | pub sampler_id: u32,
70 | pub count: u32,
71 | }
72 |
73 | /// Location of a sampler binding to override
74 | #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
75 | pub struct SamplerLocation {
76 | pub desc_set: u32,
77 | pub binding: u32,
78 | }
79 |
80 | #[repr(C)]
81 | #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
82 | pub enum SamplerCoord {
83 | Normalized = 0,
84 | Pixel = 1,
85 | }
86 |
87 | #[repr(C)]
88 | #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
89 | pub enum SamplerFilter {
90 | Nearest = 0,
91 | Linear = 1,
92 | }
93 |
94 | #[repr(C)]
95 | #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
96 | pub enum SamplerMipFilter {
97 | None = 0,
98 | Nearest = 1,
99 | Linear = 2,
100 | }
101 |
102 | #[repr(C)]
103 | #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
104 | pub enum SamplerAddress {
105 | ClampToZero = 0,
106 | ClampToEdge = 1,
107 | ClampToBorder = 2,
108 | Repeat = 3,
109 | MirroredRepeat = 4,
110 | }
111 |
112 | #[repr(C)]
113 | #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
114 | pub enum SamplerCompareFunc {
115 | Never = 0,
116 | Less = 1,
117 | LessEqual = 2,
118 | Greater = 3,
119 | GreaterEqual = 4,
120 | Equal = 5,
121 | NotEqual = 6,
122 | Always = 7,
123 | }
124 |
125 | #[repr(C)]
126 | #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
127 | pub enum SamplerBorderColor {
128 | TransparentBlack = 0,
129 | OpaqueBlack = 1,
130 | OpaqueWhite = 2,
131 | }
132 |
133 | #[repr(transparent)]
134 | #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
135 | pub struct LodBase16(u8);
136 |
137 | impl LodBase16 {
138 | pub const ZERO: Self = LodBase16(0);
139 | pub const MAX: Self = LodBase16(!0);
140 | }
141 |
142 | impl From for LodBase16 {
143 | fn from(v: f32) -> Self {
144 | LodBase16((v * 16.0).max(0.0).min(u8::MAX as f32) as u8)
145 | }
146 | }
147 |
148 | impl Into for LodBase16 {
149 | fn into(self) -> f32 {
150 | self.0 as f32 / 16.0
151 | }
152 | }
153 |
154 | /// MSL format resolution.
155 | #[repr(C)]
156 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
157 | pub enum FormatResolution {
158 | _444 = 0,
159 | _422 = 1,
160 | _420 = 2,
161 | }
162 |
163 | /// MSL chroma location.
164 | #[repr(C)]
165 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
166 | pub enum ChromaLocation {
167 | CositedEven = 0,
168 | LocationMidpoint = 1,
169 | }
170 |
171 | /// MSL component swizzle.
172 | #[repr(C)]
173 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
174 | pub enum ComponentSwizzle {
175 | Identity = 0,
176 | Zero = 1,
177 | One = 2,
178 | R = 3,
179 | G = 4,
180 | B = 5,
181 | A = 6,
182 | }
183 |
184 | /// Data fully defining a constant sampler.
185 | #[derive(Debug, Clone, Hash, Eq, PartialEq)]
186 | pub struct SamplerData {
187 | pub coord: SamplerCoord,
188 | pub min_filter: SamplerFilter,
189 | pub mag_filter: SamplerFilter,
190 | pub mip_filter: SamplerMipFilter,
191 | pub s_address: SamplerAddress,
192 | pub t_address: SamplerAddress,
193 | pub r_address: SamplerAddress,
194 | pub compare_func: SamplerCompareFunc,
195 | pub border_color: SamplerBorderColor,
196 | pub lod_clamp_min: LodBase16,
197 | pub lod_clamp_max: LodBase16,
198 | pub max_anisotropy: i32,
199 | // Sampler YCbCr conversion parameters
200 | pub planes: u32,
201 | pub resolution: FormatResolution,
202 | pub chroma_filter: SamplerFilter,
203 | pub x_chroma_offset: ChromaLocation,
204 | pub y_chroma_offset: ChromaLocation,
205 | pub swizzle: [ComponentSwizzle; 4],
206 | pub ycbcr_conversion_enable: bool,
207 | pub ycbcr_model: SamplerYCbCrModelConversion,
208 | pub ycbcr_range: SamplerYCbCrRange,
209 | pub bpc: u32,
210 | }
211 |
212 | /// A MSL sampler YCbCr model conversion.
213 | #[repr(C)]
214 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
215 | pub enum SamplerYCbCrModelConversion {
216 | RgbIdentity = 0,
217 | YCbCrIdentity = 1,
218 | YCbCrBt709 = 2,
219 | YCbCrBt601 = 3,
220 | YCbCrBt2020 = 4,
221 | }
222 |
223 | /// A MSL sampler YCbCr range.
224 | #[repr(C)]
225 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
226 | pub enum SamplerYCbCrRange {
227 | ItuFull = 0,
228 | ItuNarrow = 1,
229 | }
230 |
231 | /// A MSL shader platform.
232 | #[repr(u8)]
233 | #[allow(non_snake_case, non_camel_case_types)]
234 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
235 | pub enum Platform {
236 | iOS = 0,
237 | macOS = 1,
238 | }
239 |
240 | /// A MSL shader model version.
241 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
242 | #[non_exhaustive]
243 | pub enum Version {
244 | V1_0,
245 | V1_1,
246 | V1_2,
247 | V2_0,
248 | V2_1,
249 | V2_2,
250 | V2_3,
251 | }
252 |
253 | impl Version {
254 | fn as_raw(self) -> u32 {
255 | use self::Version::*;
256 | match self {
257 | V1_0 => 10000,
258 | V1_1 => 10100,
259 | V1_2 => 10200,
260 | V2_0 => 20000,
261 | V2_1 => 20100,
262 | V2_2 => 20200,
263 | V2_3 => 20300,
264 | }
265 | }
266 | }
267 |
268 | #[derive(Debug, Clone, Hash, Eq, PartialEq)]
269 | pub struct CompilerVertexOptions {
270 | pub invert_y: bool,
271 | pub transform_clip_space: bool,
272 | }
273 |
274 | impl Default for CompilerVertexOptions {
275 | fn default() -> Self {
276 | CompilerVertexOptions {
277 | invert_y: false,
278 | transform_clip_space: false,
279 | }
280 | }
281 | }
282 |
283 | /// MSL compiler options.
284 | #[non_exhaustive]
285 | #[derive(Debug, Clone, Hash, Eq, PartialEq)]
286 | pub struct CompilerOptions {
287 | /// The target platform.
288 | pub platform: Platform,
289 | /// The target MSL version.
290 | pub version: Version,
291 | /// Vertex compiler options.
292 | pub vertex: CompilerVertexOptions,
293 | /// The buffer index to use for swizzle.
294 | pub swizzle_buffer_index: u32,
295 | // The buffer index to use for indirect params.
296 | pub indirect_params_buffer_index: u32,
297 | /// The buffer index to use for output.
298 | pub output_buffer_index: u32,
299 | /// The buffer index to use for patch output.
300 | pub patch_output_buffer_index: u32,
301 | /// The buffer index to use for tessellation factor.
302 | pub tessellation_factor_buffer_index: u32,
303 | /// The buffer index to use for buffer size.
304 | pub buffer_size_buffer_index: u32,
305 | /// Whether the built-in point size should be enabled.
306 | pub enable_point_size_builtin: bool,
307 | /// Whether rasterization should be enabled.
308 | pub enable_rasterization: bool,
309 | /// Whether to capture output to buffer.
310 | pub capture_output_to_buffer: bool,
311 | /// Whether to swizzle texture samples.
312 | pub swizzle_texture_samples: bool,
313 | /// Whether to place the origin of tessellation domain shaders in the lower left.
314 | pub tessellation_domain_origin_lower_left: bool,
315 | /// Whether to enable use of argument buffers (only compatible with MSL 2.0).
316 | pub enable_argument_buffers: bool,
317 | /// Whether to pad fragment output to have at least the number of components as the render pass.
318 | pub pad_fragment_output_components: bool,
319 | /// MSL resource bindings overrides.
320 | pub resource_binding_overrides: BTreeMap,
321 | /// MSL vertex attribute overrides.
322 | pub vertex_attribute_overrides: BTreeMap,
323 | /// MSL const sampler mappings.
324 | pub const_samplers: BTreeMap,
325 | /// Whether to force native arrays (useful to workaround issues on some hardware).
326 | pub force_native_arrays: bool,
327 | /// Whether to force all uninitialized variables to be initialized to zero.
328 | pub force_zero_initialized_variables: bool,
329 | /// Whether to force always emit resources which are part of argument buffers
330 | pub force_active_argument_buffer_resources: bool,
331 | /// The name and execution model of the entry point to use. If no entry
332 | /// point is specified, then the first entry point found will be used.
333 | pub entry_point: Option<(String, spirv::ExecutionModel)>,
334 | }
335 |
336 | impl Default for CompilerOptions {
337 | fn default() -> Self {
338 | CompilerOptions {
339 | platform: Platform::macOS,
340 | version: Version::V1_2,
341 | vertex: CompilerVertexOptions::default(),
342 | swizzle_buffer_index: 30,
343 | indirect_params_buffer_index: 29,
344 | output_buffer_index: 28,
345 | patch_output_buffer_index: 27,
346 | tessellation_factor_buffer_index: 26,
347 | buffer_size_buffer_index: 25,
348 | enable_point_size_builtin: true,
349 | enable_rasterization: true,
350 | capture_output_to_buffer: false,
351 | swizzle_texture_samples: false,
352 | tessellation_domain_origin_lower_left: false,
353 | enable_argument_buffers: false,
354 | pad_fragment_output_components: false,
355 | resource_binding_overrides: Default::default(),
356 | vertex_attribute_overrides: Default::default(),
357 | const_samplers: Default::default(),
358 | force_native_arrays: false,
359 | force_zero_initialized_variables: false,
360 | force_active_argument_buffer_resources: false,
361 | entry_point: None,
362 | }
363 | }
364 | }
365 |
366 | impl<'a> spirv::Parse for spirv::Ast {
367 | fn parse(module: &spirv::Module) -> Result {
368 | let mut sc_compiler = ptr::null_mut();
369 | unsafe {
370 | check!(br::sc_internal_compiler_msl_new(
371 | &mut sc_compiler,
372 | module.words.as_ptr(),
373 | module.words.len(),
374 | ));
375 | }
376 |
377 | Ok(spirv::Ast {
378 | compiler: compiler::Compiler {
379 | sc_compiler,
380 | target_data: TargetData {
381 | resource_binding_overrides: Vec::new(),
382 | vertex_attribute_overrides: Vec::new(),
383 | const_samplers: Vec::new(),
384 | },
385 | has_been_compiled: false,
386 | },
387 | target_type: PhantomData,
388 | })
389 | }
390 | }
391 |
392 | impl spirv::Compile for spirv::Ast {
393 | type CompilerOptions = CompilerOptions;
394 |
395 | /// Set MSL compiler specific compilation settings.
396 | fn set_compiler_options(&mut self, options: &CompilerOptions) -> Result<(), ErrorCode> {
397 | if let Some((name, model)) = &options.entry_point {
398 | let name_raw = CString::new(name.as_str()).map_err(|_| ErrorCode::Unhandled)?;
399 | let model = model.as_raw();
400 | unsafe {
401 | check!(br::sc_internal_compiler_set_entry_point(
402 | self.compiler.sc_compiler,
403 | name_raw.as_ptr(),
404 | model,
405 | ));
406 | }
407 | };
408 | let raw_options = br::ScMslCompilerOptions {
409 | vertex_invert_y: options.vertex.invert_y,
410 | vertex_transform_clip_space: options.vertex.transform_clip_space,
411 | platform: options.platform as _,
412 | version: options.version.as_raw(),
413 | enable_point_size_builtin: options.enable_point_size_builtin,
414 | disable_rasterization: !options.enable_rasterization,
415 | swizzle_buffer_index: options.swizzle_buffer_index,
416 | indirect_params_buffer_index: options.indirect_params_buffer_index,
417 | shader_output_buffer_index: options.output_buffer_index,
418 | shader_patch_output_buffer_index: options.patch_output_buffer_index,
419 | shader_tess_factor_buffer_index: options.tessellation_factor_buffer_index,
420 | buffer_size_buffer_index: options.buffer_size_buffer_index,
421 | capture_output_to_buffer: options.capture_output_to_buffer,
422 | swizzle_texture_samples: options.swizzle_texture_samples,
423 | tess_domain_origin_lower_left: options.tessellation_domain_origin_lower_left,
424 | argument_buffers: options.enable_argument_buffers,
425 | pad_fragment_output_components: options.pad_fragment_output_components,
426 | force_native_arrays: options.force_native_arrays,
427 | force_zero_initialized_variables: options.force_zero_initialized_variables,
428 | force_active_argument_buffer_resources: options.force_active_argument_buffer_resources,
429 | };
430 | unsafe {
431 | check!(br::sc_internal_compiler_msl_set_options(
432 | self.compiler.sc_compiler,
433 | &raw_options,
434 | ));
435 | }
436 |
437 | self.compiler.target_data.resource_binding_overrides.clear();
438 | self.compiler.target_data.resource_binding_overrides.extend(
439 | options.resource_binding_overrides.iter().map(|(loc, res)| {
440 | br::spirv_cross::MSLResourceBinding {
441 | stage: loc.stage.as_raw(),
442 | desc_set: loc.desc_set,
443 | binding: loc.binding,
444 | msl_buffer: res.buffer_id,
445 | msl_texture: res.texture_id,
446 | msl_sampler: res.sampler_id,
447 | count: res.count,
448 | }
449 | }),
450 | );
451 |
452 | self.compiler.target_data.vertex_attribute_overrides.clear();
453 | self.compiler.target_data.vertex_attribute_overrides.extend(
454 | options.vertex_attribute_overrides.iter().map(|(loc, vat)| {
455 | br::spirv_cross::MSLShaderInput {
456 | location: loc.0,
457 | format: vat.format.as_raw(),
458 | builtin: spirv::built_in_as_raw(vat.built_in),
459 | vecsize: vat.vecsize,
460 | }
461 | }),
462 | );
463 |
464 | self.compiler.target_data.const_samplers.clear();
465 | self.compiler
466 | .target_data
467 | .const_samplers
468 | .extend(options.const_samplers.iter().map(|(loc, data)| unsafe {
469 | use std::mem::transmute;
470 | br::ScMslConstSamplerMapping {
471 | desc_set: loc.desc_set,
472 | binding: loc.binding,
473 | sampler: br::spirv_cross::MSLConstexprSampler {
474 | coord: transmute(data.coord),
475 | min_filter: transmute(data.min_filter),
476 | mag_filter: transmute(data.mag_filter),
477 | mip_filter: transmute(data.mip_filter),
478 | s_address: transmute(data.s_address),
479 | t_address: transmute(data.t_address),
480 | r_address: transmute(data.r_address),
481 | compare_func: transmute(data.compare_func),
482 | border_color: transmute(data.border_color),
483 | lod_clamp_min: data.lod_clamp_min.into(),
484 | lod_clamp_max: data.lod_clamp_max.into(),
485 | max_anisotropy: data.max_anisotropy,
486 | compare_enable: data.compare_func != SamplerCompareFunc::Always,
487 | lod_clamp_enable: data.lod_clamp_min != LodBase16::ZERO
488 | || data.lod_clamp_max != LodBase16::MAX,
489 | anisotropy_enable: data.max_anisotropy != 0,
490 | bpc: data.bpc,
491 | chroma_filter: transmute(data.chroma_filter),
492 | planes: data.planes,
493 | resolution: transmute(data.resolution),
494 | swizzle: transmute(data.swizzle),
495 | x_chroma_offset: transmute(data.x_chroma_offset),
496 | y_chroma_offset: transmute(data.y_chroma_offset),
497 | ycbcr_conversion_enable: data.ycbcr_conversion_enable,
498 | ycbcr_model: transmute(data.ycbcr_model),
499 | ycbcr_range: transmute(data.ycbcr_range),
500 | },
501 | }
502 | }));
503 |
504 | Ok(())
505 | }
506 |
507 | /// Generate MSL shader from the AST.
508 | fn compile(&mut self) -> Result {
509 | self.compile_internal()
510 | }
511 | }
512 |
513 | impl spirv::Ast {
514 | fn compile_internal(&self) -> Result {
515 | let vat_overrides = &self.compiler.target_data.vertex_attribute_overrides;
516 | let res_overrides = &self.compiler.target_data.resource_binding_overrides;
517 | let const_samplers = &self.compiler.target_data.const_samplers;
518 | unsafe {
519 | let mut shader_ptr = ptr::null();
520 | check!(br::sc_internal_compiler_msl_compile(
521 | self.compiler.sc_compiler,
522 | &mut shader_ptr,
523 | vat_overrides.as_ptr(),
524 | vat_overrides.len(),
525 | res_overrides.as_ptr(),
526 | res_overrides.len(),
527 | const_samplers.as_ptr(),
528 | const_samplers.len(),
529 | ));
530 | let shader = match CStr::from_ptr(shader_ptr).to_str() {
531 | Ok(v) => v.to_owned(),
532 | Err(_) => return Err(ErrorCode::Unhandled),
533 | };
534 | check!(br::sc_internal_free_pointer(
535 | shader_ptr as *mut std::os::raw::c_void
536 | ));
537 | Ok(shader)
538 | }
539 | }
540 |
541 | pub fn is_rasterization_enabled(&self) -> Result {
542 | unsafe {
543 | let mut is_disabled = false;
544 | check!(br::sc_internal_compiler_msl_get_is_rasterization_disabled(
545 | self.compiler.sc_compiler,
546 | &mut is_disabled
547 | ));
548 | Ok(!is_disabled)
549 | }
550 | }
551 | }
552 |
553 | // TODO: Generate with bindgen
554 | pub const ARGUMENT_BUFFER_BINDING: u32 = !3;
555 |
--------------------------------------------------------------------------------
/spirv_cross/src/ptr_util.rs:
--------------------------------------------------------------------------------
1 | //! Pointer utilities to abstract over native pointer access (i.e. `*const T`)
2 | //! and Emscripten pointer access (i.e. `u32` offset into the Emscripten heap).
3 |
4 | use crate::ErrorCode;
5 | #[allow(unused_imports)]
6 | use std::{
7 | slice,
8 | ffi::CStr
9 | };
10 |
11 | #[cfg(target_arch = "wasm32")]
12 | use crate::emscripten;
13 |
14 | pub unsafe fn read_string_from_ptr(ptr: *const std::os::raw::c_char) -> Result {
15 | #[cfg(not(target_arch = "wasm32"))]
16 | let string = CStr::from_ptr(ptr)
17 | .to_owned()
18 | .into_string()
19 | .map_err(|_| ErrorCode::Unhandled);
20 | #[cfg(target_arch = "wasm32")]
21 | let string = {
22 | let bytes = emscripten::get_module().read_bytes_into_vec_while(
23 | emscripten::Pointer::from_offset(ptr as u32),
24 | |byte, _| 0 != byte,
25 | false,
26 | );
27 | String::from_utf8(bytes).map_err(|_| ErrorCode::Unhandled)
28 | };
29 | string
30 | }
31 |
32 | pub unsafe fn read_from_ptr(ptr: *const T) -> T {
33 | #[cfg(not(target_arch = "wasm32"))]
34 | let value = ptr.read();
35 | #[cfg(target_arch = "wasm32")]
36 | let value = {
37 | let num_bytes_to_read = std::mem::size_of::();
38 | let mut t_val: T = std::mem::uninitialized();
39 | let t_ptr = &mut t_val as *mut T as *mut u8;
40 | let bytes = emscripten::get_module().read_bytes_into_vec_while(
41 | emscripten::Pointer::from_offset(ptr as u32),
42 | |_, bytes_read| bytes_read < num_bytes_to_read,
43 | false,
44 | );
45 | for (offset, byte) in bytes.iter().enumerate() {
46 | *t_ptr.offset(offset as isize) = *byte;
47 | }
48 | t_val
49 | };
50 | value
51 | }
52 |
53 | pub unsafe fn read_into_vec_from_ptr(ptr: *const T, size: usize) -> Vec {
54 | #[cfg(not(target_arch = "wasm32"))]
55 | let values = slice::from_raw_parts(ptr, size).to_vec();
56 | #[cfg(target_arch = "wasm32")]
57 | let values = (0..size)
58 | .map(|offset| read_from_ptr(ptr.add(offset)))
59 | .collect();
60 | values
61 | }
62 |
--------------------------------------------------------------------------------
/spirv_cross/src/spirv.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashSet;
2 | use crate::{compiler, ErrorCode};
3 | use std::marker::PhantomData;
4 |
5 | /// A stage or compute kernel.
6 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
7 | pub struct CombinedImageSampler {
8 | pub combined_id: u32,
9 | pub image_id: u32,
10 | pub sampler_id: u32,
11 | }
12 |
13 | /// A stage or compute kernel.
14 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
15 | pub enum ExecutionModel {
16 | Vertex,
17 | TessellationControl,
18 | TessellationEvaluation,
19 | Geometry,
20 | Fragment,
21 | GlCompute,
22 | Kernel,
23 | }
24 |
25 | /// A decoration.
26 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
27 | pub enum Decoration {
28 | RelaxedPrecision,
29 | SpecId,
30 | Block,
31 | BufferBlock,
32 | RowMajor,
33 | ColMajor,
34 | ArrayStride,
35 | MatrixStride,
36 | GlslShared,
37 | GlslPacked,
38 | CPacked,
39 | BuiltIn,
40 | NoPerspective,
41 | Flat,
42 | Patch,
43 | Centroid,
44 | Sample,
45 | Invariant,
46 | Restrict,
47 | Aliased,
48 | Volatile,
49 | Constant,
50 | Coherent,
51 | NonWritable,
52 | NonReadable,
53 | Uniform,
54 | SaturatedConversion,
55 | Stream,
56 | Location,
57 | Component,
58 | Index,
59 | Binding,
60 | DescriptorSet,
61 | Offset,
62 | XfbBuffer,
63 | XfbStride,
64 | FuncParamAttr,
65 | FpRoundingMode,
66 | FpFastMathMode,
67 | LinkageAttributes,
68 | NoContraction,
69 | InputAttachmentIndex,
70 | Alignment,
71 | OverrideCoverageNv,
72 | PassthroughNv,
73 | ViewportRelativeNv,
74 | SecondaryViewportRelativeNv,
75 | }
76 |
77 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
78 | pub enum VertexAttributeStep {
79 | Vertex,
80 | Instance,
81 | }
82 |
83 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
84 | pub enum BuiltIn {
85 | Position,
86 | PointSize,
87 | ClipDistance,
88 | CullDistance,
89 | VertexId,
90 | InstanceId,
91 | PrimitiveId,
92 | InvocationId,
93 | Layer,
94 | ViewportIndex,
95 | TessLevelOuter,
96 | TessLevelInner,
97 | TessCoord,
98 | PatchVertices,
99 | FragCoord,
100 | PointCoord,
101 | FrontFacing,
102 | SampleId,
103 | SamplePosition,
104 | SampleMask,
105 | FragDepth,
106 | HelperInvocation,
107 | NumWorkgroups,
108 | WorkgroupSize,
109 | WorkgroupId,
110 | LocalInvocationId,
111 | GlobalInvocationId,
112 | LocalInvocationIndex,
113 | WorkDim,
114 | GlobalSize,
115 | EnqueuedWorkgroupSize,
116 | GlobalOffset,
117 | GlobalLinearId,
118 | SubgroupSize,
119 | SubgroupMaxSize,
120 | NumSubgroups,
121 | NumEnqueuedSubgroups,
122 | SubgroupId,
123 | SubgroupLocalInvocationId,
124 | VertexIndex,
125 | InstanceIndex,
126 | SubgroupEqMask,
127 | SubgroupGeMask,
128 | SubgroupGtMask,
129 | SubgroupLeMask,
130 | SubgroupLtMask,
131 | BaseVertex,
132 | BaseInstance,
133 | DrawIndex,
134 | DeviceIndex,
135 | ViewIndex,
136 | BaryCoordNoPerspAmd,
137 | BaryCoordNoPerspCentroidAmd,
138 | BaryCoordNoPerspSampleAmd,
139 | BaryCoordSmoothAmd,
140 | BaryCoordSmoothCentroidAmd,
141 | BaryCoordSmoothSampleAmd,
142 | BaryCoordPullModelAmd,
143 | FragStencilRefExt,
144 | ViewportMaskNv,
145 | SecondaryPositionNv,
146 | SecondaryViewportMaskNv,
147 | PositionPerViewNv,
148 | ViewportMaskPerViewNv,
149 | FullyCoveredExt,
150 | TaskCountNv,
151 | PrimitiveCountNv,
152 | PrimitiveIndicesNv,
153 | ClipDistancePerViewNv,
154 | CullDistancePerViewNv,
155 | LayerPerViewNv,
156 | MeshViewCountNv,
157 | MeshViewIndicesNv,
158 | BaryCoordNv,
159 | BaryCoordNoPerspNv,
160 | FragSizeExt,
161 | FragInvocationCountExt,
162 | LaunchIdNv,
163 | LaunchSizeNv,
164 | WorldRayOriginNv,
165 | WorldRayDirectionNv,
166 | ObjectRayOriginNv,
167 | ObjectRayDirectionNv,
168 | RayTminNv,
169 | RayTmaxNv,
170 | InstanceCustomIndexNv,
171 | ObjectToWorldNv,
172 | WorldToObjectNv,
173 | HitTNv,
174 | HitKindNv,
175 | IncomingRayFlagsNv,
176 | }
177 |
178 | #[cfg(feature = "msl")]
179 | pub(crate) fn built_in_as_raw(built_in: Option) -> crate::bindings::spv::BuiltIn {
180 | use crate::bindings as br;
181 | use BuiltIn::*;
182 | match built_in {
183 | None => br::spv::BuiltIn::BuiltInMax,
184 | Some(Position) => br::spv::BuiltIn::BuiltInPosition,
185 | Some(PointSize) => br::spv::BuiltIn::BuiltInPointSize,
186 | Some(ClipDistance) => br::spv::BuiltIn::BuiltInClipDistance,
187 | Some(CullDistance) => br::spv::BuiltIn::BuiltInCullDistance,
188 | Some(VertexId) => br::spv::BuiltIn::BuiltInVertexId,
189 | Some(InstanceId) => br::spv::BuiltIn::BuiltInInstanceId,
190 | Some(PrimitiveId) => br::spv::BuiltIn::BuiltInPrimitiveId,
191 | Some(InvocationId) => br::spv::BuiltIn::BuiltInInvocationId,
192 | Some(Layer) => br::spv::BuiltIn::BuiltInLayer,
193 | Some(ViewportIndex) => br::spv::BuiltIn::BuiltInViewportIndex,
194 | Some(TessLevelOuter) => br::spv::BuiltIn::BuiltInTessLevelOuter,
195 | Some(TessLevelInner) => br::spv::BuiltIn::BuiltInTessLevelInner,
196 | Some(TessCoord) => br::spv::BuiltIn::BuiltInTessCoord,
197 | Some(PatchVertices) => br::spv::BuiltIn::BuiltInPatchVertices,
198 | Some(FragCoord) => br::spv::BuiltIn::BuiltInFragCoord,
199 | Some(PointCoord) => br::spv::BuiltIn::BuiltInPointCoord,
200 | Some(FrontFacing) => br::spv::BuiltIn::BuiltInFrontFacing,
201 | Some(SampleId) => br::spv::BuiltIn::BuiltInSampleId,
202 | Some(SamplePosition) => br::spv::BuiltIn::BuiltInSamplePosition,
203 | Some(SampleMask) => br::spv::BuiltIn::BuiltInSampleMask,
204 | Some(FragDepth) => br::spv::BuiltIn::BuiltInFragDepth,
205 | Some(HelperInvocation) => br::spv::BuiltIn::BuiltInHelperInvocation,
206 | Some(NumWorkgroups) => br::spv::BuiltIn::BuiltInNumWorkgroups,
207 | Some(WorkgroupSize) => br::spv::BuiltIn::BuiltInWorkgroupSize,
208 | Some(WorkgroupId) => br::spv::BuiltIn::BuiltInWorkgroupId,
209 | Some(LocalInvocationId) => br::spv::BuiltIn::BuiltInLocalInvocationId,
210 | Some(GlobalInvocationId) => br::spv::BuiltIn::BuiltInGlobalInvocationId,
211 | Some(LocalInvocationIndex) => br::spv::BuiltIn::BuiltInLocalInvocationIndex,
212 | Some(WorkDim) => br::spv::BuiltIn::BuiltInWorkDim,
213 | Some(GlobalSize) => br::spv::BuiltIn::BuiltInGlobalSize,
214 | Some(EnqueuedWorkgroupSize) => br::spv::BuiltIn::BuiltInEnqueuedWorkgroupSize,
215 | Some(GlobalOffset) => br::spv::BuiltIn::BuiltInGlobalOffset,
216 | Some(GlobalLinearId) => br::spv::BuiltIn::BuiltInGlobalLinearId,
217 | Some(SubgroupSize) => br::spv::BuiltIn::BuiltInSubgroupSize,
218 | Some(SubgroupMaxSize) => br::spv::BuiltIn::BuiltInSubgroupMaxSize,
219 | Some(NumSubgroups) => br::spv::BuiltIn::BuiltInNumSubgroups,
220 | Some(NumEnqueuedSubgroups) => br::spv::BuiltIn::BuiltInNumEnqueuedSubgroups,
221 | Some(SubgroupId) => br::spv::BuiltIn::BuiltInSubgroupId,
222 | Some(SubgroupLocalInvocationId) => br::spv::BuiltIn::BuiltInSubgroupLocalInvocationId,
223 | Some(VertexIndex) => br::spv::BuiltIn::BuiltInVertexIndex,
224 | Some(InstanceIndex) => br::spv::BuiltIn::BuiltInInstanceIndex,
225 | Some(SubgroupEqMask) => br::spv::BuiltIn::BuiltInSubgroupEqMask,
226 | Some(SubgroupGeMask) => br::spv::BuiltIn::BuiltInSubgroupGeMask,
227 | Some(SubgroupGtMask) => br::spv::BuiltIn::BuiltInSubgroupGtMask,
228 | Some(SubgroupLeMask) => br::spv::BuiltIn::BuiltInSubgroupLeMask,
229 | Some(SubgroupLtMask) => br::spv::BuiltIn::BuiltInSubgroupLtMask,
230 | Some(BaseVertex) => br::spv::BuiltIn::BuiltInBaseVertex,
231 | Some(BaseInstance) => br::spv::BuiltIn::BuiltInBaseInstance,
232 | Some(DrawIndex) => br::spv::BuiltIn::BuiltInDrawIndex,
233 | Some(DeviceIndex) => br::spv::BuiltIn::BuiltInDeviceIndex,
234 | Some(ViewIndex) => br::spv::BuiltIn::BuiltInViewIndex,
235 | Some(BaryCoordNoPerspAmd) => br::spv::BuiltIn::BuiltInBaryCoordNoPerspAMD,
236 | Some(BaryCoordNoPerspCentroidAmd) => br::spv::BuiltIn::BuiltInBaryCoordNoPerspCentroidAMD,
237 | Some(BaryCoordNoPerspSampleAmd) => br::spv::BuiltIn::BuiltInBaryCoordNoPerspSampleAMD,
238 | Some(BaryCoordSmoothAmd) => br::spv::BuiltIn::BuiltInBaryCoordSmoothAMD,
239 | Some(BaryCoordSmoothCentroidAmd) => br::spv::BuiltIn::BuiltInBaryCoordSmoothCentroidAMD,
240 | Some(BaryCoordSmoothSampleAmd) => br::spv::BuiltIn::BuiltInBaryCoordSmoothSampleAMD,
241 | Some(BaryCoordPullModelAmd) => br::spv::BuiltIn::BuiltInBaryCoordPullModelAMD,
242 | Some(FragStencilRefExt) => br::spv::BuiltIn::BuiltInFragStencilRefEXT,
243 | Some(ViewportMaskNv) => br::spv::BuiltIn::BuiltInViewportMaskNV,
244 | Some(SecondaryPositionNv) => br::spv::BuiltIn::BuiltInSecondaryPositionNV,
245 | Some(SecondaryViewportMaskNv) => br::spv::BuiltIn::BuiltInSecondaryViewportMaskNV,
246 | Some(PositionPerViewNv) => br::spv::BuiltIn::BuiltInPositionPerViewNV,
247 | Some(ViewportMaskPerViewNv) => br::spv::BuiltIn::BuiltInViewportMaskPerViewNV,
248 | Some(FullyCoveredExt) => br::spv::BuiltIn::BuiltInFullyCoveredEXT,
249 | Some(TaskCountNv) => br::spv::BuiltIn::BuiltInTaskCountNV,
250 | Some(PrimitiveCountNv) => br::spv::BuiltIn::BuiltInPrimitiveCountNV,
251 | Some(PrimitiveIndicesNv) => br::spv::BuiltIn::BuiltInPrimitiveIndicesNV,
252 | Some(ClipDistancePerViewNv) => br::spv::BuiltIn::BuiltInClipDistancePerViewNV,
253 | Some(CullDistancePerViewNv) => br::spv::BuiltIn::BuiltInCullDistancePerViewNV,
254 | Some(LayerPerViewNv) => br::spv::BuiltIn::BuiltInLayerPerViewNV,
255 | Some(MeshViewCountNv) => br::spv::BuiltIn::BuiltInMeshViewCountNV,
256 | Some(MeshViewIndicesNv) => br::spv::BuiltIn::BuiltInMeshViewIndicesNV,
257 | Some(BaryCoordNv) => br::spv::BuiltIn::BuiltInBaryCoordNV,
258 | Some(BaryCoordNoPerspNv) => br::spv::BuiltIn::BuiltInBaryCoordNoPerspNV,
259 | Some(FragSizeExt) => br::spv::BuiltIn::BuiltInFragSizeEXT,
260 | Some(FragInvocationCountExt) => br::spv::BuiltIn::BuiltInFragInvocationCountEXT,
261 | Some(LaunchIdNv) => br::spv::BuiltIn::BuiltInLaunchIdNV,
262 | Some(LaunchSizeNv) => br::spv::BuiltIn::BuiltInLaunchSizeNV,
263 | Some(WorldRayOriginNv) => br::spv::BuiltIn::BuiltInWorldRayOriginNV,
264 | Some(WorldRayDirectionNv) => br::spv::BuiltIn::BuiltInWorldRayDirectionNV,
265 | Some(ObjectRayOriginNv) => br::spv::BuiltIn::BuiltInObjectRayOriginNV,
266 | Some(ObjectRayDirectionNv) => br::spv::BuiltIn::BuiltInObjectRayDirectionNV,
267 | Some(RayTminNv) => br::spv::BuiltIn::BuiltInRayTminNV,
268 | Some(RayTmaxNv) => br::spv::BuiltIn::BuiltInRayTmaxNV,
269 | Some(InstanceCustomIndexNv) => br::spv::BuiltIn::BuiltInInstanceCustomIndexNV,
270 | Some(ObjectToWorldNv) => br::spv::BuiltIn::BuiltInObjectToWorldNV,
271 | Some(WorldToObjectNv) => br::spv::BuiltIn::BuiltInWorldToObjectNV,
272 | Some(HitTNv) => br::spv::BuiltIn::BuiltInHitTNV,
273 | Some(HitKindNv) => br::spv::BuiltIn::BuiltInHitKindNV,
274 | Some(IncomingRayFlagsNv) => br::spv::BuiltIn::BuiltInIncomingRayFlagsNV,
275 | }
276 | }
277 |
278 | /// A work group size.
279 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
280 | pub struct WorkGroupSize {
281 | pub x: u32,
282 | pub y: u32,
283 | pub z: u32,
284 | }
285 |
286 | /// An entry point for a SPIR-V module.
287 | #[derive(Clone, Debug, Hash, Eq, PartialEq)]
288 | pub struct EntryPoint {
289 | pub name: String,
290 | pub execution_model: ExecutionModel,
291 | pub work_group_size: WorkGroupSize,
292 | }
293 |
294 | /// Description of struct member's range.
295 | #[derive(Clone, Debug, Hash, Eq, PartialEq)]
296 | pub struct BufferRange {
297 | /// An index. Useful for passing to `get_member_name` and `get_member_decoration`.
298 | pub index: u32,
299 | /// Bytes from start of buffer not beginning of struct.
300 | pub offset: usize,
301 | /// Size of field in bytes.
302 | pub range: usize,
303 | }
304 |
305 | /// A resource.
306 | #[derive(Clone, Debug, Hash, Eq, PartialEq)]
307 | pub struct Resource {
308 | pub id: u32,
309 | pub type_id: u32,
310 | pub base_type_id: u32,
311 | pub name: String,
312 | }
313 |
314 | /// Specialization constant reference.
315 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
316 | pub struct SpecializationConstant {
317 | pub id: u32,
318 | pub constant_id: u32,
319 | }
320 |
321 | /// Work group size specialization constants.
322 | #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
323 | pub struct WorkGroupSizeSpecializationConstants {
324 | pub x: SpecializationConstant,
325 | pub y: SpecializationConstant,
326 | pub z: SpecializationConstant,
327 | }
328 |
329 | /// Shader resources.
330 | #[derive(Debug, Clone)]
331 | pub struct ShaderResources {
332 | pub uniform_buffers: Vec,
333 | pub storage_buffers: Vec,
334 | pub stage_inputs: Vec,
335 | pub stage_outputs: Vec,
336 | pub subpass_inputs: Vec,
337 | pub storage_images: Vec,
338 | pub sampled_images: Vec,
339 | pub atomic_counters: Vec,
340 | pub push_constant_buffers: Vec,
341 | pub separate_images: Vec,
342 | pub separate_samplers: Vec,
343 | }
344 |
345 | #[derive(Debug, Clone)]
346 | pub enum Dim {
347 | Dim1D = 0,
348 | Dim2D = 1,
349 | Dim3D = 2,
350 | DimCube = 3,
351 | DimRect = 4,
352 | DimBuffer = 5,
353 | DimSubpassData = 6,
354 | }
355 |
356 | #[derive(Debug, Clone)]
357 | pub enum ImageFormat {
358 | Unknown = 0,
359 | Rgba32f = 1,
360 | Rgba16f = 2,
361 | R32f = 3,
362 | Rgba8 = 4,
363 | Rgba8Snorm = 5,
364 | Rg32f = 6,
365 | Rg16f = 7,
366 | R11fG11fB10f = 8,
367 | R16f = 9,
368 | Rgba16 = 10,
369 | Rgb10A2 = 11,
370 | Rg16 = 12,
371 | Rg8 = 13,
372 | R16 = 14,
373 | R8 = 15,
374 | Rgba16Snorm = 16,
375 | Rg16Snorm = 17,
376 | Rg8Snorm = 18,
377 | R16Snorm = 19,
378 | R8Snorm = 20,
379 | Rgba32i = 21,
380 | Rgba16i = 22,
381 | Rgba8i = 23,
382 | R32i = 24,
383 | Rg32i = 25,
384 | Rg16i = 26,
385 | Rg8i = 27,
386 | R16i = 28,
387 | R8i = 29,
388 | Rgba32ui = 30,
389 | Rgba16ui = 31,
390 | Rgba8ui = 32,
391 | R32ui = 33,
392 | Rgb10a2ui = 34,
393 | Rg32ui = 35,
394 | Rg16ui = 36,
395 | Rg8ui = 37,
396 | R16ui = 38,
397 | R8ui = 39,
398 | R64ui = 40,
399 | R64i = 41,
400 | }
401 |
402 | #[derive(Debug, Clone)]
403 | pub struct ImageType {
404 | pub type_id: u32,
405 | pub dim: Dim,
406 | pub depth: bool,
407 | pub arrayed: bool,
408 | pub ms: bool,
409 | pub sampled: u32,
410 | pub format: ImageFormat,
411 | }
412 |
413 | #[derive(Debug, Clone)]
414 | #[non_exhaustive]
415 | pub enum Type {
416 | // TODO: Add missing fields to relevant variants from SPIRType
417 | Unknown,
418 | Void,
419 | Boolean {
420 | vecsize: u32,
421 | columns: u32,
422 | array: Vec,
423 | array_size_literal: Vec,
424 | },
425 | Char {
426 | array: Vec,
427 | array_size_literal: Vec,
428 | },
429 | Int {
430 | vecsize: u32,
431 | columns: u32,
432 | array: Vec,
433 | array_size_literal: Vec,
434 | },
435 | UInt {
436 | vecsize: u32,
437 | columns: u32,
438 | array: Vec,
439 | array_size_literal: Vec,
440 | },
441 | Int64 {
442 | vecsize: u32,
443 | array: Vec,
444 | array_size_literal: Vec,
445 | },
446 | UInt64 {
447 | vecsize: u32,
448 | array: Vec,
449 | array_size_literal: Vec,
450 | },
451 | AtomicCounter {
452 | array: Vec,
453 | array_size_literal: Vec,
454 | },
455 | Half {
456 | vecsize: u32,
457 | columns: u32,
458 | array: Vec,
459 | array_size_literal: Vec,
460 | },
461 | Float {
462 | vecsize: u32,
463 | columns: u32,
464 | array: Vec,
465 | array_size_literal: Vec,
466 | },
467 | Double {
468 | vecsize: u32,
469 | columns: u32,
470 | array: Vec,
471 | array_size_literal: Vec,
472 | },
473 | Struct {
474 | member_types: Vec,
475 | array: Vec,
476 | array_size_literal: Vec,
477 | },
478 | Image {
479 | array: Vec,
480 | array_size_literal: Vec,
481 | image: ImageType,
482 | },
483 | SampledImage {
484 | array: Vec,
485 | array_size_literal: Vec,
486 | image: ImageType,
487 | },
488 | Sampler {
489 | array: Vec,
490 | array_size_literal: Vec,
491 | },
492 | SByte {
493 | vecsize: u32,
494 | array: Vec,
495 | array_size_literal: Vec,
496 | },
497 | UByte {
498 | vecsize: u32,
499 | array: Vec,
500 | array_size_literal: Vec,
501 | },
502 | Short {
503 | vecsize: u32,
504 | array: Vec,
505 | array_size_literal: Vec,
506 | },
507 | UShort {
508 | vecsize: u32,
509 | array: Vec,
510 | array_size_literal: Vec,
511 | },
512 | ControlPointArray,
513 | AccelerationStructure,
514 | RayQuery,
515 | Interpolant,
516 | }
517 |
518 | /// A SPIR-V shader module.
519 | #[derive(Debug, Clone)]
520 | pub struct Module<'a> {
521 | pub(crate) words: &'a [u32],
522 | }
523 |
524 | impl<'a> Module<'a> {
525 | /// Creates a shader module from SPIR-V words.
526 | pub fn from_words(words: &[u32]) -> Module {
527 | Module { words }
528 | }
529 | }
530 |
531 | pub trait Target {
532 | type Data;
533 | }
534 |
535 | /// An abstract syntax tree that corresponds to a SPIR-V module.
536 | pub struct Ast
537 | where
538 | TTarget: Target,
539 | {
540 | pub(crate) compiler: compiler::Compiler,
541 | pub(crate) target_type: PhantomData,
542 | }
543 |
544 | pub trait Parse: Sized {
545 | fn parse(module: &Module) -> Result;
546 | }
547 |
548 | pub trait Compile {
549 | type CompilerOptions;
550 |
551 | fn set_compiler_options(
552 | &mut self,
553 | compiler_options: &Self::CompilerOptions,
554 | ) -> Result<(), ErrorCode>;
555 | fn compile(&mut self) -> Result;
556 | }
557 |
558 | impl Ast
559 | where
560 | Self: Parse + Compile,
561 | TTarget: Target,
562 | {
563 | /// Gets a decoration.
564 | pub fn get_decoration(&self, id: u32, decoration: Decoration) -> Result {
565 | self.compiler.get_decoration(id, decoration)
566 | }
567 |
568 | /// Gets a name. If not defined, an empty string will be returned.
569 | pub fn get_name(&mut self, id: u32) -> Result {
570 | self.compiler.get_name(id)
571 | }
572 |
573 | /// Sets a name.
574 | pub fn set_name(&mut self, id: u32, name: &str) -> Result<(), ErrorCode> {
575 | self.compiler.set_name(id, name)
576 | }
577 |
578 | /// Sets a member name.
579 | pub fn set_member_name(&mut self, id: u32, index: u32, name: &str) -> Result<(), ErrorCode> {
580 | self.compiler.set_member_name(id, index, name)
581 | }
582 |
583 | /// Unsets a decoration.
584 | pub fn unset_decoration(&mut self, id: u32, decoration: Decoration) -> Result<(), ErrorCode> {
585 | self.compiler.unset_decoration(id, decoration)
586 | }
587 |
588 | /// Sets a decoration.
589 | pub fn set_decoration(
590 | &mut self,
591 | id: u32,
592 | decoration: Decoration,
593 | argument: u32,
594 | ) -> Result<(), ErrorCode> {
595 | self.compiler.set_decoration(id, decoration, argument)
596 | }
597 |
598 | /// Gets entry points.
599 | pub fn get_entry_points(&self) -> Result, ErrorCode> {
600 | self.compiler.get_entry_points()
601 | }
602 |
603 | /// Gets cleansed entry point names. `compile` must be called first.
604 | pub fn get_cleansed_entry_point_name(
605 | &self,
606 | entry_point_name: &str,
607 | execution_model: ExecutionModel,
608 | ) -> Result {
609 | if self.compiler.has_been_compiled {
610 | self.compiler
611 | .get_cleansed_entry_point_name(entry_point_name, execution_model)
612 | } else {
613 | Err(ErrorCode::CompilationError(String::from(
614 | "`compile` must be called first",
615 | )))
616 | }
617 | }
618 |
619 | /// Gets active buffer ragnes. Useful for push constants.
620 | pub fn get_active_buffer_ranges(&self, id: u32) -> Result, ErrorCode> {
621 | self.compiler.get_active_buffer_ranges(id)
622 | }
623 |
624 | /// Gets all specialization constants.
625 | pub fn get_specialization_constants(&self) -> Result, ErrorCode> {
626 | self.compiler.get_specialization_constants()
627 | }
628 |
629 | /// Set reference of a scalar constant to a value, overriding the default.
630 | ///
631 | /// Can be used to override specialization constants.
632 | pub fn set_scalar_constant(&mut self, id: u32, value: u64) -> Result<(), ErrorCode> {
633 | self.compiler.set_scalar_constant(id, value)
634 | }
635 |
636 | /// Gets shader resources.
637 | pub fn get_shader_resources(&self) -> Result {
638 | self.compiler.get_shader_resources()
639 | }
640 |
641 | /// Gets the SPIR-V type associated with an ID.
642 | pub fn get_type(&self, id: u32) -> Result {
643 | self.compiler.get_type(id)
644 | }
645 |
646 | /// Gets the identifier for a member located at `index` within an `OpTypeStruct`.
647 | pub fn get_member_name(&self, id: u32, index: u32) -> Result {
648 | self.compiler.get_member_name(id, index)
649 | }
650 |
651 | /// Gets a decoration for a member located at `index` within an `OpTypeStruct`.
652 | pub fn get_member_decoration(
653 | &self,
654 | id: u32,
655 | index: u32,
656 | decoration: Decoration,
657 | ) -> Result {
658 | self.compiler.get_member_decoration(id, index, decoration)
659 | }
660 |
661 | /// Sets a decoration for a member located at `index` within an `OpTypeStruct`.
662 | pub fn set_member_decoration(
663 | &mut self,
664 | id: u32,
665 | index: u32,
666 | decoration: Decoration,
667 | argument: u32,
668 | ) -> Result<(), ErrorCode> {
669 | self.compiler
670 | .set_member_decoration(id, index, decoration, argument)
671 | }
672 |
673 | /// Gets the effective size of a buffer block.
674 | pub fn get_declared_struct_size(&self, id: u32) -> Result {
675 | self.compiler.get_declared_struct_size(id)
676 | }
677 |
678 | /// Gets the effective size of a buffer block struct member.
679 | pub fn get_declared_struct_member_size(&self, id: u32, index: u32) -> Result {
680 | self.compiler.get_declared_struct_member_size(id, index)
681 | }
682 |
683 | /// Renames an interface variable.
684 | pub fn rename_interface_variable(
685 | &mut self,
686 | resources: &[Resource],
687 | location: u32,
688 | name: &str,
689 | ) -> Result<(), ErrorCode> {
690 | self.compiler
691 | .rename_interface_variable(resources, location, name)
692 | }
693 |
694 | /// get the active interface variable.
695 | pub fn get_active_interface_variables(&mut self) -> Result, ErrorCode> {
696 | self.compiler
697 | .get_active_interface_variables()
698 | }
699 |
700 | /// Gets work group size specialization constants.
701 | pub fn get_work_group_size_specialization_constants(
702 | &self,
703 | ) -> Result {
704 | self.compiler.get_work_group_size_specialization_constants()
705 | }
706 |
707 | /// Parses a module into `Ast`.
708 | pub fn parse(module: &Module) -> Result {
709 | Parse::::parse(&module)
710 | }
711 |
712 | /// Sets compile options.
713 | pub fn set_compiler_options(
714 | &mut self,
715 | options: &>::CompilerOptions,
716 | ) -> Result<(), ErrorCode> {
717 | Compile::::set_compiler_options(self, options)
718 | }
719 |
720 | /// Compiles an abstract syntax tree to a `String` in the specified `TTarget` language.
721 | pub fn compile(&mut self) -> Result {
722 | self.compiler.has_been_compiled = true;
723 | Compile::::compile(self)
724 | }
725 | }
726 |
--------------------------------------------------------------------------------
/spirv_cross/src/wrapper.hpp:
--------------------------------------------------------------------------------
1 | #include "vendor/SPIRV-Cross/spirv.hpp"
2 | #include "vendor/SPIRV-Cross/spirv_cross_util.hpp"
3 | #include "vendor/SPIRV-Cross/spirv_hlsl.hpp"
4 | #include "vendor/SPIRV-Cross/spirv_msl.hpp"
5 | #include "vendor/SPIRV-Cross/spirv_glsl.hpp"
6 |
7 | typedef void ScInternalCompilerBase;
8 | typedef void ScInternalCompilerHlsl;
9 | typedef void ScInternalCompilerMsl;
10 | typedef void ScInternalCompilerGlsl;
11 |
12 | extern "C"
13 | {
14 | enum ScInternalResult
15 | {
16 | Success,
17 | Unhandled,
18 | CompilationError,
19 | };
20 |
21 | typedef struct ScEntryPoint
22 | {
23 | char *name;
24 | spv::ExecutionModel execution_model;
25 | uint32_t work_group_size_x;
26 | uint32_t work_group_size_y;
27 | uint32_t work_group_size_z;
28 | } ScEntryPoint;
29 |
30 | typedef struct ScBufferRange
31 | {
32 | unsigned index;
33 | size_t offset;
34 | size_t range;
35 | } ScBufferRange;
36 |
37 | typedef struct ScCombinedImageSampler
38 | {
39 | uint32_t combined_id;
40 | uint32_t image_id;
41 | uint32_t sampler_id;
42 | } ScCombinedImageSampler;
43 |
44 | typedef struct ScHlslRootConstant
45 | {
46 | uint32_t start;
47 | uint32_t end;
48 | uint32_t binding;
49 | uint32_t space;
50 | } ScHlslRootConstant;
51 |
52 | typedef struct ScHlslCompilerOptions
53 | {
54 | int32_t shader_model;
55 | bool point_size_compat;
56 | bool point_coord_compat;
57 | bool vertex_transform_clip_space;
58 | bool vertex_invert_y;
59 | bool force_storage_buffer_as_uav;
60 | bool nonwritable_uav_texture_as_srv;
61 | bool force_zero_initialized_variables;
62 | } ScHlslCompilerOptions;
63 |
64 | typedef struct ScMslCompilerOptions
65 | {
66 | bool vertex_transform_clip_space;
67 | bool vertex_invert_y;
68 | uint8_t platform;
69 | uint32_t version;
70 | bool enable_point_size_builtin;
71 | bool disable_rasterization;
72 | uint32_t swizzle_buffer_index;
73 | uint32_t indirect_params_buffer_index;
74 | uint32_t shader_output_buffer_index;
75 | uint32_t shader_patch_output_buffer_index;
76 | uint32_t shader_tess_factor_buffer_index;
77 | uint32_t buffer_size_buffer_index;
78 | bool capture_output_to_buffer;
79 | bool swizzle_texture_samples;
80 | bool tess_domain_origin_lower_left;
81 | bool argument_buffers;
82 | bool pad_fragment_output_components;
83 | bool force_native_arrays;
84 | bool force_zero_initialized_variables;
85 | bool force_active_argument_buffer_resources;
86 | } ScMslCompilerOptions;
87 |
88 | typedef struct ScGlslCompilerOptions
89 | {
90 | bool vertex_transform_clip_space;
91 | bool vertex_invert_y;
92 | bool vertex_support_nonzero_base_instance;
93 | uint8_t fragment_default_float_precision;
94 | uint8_t fragment_default_int_precision;
95 | uint32_t version;
96 | bool es;
97 | bool force_temporary;
98 | bool vulkan_semantics;
99 | bool separate_shader_objects;
100 | bool flatten_multidimensional_arrays;
101 | bool enable_420_pack_extension;
102 | bool emit_push_constant_as_uniform_buffer;
103 | bool emit_uniform_buffer_as_plain_uniforms;
104 | bool emit_line_directives;
105 | bool enable_storage_image_qualifier_deduction;
106 | bool force_zero_initialized_variables;
107 | } ScGlslCompilerOptions;
108 |
109 | typedef struct ScResource
110 | {
111 | uint32_t id;
112 | uint32_t type_id;
113 | uint32_t base_type_id;
114 | char *name;
115 | } ScResource;
116 |
117 | typedef struct ScResourceArray
118 | {
119 | ScResource *data;
120 | size_t num;
121 | } ScResourceArray;
122 |
123 | typedef struct ScShaderResources
124 | {
125 | ScResourceArray uniform_buffers;
126 | ScResourceArray storage_buffers;
127 | ScResourceArray stage_inputs;
128 | ScResourceArray stage_outputs;
129 | ScResourceArray subpass_inputs;
130 | ScResourceArray storage_images;
131 | ScResourceArray sampled_images;
132 | ScResourceArray atomic_counters;
133 | ScResourceArray push_constant_buffers;
134 | ScResourceArray separate_images;
135 | ScResourceArray separate_samplers;
136 | } ScShaderResources;
137 |
138 | typedef struct ScSpecializationConstant
139 | {
140 | uint32_t id;
141 | uint32_t constant_id;
142 | } ScSpecializationConstant;
143 |
144 | typedef struct ScType
145 | {
146 | spirv_cross::SPIRType::BaseType type;
147 | uint32_t width;
148 | uint32_t vecsize;
149 | uint32_t columns;
150 | uint32_t *member_types;
151 | size_t member_types_size;
152 | uint32_t *array;
153 | bool *array_size_literal;
154 | size_t array_size;
155 | spv::StorageClass storage;
156 | spirv_cross::SPIRType::ImageType image;
157 | } ScType;
158 |
159 | ScInternalResult sc_internal_get_latest_exception_message(const char **message);
160 |
161 | #ifdef SPIRV_CROSS_WRAPPER_HLSL
162 | ScInternalResult sc_internal_compiler_hlsl_new(ScInternalCompilerHlsl **compiler, const uint32_t *ir, const size_t size);
163 | ScInternalResult sc_internal_compiler_hlsl_set_options(const ScInternalCompilerHlsl *compiler, const ScHlslCompilerOptions *options);
164 | ScInternalResult sc_internal_compiler_hlsl_set_root_constant_layout(const ScInternalCompilerHlsl *compiler, const ScHlslRootConstant *constants, size_t count);
165 | #endif
166 |
167 | #ifdef SPIRV_CROSS_WRAPPER_MSL
168 | typedef struct ScMslConstSamplerMapping {
169 | uint32_t desc_set;
170 | uint32_t binding;
171 | spirv_cross::MSLConstexprSampler sampler;
172 | } ScMslConstSamplerMapping;
173 |
174 | ScInternalResult sc_internal_compiler_msl_new(ScInternalCompilerMsl **compiler, const uint32_t *ir, const size_t size);
175 | ScInternalResult sc_internal_compiler_msl_set_options(const ScInternalCompilerMsl *compiler, const ScMslCompilerOptions *options);
176 | ScInternalResult sc_internal_compiler_msl_get_is_rasterization_disabled(const ScInternalCompilerMsl *compiler, bool *is_rasterization_disabled);
177 | ScInternalResult sc_internal_compiler_msl_compile(const ScInternalCompilerBase *compiler, const char **shader,
178 | const spirv_cross::MSLShaderInput *p_vat_overrides, const size_t vat_override_count,
179 | const spirv_cross::MSLResourceBinding *p_res_overrides, const size_t res_override_count,
180 | const ScMslConstSamplerMapping *p_const_samplers, const size_t const_sampler_count);
181 | #endif
182 |
183 | #ifdef SPIRV_CROSS_WRAPPER_GLSL
184 | ScInternalResult sc_internal_compiler_glsl_new(ScInternalCompilerGlsl **compiler, const uint32_t *ir, const size_t size);
185 | ScInternalResult sc_internal_compiler_glsl_set_options(const ScInternalCompilerGlsl *compiler, const ScGlslCompilerOptions *options);
186 | ScInternalResult sc_internal_compiler_glsl_build_combined_image_samplers(const ScInternalCompilerBase *compiler);
187 | ScInternalResult sc_internal_compiler_glsl_get_combined_image_samplers(const ScInternalCompilerBase *compiler, const ScCombinedImageSampler **samplers, size_t *size);
188 | ScInternalResult sc_internal_compiler_glsl_add_header_line(const ScInternalCompilerBase *compiler, const char *str);
189 | ScInternalResult sc_internal_compiler_glsl_flatten_buffer_block(const ScInternalCompilerBase *compiler, const uint32_t id);
190 | #endif
191 |
192 | ScInternalResult sc_internal_compiler_get_decoration(const ScInternalCompilerBase *compiler, uint32_t *result, const uint32_t id, const spv::Decoration decoration);
193 | ScInternalResult sc_internal_compiler_set_decoration(const ScInternalCompilerBase *compiler, const uint32_t id, const spv::Decoration decoration, const uint32_t argument);
194 | ScInternalResult sc_internal_compiler_unset_decoration(const ScInternalCompilerBase *compiler, const uint32_t id, const spv::Decoration decoration);
195 | ScInternalResult sc_internal_compiler_get_name(const ScInternalCompilerBase *compiler, const uint32_t id, const char **name);
196 | ScInternalResult sc_internal_compiler_set_name(const ScInternalCompilerBase *compiler, const uint32_t id, const char *name);
197 | ScInternalResult sc_internal_compiler_set_member_name(const ScInternalCompilerBase *compiler, const uint32_t id, const uint32_t index, const char *name);
198 | ScInternalResult sc_internal_compiler_get_entry_points(const ScInternalCompilerBase *compiler, ScEntryPoint **entry_points, size_t *size);
199 | ScInternalResult sc_internal_compiler_get_active_buffer_ranges(const ScInternalCompilerBase *compiler, uint32_t id, ScBufferRange **active_buffer_ranges, size_t *size);
200 | ScInternalResult sc_internal_compiler_get_cleansed_entry_point_name(const ScInternalCompilerBase *compiler, const char *original_entry_point_name, const spv::ExecutionModel execution_model, const char **compiled_entry_point_name);
201 | ScInternalResult sc_internal_compiler_get_shader_resources(const ScInternalCompilerBase *compiler, ScShaderResources *shader_resources);
202 | ScInternalResult sc_internal_compiler_get_specialization_constants(const ScInternalCompilerBase *compiler, ScSpecializationConstant **constants, size_t *size);
203 | // `uint64_t` isn't supported in Emscripten without implicitly splitting the value into two `uint32_t` - instead do it explicitly
204 | ScInternalResult sc_internal_compiler_set_scalar_constant(const ScInternalCompilerBase *compiler, const uint32_t id, const uint32_t constant_high_bits, const uint32_t constant_low_bits);
205 | ScInternalResult sc_internal_compiler_get_type(const ScInternalCompilerBase *compiler, const uint32_t id, const ScType **spirv_type);
206 | ScInternalResult sc_internal_compiler_get_member_name(const ScInternalCompilerBase *compiler, const uint32_t id, const uint32_t index, const char **name);
207 | ScInternalResult sc_internal_compiler_get_member_decoration(const ScInternalCompilerBase *compiler, const uint32_t id, const uint32_t index, const spv::Decoration decoration, uint32_t *result);
208 | ScInternalResult sc_internal_compiler_set_member_decoration(const ScInternalCompilerBase *compiler, const uint32_t id, const uint32_t index, const spv::Decoration decoration, const uint32_t argument);
209 | ScInternalResult sc_internal_compiler_get_declared_struct_size(const ScInternalCompilerBase *compiler, const uint32_t id, uint32_t *result);
210 | ScInternalResult sc_internal_compiler_get_declared_struct_member_size(const ScInternalCompilerBase *compiler, const uint32_t id, const uint32_t index, uint32_t *result);
211 | ScInternalResult sc_internal_compiler_rename_interface_variable(const ScInternalCompilerBase *compiler, const ScResource *resources, const size_t resources_size, uint32_t location, const char *name);
212 | ScInternalResult sc_internal_compiler_get_work_group_size_specialization_constants(const ScInternalCompilerBase *compiler, ScSpecializationConstant **constants);
213 | ScInternalResult sc_internal_compiler_set_entry_point(const ScInternalCompilerBase *compiler, const char *name, const spv::ExecutionModel execution_model);
214 | ScInternalResult sc_internal_compiler_compile(const ScInternalCompilerBase *compiler, const char **shader);
215 | ScInternalResult sc_internal_compiler_delete(ScInternalCompilerBase *compiler);
216 | ScInternalResult sc_internal_compiler_get_active_interface_variables(const ScInternalCompilerBase *compiler, uint32_t **ids, size_t* size);
217 |
218 | ScInternalResult sc_internal_free_pointer(void *pointer);
219 | }
220 |
--------------------------------------------------------------------------------
/spirv_cross/tests/common/mod.rs:
--------------------------------------------------------------------------------
1 | #[allow(clippy::cast_ptr_alignment)]
2 | pub fn words_from_bytes(buf: &[u8]) -> &[u32] {
3 | unsafe {
4 | std::slice::from_raw_parts(
5 | buf.as_ptr() as *const u32,
6 | buf.len() / std::mem::size_of::(),
7 | )
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/spirv_cross/tests/glsl_tests.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashSet;
2 | use spirv_cross::{glsl, spirv};
3 |
4 | mod common;
5 | use crate::common::words_from_bytes;
6 |
7 | #[test]
8 | fn glsl_compiler_options_has_default() {
9 | let compiler_options = glsl::CompilerOptions::default();
10 | assert_eq!(compiler_options.vertex.invert_y, false);
11 | assert_eq!(compiler_options.vertex.transform_clip_space, false);
12 | }
13 |
14 | #[test]
15 | fn ast_compiles_to_glsl() {
16 | let mut ast = spirv::Ast::::parse(&spirv::Module::from_words(words_from_bytes(
17 | include_bytes!("shaders/simple.vert.spv"),
18 | )))
19 | .unwrap();
20 | let mut options = glsl::CompilerOptions::default();
21 | options.version = glsl::Version::V4_60;
22 | options.enable_420_pack_extension = true;
23 | ast.set_compiler_options(&options).unwrap();
24 |
25 | assert_eq!(
26 | ast.compile().unwrap(),
27 | "\
28 | #version 460
29 |
30 | layout(std140) uniform uniform_buffer_object
31 | {
32 | mat4 u_model_view_projection;
33 | float u_scale;
34 | } _22;
35 |
36 | layout(location = 0) out vec3 v_normal;
37 | layout(location = 1) in vec3 a_normal;
38 | layout(location = 0) in vec4 a_position;
39 |
40 | void main()
41 | {
42 | v_normal = a_normal;
43 | gl_Position = (_22.u_model_view_projection * a_position) * _22.u_scale;
44 | }
45 |
46 | "
47 | );
48 | }
49 |
50 | #[test]
51 | fn ast_compiles_all_versions_to_glsl() {
52 | use spirv_cross::glsl::Version::*;
53 |
54 | let module =
55 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
56 | let mut ast = spirv::Ast::::parse(&module).unwrap();
57 |
58 | let versions = [
59 | V1_10, V1_20, V1_30, V1_40, V1_50, V3_30, V4_00, V4_10, V4_20, V4_30, V4_40, V4_50, V4_60,
60 | V1_00Es, V3_00Es,
61 | ];
62 | for &version in versions.iter() {
63 | let mut options = glsl::CompilerOptions::default();
64 | options.version = version;
65 | options.enable_420_pack_extension = true;
66 | if ast.set_compiler_options(&options).is_err() {
67 | panic!("Did not compile");
68 | }
69 | }
70 | }
71 |
72 |
73 | #[test]
74 | fn ast_active_variables() {
75 | let vert =
76 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/struct.vert.spv")));
77 | let mut vert_ast = spirv::Ast::::parse(&vert).unwrap();
78 | let mut vert_options = glsl::CompilerOptions::default();
79 | vert_options.version = glsl::Version::V1_00Es;
80 | vert_options.enable_420_pack_extension = true;
81 | vert_ast.set_compiler_options(&vert_options).unwrap();
82 |
83 | let active = vert_ast.get_active_interface_variables().unwrap();
84 | assert_eq!(active.len(), 5);
85 | let variables = HashSet::from(["a", "b", "c", "d", "v"]);
86 | for i in active {
87 | let mut name = vert_ast.get_name(i).unwrap();
88 | assert!(variables.contains(name.as_str()));
89 | }
90 | }
91 |
92 | #[test]
93 | fn ast_renames_interface_variables() {
94 | let vert =
95 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/struct.vert.spv")));
96 | let mut vert_ast = spirv::Ast::::parse(&vert).unwrap();
97 | let mut vert_options = glsl::CompilerOptions::default();
98 | vert_options.version = glsl::Version::V1_00Es;
99 | vert_options.enable_420_pack_extension = true;
100 | vert_ast.set_compiler_options(&vert_options).unwrap();
101 | let vert_stage_outputs = vert_ast.get_shader_resources().unwrap().stage_outputs;
102 | vert_ast
103 | .rename_interface_variable(&vert_stage_outputs, 0, "renamed")
104 | .unwrap();
105 |
106 | let vert_output = vert_ast.compile().unwrap();
107 |
108 | let frag =
109 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/struct.frag.spv")));
110 | let mut frag_ast = spirv::Ast::::parse(&frag).unwrap();
111 | let mut frag_options = glsl::CompilerOptions::default();
112 | frag_options.version = glsl::Version::V1_00Es;
113 | frag_options.enable_420_pack_extension = true;
114 | frag_ast.set_compiler_options(&frag_options).unwrap();
115 | let frag_stage_inputs = frag_ast.get_shader_resources().unwrap().stage_inputs;
116 | frag_ast
117 | .rename_interface_variable(&frag_stage_inputs, 0, "renamed")
118 | .unwrap();
119 | let frag_output = frag_ast.compile().unwrap();
120 |
121 | assert_eq!(
122 | vert_output,
123 | "\
124 | #version 100
125 |
126 | struct SPIRV_Cross_Interface_Location0
127 | {
128 | vec4 InterfaceMember0;
129 | vec4 InterfaceMember1;
130 | vec4 InterfaceMember2;
131 | vec4 InterfaceMember3;
132 | };
133 |
134 | varying vec4 renamed_InterfaceMember0;
135 | varying vec4 renamed_InterfaceMember1;
136 | varying vec4 renamed_InterfaceMember2;
137 | varying vec4 renamed_InterfaceMember3;
138 | attribute vec4 a;
139 | attribute vec4 b;
140 | attribute vec4 c;
141 | attribute vec4 d;
142 |
143 | void main()
144 | {
145 | SPIRV_Cross_Interface_Location0 _20 = SPIRV_Cross_Interface_Location0(a, b, c, d);
146 | renamed_InterfaceMember0 = _20.InterfaceMember0;
147 | renamed_InterfaceMember1 = _20.InterfaceMember1;
148 | renamed_InterfaceMember2 = _20.InterfaceMember2;
149 | renamed_InterfaceMember3 = _20.InterfaceMember3;
150 | }
151 |
152 | "
153 | );
154 |
155 | assert_eq!(
156 | frag_output,
157 | "\
158 | #version 100
159 | precision mediump float;
160 | precision highp int;
161 |
162 | struct SPIRV_Cross_Interface_Location0
163 | {
164 | vec4 InterfaceMember0;
165 | vec4 InterfaceMember1;
166 | vec4 InterfaceMember2;
167 | vec4 InterfaceMember3;
168 | };
169 |
170 | varying vec4 renamed_InterfaceMember0;
171 | varying vec4 renamed_InterfaceMember1;
172 | varying vec4 renamed_InterfaceMember2;
173 | varying vec4 renamed_InterfaceMember3;
174 |
175 | void main()
176 | {
177 | gl_FragData[0] = vec4(renamed_InterfaceMember0.x, renamed_InterfaceMember1.y, renamed_InterfaceMember2.z, renamed_InterfaceMember3.w);
178 | }
179 |
180 | "
181 | );
182 | }
183 |
184 | #[test]
185 | fn ast_can_rename_combined_image_samplers() {
186 | let mut ast = spirv::Ast::::parse(&spirv::Module::from_words(words_from_bytes(
187 | include_bytes!("shaders/sampler.frag.spv"),
188 | )))
189 | .unwrap();
190 | let mut options = glsl::CompilerOptions::default();
191 | options.version = glsl::Version::V4_10;
192 | options.enable_420_pack_extension = true;
193 | ast.set_compiler_options(&options).unwrap();
194 | for cis in ast.get_combined_image_samplers().unwrap() {
195 | let new_name = format!(
196 | "combined_sampler_{}_{}_{}",
197 | cis.sampler_id, cis.image_id, cis.combined_id
198 | );
199 | ast.set_name(cis.combined_id, &new_name).unwrap();
200 | assert_eq!(new_name, ast.get_name(cis.combined_id).unwrap());
201 | }
202 |
203 | assert_eq!(
204 | ast.compile().unwrap(),
205 | "\
206 | #version 410
207 | #ifdef GL_ARB_shading_language_420pack
208 | #extension GL_ARB_shading_language_420pack : require
209 | #endif
210 |
211 | uniform sampler2D combined_sampler_16_12_26;
212 |
213 | layout(location = 0) out vec4 target0;
214 | layout(location = 0) in vec2 v_uv;
215 |
216 | void main()
217 | {
218 | target0 = texture(combined_sampler_16_12_26, v_uv);
219 | }
220 |
221 | "
222 | );
223 | }
224 |
225 | #[test]
226 | fn flatten_uniform_buffers() {
227 | let mut ast = spirv::Ast::::parse(&spirv::Module::from_words(words_from_bytes(
228 | include_bytes!("shaders/two_ubo.vert.spv"),
229 | )))
230 | .unwrap();
231 | let mut options = glsl::CompilerOptions::default();
232 | options.version = glsl::Version::V3_30;
233 | options.emit_uniform_buffer_as_plain_uniforms = true;
234 | options.enable_420_pack_extension = false;
235 |
236 | ast.set_compiler_options(&options).unwrap();
237 |
238 | for uniform_buffer in &ast.get_shader_resources().unwrap().uniform_buffers {
239 | ast.flatten_buffer_block(uniform_buffer.id).unwrap();
240 | }
241 |
242 | assert_eq!(
243 | ast.compile().unwrap(),
244 | "\
245 | #version 330
246 |
247 | uniform vec4 ubo1[7];
248 | uniform vec4 ubo2[3];
249 | void main()
250 | {
251 | gl_Position = vec4(((((ubo1[1].z + ubo1[4].x) + ubo1[6].y) + ubo2[0].x) + ubo2[1].x) + ubo2[2].z);
252 | }
253 |
254 | "
255 | );
256 | }
257 |
258 | #[test]
259 | fn add_header_line() {
260 | let mut ast = spirv::Ast::::parse(&spirv::Module::from_words(words_from_bytes(
261 | include_bytes!("shaders/simple.vert.spv"),
262 | )))
263 | .unwrap();
264 | ast.add_header_line("// Comment").unwrap();
265 |
266 | assert_eq!(Some("// Comment"), ast.compile().unwrap().lines().nth(1));
267 | }
268 |
269 | #[test]
270 | fn low_precision() {
271 | let mut ast = spirv::Ast::::parse(&spirv::Module::from_words(words_from_bytes(
272 | include_bytes!("shaders/sampler.frag.spv"),
273 | )))
274 | .unwrap();
275 | let mut options = glsl::CompilerOptions::default();
276 | options.version = glsl::Version::V3_00Es;
277 | options.fragment = glsl::CompilerFragmentOptions {
278 | default_float_precision: glsl::Precision::Low,
279 | default_int_precision: glsl::Precision::Low,
280 | };
281 | ast.set_compiler_options(&options).unwrap();
282 |
283 | assert_eq!(
284 | ast.compile().unwrap(),
285 | "\
286 | #version 300 es
287 | precision lowp float;
288 | precision lowp int;
289 |
290 | uniform highp sampler2D _26;
291 |
292 | layout(location = 0) out highp vec4 target0;
293 | in highp vec2 v_uv;
294 |
295 | void main()
296 | {
297 | target0 = texture(_26, v_uv);
298 | }
299 |
300 | "
301 | );
302 | }
303 |
304 | #[test]
305 | fn forces_zero_initialization() {
306 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
307 | "shaders/initialization.vert.spv"
308 | )));
309 |
310 | let cases = [
311 | (
312 | false,
313 | "\
314 | #version 450
315 |
316 | layout(location = 0) in float rand;
317 |
318 | void main()
319 | {
320 | vec4 pos;
321 | if (rand > 0.5)
322 | {
323 | pos = vec4(1.0);
324 | }
325 | gl_Position = pos;
326 | }
327 |
328 | ",
329 | ),
330 | (
331 | true,
332 | "\
333 | #version 450
334 |
335 | layout(location = 0) in float rand;
336 |
337 | void main()
338 | {
339 | vec4 pos = vec4(0.0);
340 | if (rand > 0.5)
341 | {
342 | pos = vec4(1.0);
343 | }
344 | gl_Position = pos;
345 | }
346 |
347 | ",
348 | ),
349 | ];
350 | for (force_zero_initialized_variables, expected_result) in cases.iter() {
351 | let mut ast = spirv::Ast::::parse(&module).unwrap();
352 | let mut compiler_options = glsl::CompilerOptions::default();
353 | compiler_options.force_zero_initialized_variables = *force_zero_initialized_variables;
354 | ast.set_compiler_options(&compiler_options).unwrap();
355 | assert_eq!(&ast.compile().unwrap(), expected_result);
356 | }
357 | }
358 |
359 | #[test]
360 | fn ast_sets_entry_point() {
361 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
362 | "shaders/vs_and_fs.asm.spv"
363 | )));
364 |
365 | let mut cases = vec![
366 | (
367 | None,
368 | "\
369 | #version 450
370 |
371 | void main()
372 | {
373 | gl_Position = vec4(1.0);
374 | }
375 |
376 | ",
377 | ),
378 | (
379 | Some((String::from("main_vs"), spirv::ExecutionModel::Vertex)),
380 | "\
381 | #version 450
382 |
383 | void main()
384 | {
385 | gl_Position = vec4(1.0);
386 | }
387 |
388 | ",
389 | ),
390 | (
391 | Some((String::from("main_fs"), spirv::ExecutionModel::Fragment)),
392 | "\
393 | #version 450
394 |
395 | layout(location = 0) out vec4 color;
396 |
397 | void main()
398 | {
399 | color = vec4(1.0);
400 | }
401 |
402 | ",
403 | ),
404 | ];
405 |
406 | for (entry_point, expected_result) in cases.drain(..) {
407 | let mut ast = spirv::Ast::::parse(&module).unwrap();
408 | let mut compiler_options = glsl::CompilerOptions::default();
409 | compiler_options.entry_point = entry_point;
410 | ast.set_compiler_options(&compiler_options).unwrap();
411 | assert_eq!(&ast.compile().unwrap(), expected_result);
412 | }
413 | }
414 |
--------------------------------------------------------------------------------
/spirv_cross/tests/hlsl_tests.rs:
--------------------------------------------------------------------------------
1 | use spirv_cross::{hlsl, spirv};
2 |
3 | mod common;
4 | use crate::common::words_from_bytes;
5 |
6 | #[test]
7 | fn hlsl_compiler_options_has_default() {
8 | let compiler_options = hlsl::CompilerOptions::default();
9 | assert_eq!(compiler_options.shader_model, hlsl::ShaderModel::V3_0);
10 | assert_eq!(compiler_options.point_size_compat, false);
11 | assert_eq!(compiler_options.point_coord_compat, false);
12 | assert_eq!(compiler_options.vertex.invert_y, false);
13 | assert_eq!(compiler_options.vertex.transform_clip_space, false);
14 | }
15 |
16 | #[test]
17 | fn ast_compiles_to_hlsl() {
18 | let module =
19 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
20 | let mut ast = spirv::Ast::::parse(&module).unwrap();
21 | let mut options = hlsl::CompilerOptions::default();
22 | options.shader_model = hlsl::ShaderModel::V6_0;
23 | ast.set_compiler_options(&options).unwrap();
24 |
25 | assert_eq!(
26 | ast.compile().unwrap(),
27 | "\
28 | cbuffer uniform_buffer_object
29 | {
30 | row_major float4x4 _22_u_model_view_projection : packoffset(c0);
31 | float _22_u_scale : packoffset(c4);
32 | };
33 |
34 |
35 | static float4 gl_Position;
36 | static float3 v_normal;
37 | static float3 a_normal;
38 | static float4 a_position;
39 |
40 | struct SPIRV_Cross_Input
41 | {
42 | float4 a_position : TEXCOORD0;
43 | float3 a_normal : TEXCOORD1;
44 | };
45 |
46 | struct SPIRV_Cross_Output
47 | {
48 | float3 v_normal : TEXCOORD0;
49 | float4 gl_Position : SV_Position;
50 | };
51 |
52 | void vert_main()
53 | {
54 | v_normal = a_normal;
55 | gl_Position = mul(a_position, _22_u_model_view_projection) * _22_u_scale;
56 | }
57 |
58 | SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
59 | {
60 | a_normal = stage_input.a_normal;
61 | a_position = stage_input.a_position;
62 | vert_main();
63 | SPIRV_Cross_Output stage_output;
64 | stage_output.gl_Position = gl_Position;
65 | stage_output.v_normal = v_normal;
66 | return stage_output;
67 | }
68 | "
69 | );
70 | }
71 |
72 | #[test]
73 | fn ast_compiles_all_shader_models_to_hlsl() {
74 | let module =
75 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
76 | let mut ast = spirv::Ast::::parse(&module).unwrap();
77 |
78 | let shader_models = [
79 | hlsl::ShaderModel::V3_0,
80 | hlsl::ShaderModel::V4_0,
81 | hlsl::ShaderModel::V4_0L9_0,
82 | hlsl::ShaderModel::V4_0L9_1,
83 | hlsl::ShaderModel::V4_0L9_3,
84 | hlsl::ShaderModel::V4_1,
85 | hlsl::ShaderModel::V5_0,
86 | hlsl::ShaderModel::V5_1,
87 | hlsl::ShaderModel::V6_0,
88 | ];
89 | for &shader_model in shader_models.iter() {
90 | let mut options = hlsl::CompilerOptions::default();
91 | options.shader_model = shader_model;
92 | assert!(ast.set_compiler_options(&options).is_ok());
93 | }
94 | }
95 |
96 | #[test]
97 | fn forces_zero_initialization() {
98 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
99 | "shaders/initialization.vert.spv"
100 | )));
101 |
102 | let cases = [
103 | (
104 | false,
105 | "\
106 | uniform float4 gl_HalfPixel;
107 |
108 | static float4 gl_Position;
109 | static float rand;
110 |
111 | struct SPIRV_Cross_Input
112 | {
113 | float rand : TEXCOORD0;
114 | };
115 |
116 | struct SPIRV_Cross_Output
117 | {
118 | float4 gl_Position : POSITION;
119 | };
120 |
121 | void vert_main()
122 | {
123 | float4 pos;
124 | if (rand > 0.5f)
125 | {
126 | pos = 1.0f.xxxx;
127 | }
128 | gl_Position = pos;
129 | gl_Position.x = gl_Position.x - gl_HalfPixel.x * gl_Position.w;
130 | gl_Position.y = gl_Position.y + gl_HalfPixel.y * gl_Position.w;
131 | }
132 |
133 | SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
134 | {
135 | rand = stage_input.rand;
136 | vert_main();
137 | SPIRV_Cross_Output stage_output;
138 | stage_output.gl_Position = gl_Position;
139 | return stage_output;
140 | }
141 | ",
142 | ),
143 | (
144 | true,
145 | "\
146 | uniform float4 gl_HalfPixel;
147 |
148 | static float4 gl_Position;
149 | static float rand;
150 |
151 | struct SPIRV_Cross_Input
152 | {
153 | float rand : TEXCOORD0;
154 | };
155 |
156 | struct SPIRV_Cross_Output
157 | {
158 | float4 gl_Position : POSITION;
159 | };
160 |
161 | void vert_main()
162 | {
163 | float4 pos = 0.0f.xxxx;
164 | if (rand > 0.5f)
165 | {
166 | pos = 1.0f.xxxx;
167 | }
168 | gl_Position = pos;
169 | gl_Position.x = gl_Position.x - gl_HalfPixel.x * gl_Position.w;
170 | gl_Position.y = gl_Position.y + gl_HalfPixel.y * gl_Position.w;
171 | }
172 |
173 | SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
174 | {
175 | rand = stage_input.rand;
176 | vert_main();
177 | SPIRV_Cross_Output stage_output;
178 | stage_output.gl_Position = gl_Position;
179 | return stage_output;
180 | }
181 | ",
182 | ),
183 | ];
184 | for (force_zero_initialized_variables, expected_result) in cases.iter() {
185 | let mut ast = spirv::Ast::::parse(&module).unwrap();
186 | let mut compiler_options = hlsl::CompilerOptions::default();
187 | compiler_options.force_zero_initialized_variables = *force_zero_initialized_variables;
188 | ast.set_compiler_options(&compiler_options).unwrap();
189 | assert_eq!(&ast.compile().unwrap(), expected_result);
190 | }
191 | }
192 |
193 | #[test]
194 | fn ast_sets_entry_point() {
195 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
196 | "shaders/vs_and_fs.asm.spv"
197 | )));
198 |
199 | let mut cases = vec![
200 | (
201 | None,
202 | "\
203 | uniform float4 gl_HalfPixel;
204 |
205 | static float4 gl_Position;
206 | struct SPIRV_Cross_Output
207 | {
208 | float4 gl_Position : POSITION;
209 | };
210 |
211 | void vert_main()
212 | {
213 | gl_Position = 1.0f.xxxx;
214 | gl_Position.x = gl_Position.x - gl_HalfPixel.x * gl_Position.w;
215 | gl_Position.y = gl_Position.y + gl_HalfPixel.y * gl_Position.w;
216 | }
217 |
218 | SPIRV_Cross_Output main()
219 | {
220 | vert_main();
221 | SPIRV_Cross_Output stage_output;
222 | stage_output.gl_Position = gl_Position;
223 | return stage_output;
224 | }
225 | ",
226 | ),
227 | (
228 | Some((String::from("main_vs"), spirv::ExecutionModel::Vertex)),
229 | "\
230 | uniform float4 gl_HalfPixel;
231 |
232 | static float4 gl_Position;
233 | struct SPIRV_Cross_Output
234 | {
235 | float4 gl_Position : POSITION;
236 | };
237 |
238 | void vert_main()
239 | {
240 | gl_Position = 1.0f.xxxx;
241 | gl_Position.x = gl_Position.x - gl_HalfPixel.x * gl_Position.w;
242 | gl_Position.y = gl_Position.y + gl_HalfPixel.y * gl_Position.w;
243 | }
244 |
245 | SPIRV_Cross_Output main()
246 | {
247 | vert_main();
248 | SPIRV_Cross_Output stage_output;
249 | stage_output.gl_Position = gl_Position;
250 | return stage_output;
251 | }
252 | ",
253 | ),
254 | (
255 | Some((String::from("main_fs"), spirv::ExecutionModel::Fragment)),
256 | "\
257 | static float4 color;
258 |
259 | struct SPIRV_Cross_Output
260 | {
261 | float4 color : COLOR0;
262 | };
263 |
264 | void frag_main()
265 | {
266 | color = 1.0f.xxxx;
267 | }
268 |
269 | SPIRV_Cross_Output main()
270 | {
271 | frag_main();
272 | SPIRV_Cross_Output stage_output;
273 | stage_output.color = float4(color);
274 | return stage_output;
275 | }
276 | ",
277 | ),
278 | ];
279 |
280 | for (entry_point, expected_result) in cases.drain(..) {
281 | let mut ast = spirv::Ast::::parse(&module).unwrap();
282 | let mut compiler_options = hlsl::CompilerOptions::default();
283 | compiler_options.entry_point = entry_point;
284 | ast.set_compiler_options(&compiler_options).unwrap();
285 | assert_eq!(&ast.compile().unwrap(), expected_result);
286 | }
287 | }
288 |
--------------------------------------------------------------------------------
/spirv_cross/tests/msl_tests.rs:
--------------------------------------------------------------------------------
1 | use spirv_cross::{msl, spirv};
2 |
3 | use std::collections::BTreeMap;
4 |
5 | mod common;
6 | use crate::common::words_from_bytes;
7 |
8 | #[test]
9 | fn msl_compiler_options_has_default() {
10 | let compiler_options = msl::CompilerOptions::default();
11 | assert_eq!(compiler_options.vertex.invert_y, false);
12 | assert_eq!(compiler_options.vertex.transform_clip_space, false);
13 | assert!(compiler_options.resource_binding_overrides.is_empty());
14 | assert!(compiler_options.vertex_attribute_overrides.is_empty());
15 | }
16 |
17 | #[test]
18 | fn is_rasterization_enabled() {
19 | let modules = [
20 | (
21 | true,
22 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv"))),
23 | ),
24 | (
25 | false,
26 | spirv::Module::from_words(words_from_bytes(include_bytes!(
27 | "shaders/rasterize_disabled.vert.spv"
28 | ))),
29 | ),
30 | ];
31 | for (expected, module) in &modules {
32 | let mut ast = spirv::Ast::::parse(&module).unwrap();
33 | ast.compile().unwrap();
34 | assert_eq!(*expected, ast.is_rasterization_enabled().unwrap());
35 | }
36 | }
37 |
38 | #[test]
39 | fn ast_compiles_to_msl() {
40 | let module =
41 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
42 | let mut ast = spirv::Ast::::parse(&module).unwrap();
43 |
44 | let mut compiler_options = msl::CompilerOptions::default();
45 |
46 | compiler_options.resource_binding_overrides.insert(
47 | msl::ResourceBindingLocation {
48 | stage: spirv::ExecutionModel::Vertex,
49 | desc_set: 0,
50 | binding: 0,
51 | },
52 | msl::ResourceBinding {
53 | buffer_id: 5,
54 | texture_id: 6,
55 | sampler_id: 7,
56 | count: 0,
57 | },
58 | );
59 |
60 | ast.set_compiler_options(&compiler_options).unwrap();
61 | assert_eq!(
62 | ast.compile().unwrap(),
63 | "\
64 | #include
65 | #include
66 |
67 | using namespace metal;
68 |
69 | struct uniform_buffer_object
70 | {
71 | float4x4 u_model_view_projection;
72 | float u_scale;
73 | };
74 |
75 | struct main0_out
76 | {
77 | float3 v_normal [[user(locn0)]];
78 | float4 gl_Position [[position]];
79 | };
80 |
81 | struct main0_in
82 | {
83 | float4 a_position [[attribute(0)]];
84 | float3 a_normal [[attribute(1)]];
85 | };
86 |
87 | vertex main0_out main0(main0_in in [[stage_in]], constant uniform_buffer_object& _22 [[buffer(5)]])
88 | {
89 | main0_out out = {};
90 | out.v_normal = in.a_normal;
91 | out.gl_Position = (_22.u_model_view_projection * in.a_position) * _22.u_scale;
92 | return out;
93 | }
94 |
95 | "
96 | );
97 | assert_eq!(
98 | ast.get_cleansed_entry_point_name("main", spirv::ExecutionModel::Vertex)
99 | .unwrap(),
100 | "main0"
101 | );
102 | }
103 |
104 | #[test]
105 | fn captures_output_to_buffer() {
106 | let module =
107 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
108 | let mut ast = spirv::Ast::::parse(&module).unwrap();
109 | let mut compiler_options = msl::CompilerOptions::default();
110 | compiler_options.capture_output_to_buffer = true;
111 | compiler_options.output_buffer_index = 456;
112 | ast.set_compiler_options(&compiler_options).unwrap();
113 | assert_eq!(
114 | ast.compile().unwrap(),
115 | "\
116 | #include
117 | #include
118 |
119 | using namespace metal;
120 |
121 | struct uniform_buffer_object
122 | {
123 | float4x4 u_model_view_projection;
124 | float u_scale;
125 | };
126 |
127 | struct main0_out
128 | {
129 | float3 v_normal [[user(locn0)]];
130 | float4 gl_Position [[position]];
131 | };
132 |
133 | struct main0_in
134 | {
135 | float4 a_position [[attribute(0)]];
136 | float3 a_normal [[attribute(1)]];
137 | };
138 |
139 | vertex void main0(main0_in in [[stage_in]], constant uniform_buffer_object& _22 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]], uint gl_BaseVertex [[base_vertex]], uint gl_InstanceIndex [[instance_id]], uint gl_BaseInstance [[base_instance]], device main0_out* spvOut [[buffer(456)]], device uint* spvIndirectParams [[buffer(29)]])
140 | {
141 | device main0_out& out = spvOut[(gl_InstanceIndex - gl_BaseInstance) * spvIndirectParams[0] + gl_VertexIndex - gl_BaseVertex];
142 | out.v_normal = in.a_normal;
143 | out.gl_Position = (_22.u_model_view_projection * in.a_position) * _22.u_scale;
144 | }
145 |
146 | "
147 | );
148 | }
149 |
150 | #[test]
151 | fn swizzles_texture_samples() {
152 | let module =
153 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/sampler.frag.spv")));
154 | let mut ast = spirv::Ast::::parse(&module).unwrap();
155 | let mut compiler_options = msl::CompilerOptions::default();
156 | compiler_options.swizzle_texture_samples = true;
157 | compiler_options.swizzle_buffer_index = 123;
158 | ast.set_compiler_options(&compiler_options).unwrap();
159 | assert_eq!(
160 | ast.compile().unwrap(),
161 | "\
162 | #pragma clang diagnostic ignored \"-Wmissing-prototypes\"
163 |
164 | #include
165 | #include
166 |
167 | using namespace metal;
168 |
169 | struct main0_out
170 | {
171 | float4 target0 [[color(0)]];
172 | };
173 |
174 | struct main0_in
175 | {
176 | float2 v_uv [[user(locn0)]];
177 | };
178 |
179 | template struct spvRemoveReference { typedef T type; };
180 | template struct spvRemoveReference { typedef T type; };
181 | template struct spvRemoveReference { typedef T type; };
182 | template inline constexpr thread T&& spvForward(thread typename spvRemoveReference::type& x)
183 | {
184 | return static_cast(x);
185 | }
186 | template inline constexpr thread T&& spvForward(thread typename spvRemoveReference::type&& x)
187 | {
188 | return static_cast(x);
189 | }
190 |
191 | enum class spvSwizzle : uint
192 | {
193 | none = 0,
194 | zero,
195 | one,
196 | red,
197 | green,
198 | blue,
199 | alpha
200 | };
201 |
202 | template
203 | inline T spvGetSwizzle(vec x, T c, spvSwizzle s)
204 | {
205 | switch (s)
206 | {
207 | case spvSwizzle::none:
208 | return c;
209 | case spvSwizzle::zero:
210 | return 0;
211 | case spvSwizzle::one:
212 | return 1;
213 | case spvSwizzle::red:
214 | return x.r;
215 | case spvSwizzle::green:
216 | return x.g;
217 | case spvSwizzle::blue:
218 | return x.b;
219 | case spvSwizzle::alpha:
220 | return x.a;
221 | }
222 | }
223 |
224 | // Wrapper function that swizzles texture samples and fetches.
225 | template
226 | inline vec spvTextureSwizzle(vec x, uint s)
227 | {
228 | if (!s)
229 | return x;
230 | return vec(spvGetSwizzle(x, x.r, spvSwizzle((s >> 0) & 0xFF)), spvGetSwizzle(x, x.g, spvSwizzle((s >> 8) & 0xFF)), spvGetSwizzle(x, x.b, spvSwizzle((s >> 16) & 0xFF)), spvGetSwizzle(x, x.a, spvSwizzle((s >> 24) & 0xFF)));
231 | }
232 |
233 | template
234 | inline T spvTextureSwizzle(T x, uint s)
235 | {
236 | return spvTextureSwizzle(vec(x, 0, 0, 1), s).x;
237 | }
238 |
239 | fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvSwizzleConstants [[buffer(123)]], texture2d u_texture [[texture(0)]], sampler u_sampler [[sampler(0)]])
240 | {
241 | main0_out out = {};
242 | constant uint& u_textureSwzl = spvSwizzleConstants[0];
243 | out.target0 = spvTextureSwizzle(u_texture.sample(u_sampler, in.v_uv), u_textureSwzl);
244 | return out;
245 | }
246 |
247 | "
248 | );
249 | }
250 |
251 | #[test]
252 | fn sets_argument_buffer_index() {
253 | let module =
254 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/sampler.frag.spv")));
255 | let mut ast = spirv::Ast::::parse(&module).unwrap();
256 | let mut resource_binding_overrides = BTreeMap::new();
257 | resource_binding_overrides.insert(
258 | spirv_cross::msl::ResourceBindingLocation {
259 | stage: spirv::ExecutionModel::Fragment,
260 | desc_set: 0,
261 | binding: msl::ARGUMENT_BUFFER_BINDING,
262 | },
263 | spirv_cross::msl::ResourceBinding {
264 | buffer_id: 2,
265 | texture_id: 0,
266 | sampler_id: 0,
267 | count: 0,
268 | },
269 | );
270 | let mut compiler_options = msl::CompilerOptions::default();
271 | compiler_options.resource_binding_overrides = resource_binding_overrides;
272 | compiler_options.version = spirv_cross::msl::Version::V2_0;
273 | compiler_options.enable_argument_buffers = true;
274 | ast.set_compiler_options(&compiler_options).unwrap();
275 | assert_eq!(
276 | ast.compile().unwrap(),
277 | "\
278 | #include
279 | #include
280 |
281 | using namespace metal;
282 |
283 | struct spvDescriptorSetBuffer0
284 | {
285 | texture2d u_texture [[id(0)]];
286 | sampler u_sampler [[id(1)]];
287 | };
288 |
289 | struct main0_out
290 | {
291 | float4 target0 [[color(0)]];
292 | };
293 |
294 | struct main0_in
295 | {
296 | float2 v_uv [[user(locn0)]];
297 | };
298 |
299 | fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(2)]])
300 | {
301 | main0_out out = {};
302 | out.target0 = spvDescriptorSet0.u_texture.sample(spvDescriptorSet0.u_sampler, in.v_uv);
303 | return out;
304 | }
305 |
306 | ",
307 | );
308 | }
309 |
310 | #[test]
311 | fn forces_native_array() {
312 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
313 | "shaders/const_array.vert.spv"
314 | )));
315 |
316 | let cases = [
317 | (
318 | false,
319 | "\
320 | #pragma clang diagnostic ignored \"-Wmissing-prototypes\"
321 | #pragma clang diagnostic ignored \"-Wmissing-braces\"
322 |
323 | #include
324 | #include
325 |
326 | using namespace metal;
327 |
328 | template
329 | struct spvUnsafeArray
330 | {
331 | T elements[Num ? Num : 1];
332 |
333 | thread T& operator [] (size_t pos) thread
334 | {
335 | return elements[pos];
336 | }
337 | constexpr const thread T& operator [] (size_t pos) const thread
338 | {
339 | return elements[pos];
340 | }
341 |
342 | device T& operator [] (size_t pos) device
343 | {
344 | return elements[pos];
345 | }
346 | constexpr const device T& operator [] (size_t pos) const device
347 | {
348 | return elements[pos];
349 | }
350 |
351 | constexpr const constant T& operator [] (size_t pos) const constant
352 | {
353 | return elements[pos];
354 | }
355 |
356 | threadgroup T& operator [] (size_t pos) threadgroup
357 | {
358 | return elements[pos];
359 | }
360 | constexpr const threadgroup T& operator [] (size_t pos) const threadgroup
361 | {
362 | return elements[pos];
363 | }
364 | };
365 |
366 | constant spvUnsafeArray _23 = spvUnsafeArray({ float2(0.0, -0.5), float2(0.5), float2(-0.5, 0.5) });
367 |
368 | struct main0_out
369 | {
370 | float4 gl_Position [[position]];
371 | };
372 |
373 | vertex main0_out main0(uint gl_VertexIndex [[vertex_id]])
374 | {
375 | main0_out out = {};
376 | out.gl_Position = float4(_23[int(gl_VertexIndex)], 0.0, 1.0);
377 | return out;
378 | }
379 |
380 | "
381 | ),
382 | (
383 | true,
384 | "\
385 | #include
386 | #include
387 |
388 | using namespace metal;
389 |
390 | constant float2 _23[3] = { float2(0.0, -0.5), float2(0.5), float2(-0.5, 0.5) };
391 |
392 | struct main0_out
393 | {
394 | float4 gl_Position [[position]];
395 | };
396 |
397 | vertex main0_out main0(uint gl_VertexIndex [[vertex_id]])
398 | {
399 | main0_out out = {};
400 | out.gl_Position = float4(_23[int(gl_VertexIndex)], 0.0, 1.0);
401 | return out;
402 | }
403 |
404 | "
405 | )
406 | ];
407 | for (force_native_arrays, expected_result) in cases.iter() {
408 | let mut ast = spirv::Ast::::parse(&module).unwrap();
409 | let mut compiler_options = msl::CompilerOptions::default();
410 | compiler_options.force_native_arrays = *force_native_arrays;
411 | ast.set_compiler_options(&compiler_options).unwrap();
412 | assert_eq!(&ast.compile().unwrap(), expected_result);
413 | }
414 | }
415 |
416 | #[test]
417 | fn forces_zero_initialization() {
418 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
419 | "shaders/initialization.vert.spv"
420 | )));
421 |
422 | let cases = [
423 | (
424 | false,
425 | "\
426 | #include
427 | #include
428 |
429 | using namespace metal;
430 |
431 | struct main0_out
432 | {
433 | float4 gl_Position [[position]];
434 | };
435 |
436 | struct main0_in
437 | {
438 | float rand [[attribute(0)]];
439 | };
440 |
441 | vertex main0_out main0(main0_in in [[stage_in]])
442 | {
443 | main0_out out = {};
444 | float4 pos;
445 | if (in.rand > 0.5)
446 | {
447 | pos = float4(1.0);
448 | }
449 | out.gl_Position = pos;
450 | return out;
451 | }
452 |
453 | ",
454 | ),
455 | (
456 | true,
457 | "\
458 | #include
459 | #include
460 |
461 | using namespace metal;
462 |
463 | struct main0_out
464 | {
465 | float4 gl_Position [[position]];
466 | };
467 |
468 | struct main0_in
469 | {
470 | float rand [[attribute(0)]];
471 | };
472 |
473 | vertex main0_out main0(main0_in in [[stage_in]])
474 | {
475 | main0_out out = {};
476 | float4 pos = {};
477 | if (in.rand > 0.5)
478 | {
479 | pos = float4(1.0);
480 | }
481 | out.gl_Position = pos;
482 | return out;
483 | }
484 |
485 | ",
486 | ),
487 | ];
488 | for (force_zero_initialized_variables, expected_result) in cases.iter() {
489 | let mut ast = spirv::Ast::::parse(&module).unwrap();
490 | let mut compiler_options = msl::CompilerOptions::default();
491 | compiler_options.force_zero_initialized_variables = *force_zero_initialized_variables;
492 | ast.set_compiler_options(&compiler_options).unwrap();
493 | assert_eq!(&ast.compile().unwrap(), expected_result);
494 | }
495 | }
496 |
497 | #[test]
498 | fn ast_sets_entry_point() {
499 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
500 | "shaders/vs_and_fs.asm.spv"
501 | )));
502 |
503 | let mut cases = vec![
504 | (
505 | None,
506 | "\
507 | #include
508 | #include
509 |
510 | using namespace metal;
511 |
512 | struct main_vs_out
513 | {
514 | float4 gl_Position [[position]];
515 | };
516 |
517 | vertex main_vs_out main_vs()
518 | {
519 | main_vs_out out = {};
520 | out.gl_Position = float4(1.0);
521 | return out;
522 | }
523 |
524 | ",
525 | ),
526 | (
527 | Some((String::from("main_vs"), spirv::ExecutionModel::Vertex)),
528 | "\
529 | #include
530 | #include
531 |
532 | using namespace metal;
533 |
534 | struct main_vs_out
535 | {
536 | float4 gl_Position [[position]];
537 | };
538 |
539 | vertex main_vs_out main_vs()
540 | {
541 | main_vs_out out = {};
542 | out.gl_Position = float4(1.0);
543 | return out;
544 | }
545 |
546 | ",
547 | ),
548 | (
549 | Some((String::from("main_fs"), spirv::ExecutionModel::Fragment)),
550 | "\
551 | #include
552 | #include
553 |
554 | using namespace metal;
555 |
556 | struct main_fs_out
557 | {
558 | float4 color [[color(0)]];
559 | };
560 |
561 | fragment main_fs_out main_fs()
562 | {
563 | main_fs_out out = {};
564 | out.color = float4(1.0);
565 | return out;
566 | }
567 |
568 | ",
569 | ),
570 | ];
571 |
572 | for (entry_point, expected_result) in cases.drain(..) {
573 | let mut ast = spirv::Ast::::parse(&module).unwrap();
574 | let mut compiler_options = msl::CompilerOptions::default();
575 | compiler_options.entry_point = entry_point;
576 | ast.set_compiler_options(&compiler_options).unwrap();
577 | assert_eq!(&ast.compile().unwrap(), expected_result);
578 | }
579 | }
580 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/array.vert:
--------------------------------------------------------------------------------
1 | #version 310 es
2 |
3 | layout(std140) uniform uniform_buffer_object
4 | {
5 | mat4 u_model_view_projection;
6 | float u_scale;
7 | vec3 u_bias[3];
8 | };
9 |
10 | layout(location = 0) in vec4 a_position;
11 | layout(location = 1) in vec3 a_normal;
12 | layout(location = 0) out vec3 v_normal;
13 | layout(location = 1) out vec3 v_bias;
14 |
15 | void main()
16 | {
17 | v_normal = a_normal;
18 | v_bias = u_bias[gl_VertexIndex];
19 | gl_Position = u_model_view_projection * a_position * u_scale;
20 | }
21 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/array.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/array.vert.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/const_array.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | out gl_PerVertex {
4 | vec4 gl_Position;
5 | };
6 |
7 | const vec2 positions[3] = vec2[3](
8 | vec2(0.0, -0.5),
9 | vec2(0.5, 0.5),
10 | vec2(-0.5, 0.5)
11 | );
12 |
13 | void main() {
14 | gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
15 | }
16 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/const_array.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/const_array.vert.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/initialization.vert:
--------------------------------------------------------------------------------
1 | #version 310 es
2 |
3 | layout(location = 0) in float rand;
4 |
5 | void main()
6 | {
7 | vec4 pos;
8 |
9 | if (rand > 0.5) {
10 | pos = vec4(1.0);
11 | }
12 |
13 | gl_Position = pos;
14 | }
15 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/initialization.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/initialization.vert.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/multiple_entry_points.cl:
--------------------------------------------------------------------------------
1 | __kernel void entry_1() {}
2 | __kernel void entry_2() {}
3 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/multiple_entry_points.cl.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/multiple_entry_points.cl.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/rasterize_disabled.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location = 0) in vec4 input_buffer;
4 |
5 | layout(binding = 0, std140) uniform iu
6 | {
7 | uvec4 m[2];
8 | } input_uniform;
9 |
10 | layout(binding = 1, std430) writeonly buffer ob
11 | {
12 | uvec4 m[2];
13 | } output_buffer;
14 |
15 | void main()
16 | {
17 | gl_Position = input_buffer;
18 | for (int i = 0; i < 2; i++)
19 | {
20 | output_buffer.m[i] = input_uniform.m[i];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/rasterize_disabled.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/rasterize_disabled.vert.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/sampler.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 | #extension GL_ARB_separate_shader_objects : enable
3 |
4 | layout(location = 0) in vec2 v_uv;
5 | layout(location = 0) out vec4 target0;
6 |
7 | layout(set = 0, binding = 0) uniform texture2D u_texture;
8 | layout(set = 0, binding = 1) uniform sampler u_sampler;
9 |
10 | void main() {
11 | target0 = texture(sampler2D(u_texture, u_sampler), v_uv);
12 | }
13 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/sampler.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/sampler.frag.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/simple.vert:
--------------------------------------------------------------------------------
1 | #version 310 es
2 |
3 | layout(std140) uniform uniform_buffer_object
4 | {
5 | mat4 u_model_view_projection;
6 | float u_scale;
7 | };
8 |
9 | layout(location = 0) in vec4 a_position;
10 | layout(location = 1) in vec3 a_normal;
11 | layout(location = 0) out vec3 v_normal;
12 |
13 | void main()
14 | {
15 | v_normal = a_normal;
16 | gl_Position = u_model_view_projection * a_position * u_scale;
17 | }
18 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/simple.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/simple.vert.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/specialization.comp:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout (constant_id = 10) const int CONSTANT = 123;
4 |
5 | void main() {}
6 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/specialization.comp.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/specialization.comp.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/struct.frag:
--------------------------------------------------------------------------------
1 | #version 310 es
2 | precision mediump float;
3 |
4 | struct W
5 | {
6 | vec4 e;
7 | vec4 f;
8 | vec4 g;
9 | vec4 h;
10 | };
11 |
12 | layout(location = 0) in W w;
13 |
14 | layout(location = 0) out vec4 color;
15 |
16 | void main() {
17 | color = vec4(w.e.x, w.f.y, w.g.z, w.h.w);
18 | }
19 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/struct.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/struct.frag.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/struct.vert:
--------------------------------------------------------------------------------
1 | #version 310 es
2 |
3 | layout(location = 0) in vec4 a;
4 | layout(location = 1) in vec4 b;
5 | layout(location = 2) in vec4 c;
6 | layout(location = 3) in vec4 d;
7 |
8 | struct V
9 | {
10 | vec4 a;
11 | vec4 b;
12 | vec4 c;
13 | vec4 d;
14 | };
15 |
16 | layout(location = 0) out V v;
17 |
18 | void main()
19 | {
20 | v = V(a, b, c, d);
21 | }
22 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/struct.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/struct.vert.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/two_ubo.vert:
--------------------------------------------------------------------------------
1 | #version 310 es
2 |
3 | layout(std140) uniform ubo1
4 | {
5 | mat4 a;
6 | float b;
7 | vec4 c[2];
8 | };
9 |
10 | layout(std140) uniform ubo2
11 | {
12 | float d;
13 | vec3 e;
14 | vec3 f;
15 | };
16 |
17 | void main()
18 | {
19 | gl_Position = vec4(a[1][2] + b + c[1].y + d + e.x + f.z);
20 | }
21 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/two_ubo.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/two_ubo.vert.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/vs_and_fs.asm:
--------------------------------------------------------------------------------
1 | ; SPIR-V
2 | ; Version: 1.0
3 | ; Generator: Khronos SPIR-V Tools Assembler; 0
4 | ; Bound: 25
5 | ; Schema: 0
6 | OpCapability Shader
7 | %1 = OpExtInstImport "GLSL.std.450"
8 | OpMemoryModel Logical GLSL450
9 | OpEntryPoint Vertex %main_vs "main_vs" %_
10 | OpEntryPoint Fragment %main_fs "main_fs" %color
11 | OpExecutionMode %main_fs OriginUpperLeft
12 | OpSource GLSL 330
13 | OpName %main_vs "main_vs"
14 | OpName %main_fs "main_fs"
15 | OpName %gl_PerVertex "gl_PerVertex"
16 | OpMemberName %gl_PerVertex 0 "gl_Position"
17 | OpMemberName %gl_PerVertex 1 "gl_PointSize"
18 | OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
19 | OpName %_ ""
20 | OpName %color "color"
21 | OpDecorate %color Location 0
22 | OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
23 | OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
24 | OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
25 | OpDecorate %gl_PerVertex Block
26 | %void = OpTypeVoid
27 | %3 = OpTypeFunction %void
28 | %float = OpTypeFloat 32
29 | %v4float = OpTypeVector %float 4
30 | %uint = OpTypeInt 32 0
31 | %uint_1 = OpConstant %uint 1
32 | %_arr_float_uint_1 = OpTypeArray %float %uint_1
33 | %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1
34 | %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
35 | %_ = OpVariable %_ptr_Output_gl_PerVertex Output
36 | %int = OpTypeInt 32 1
37 | %int_0 = OpConstant %int 0
38 | %float_1 = OpConstant %float 1
39 | %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
40 | %_ptr_Output_v4float = OpTypePointer Output %v4float
41 | %main_vs = OpFunction %void None %3
42 | %5 = OpLabel
43 | %21 = OpAccessChain %_ptr_Output_v4float %_ %int_0
44 | OpStore %21 %19
45 | OpReturn
46 | OpFunctionEnd
47 | %4 = OpTypeFunction %void
48 | %color = OpVariable %_ptr_Output_v4float Output
49 | %13 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
50 | %main_fs = OpFunction %void None %4
51 | %6 = OpLabel
52 | OpStore %color %13
53 | OpReturn
54 | OpFunctionEnd
55 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/vs_and_fs.asm.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/vs_and_fs.asm.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/workgroup.comp:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(local_size_x_id = 5, local_size_y_id = 10, local_size_z_id = 15) in;
4 |
5 | void main()
6 | {
7 | // See https://github.com/KhronosGroup/glslang/issues/557
8 | gl_WorkGroupSize;
9 | }
10 |
--------------------------------------------------------------------------------
/spirv_cross/tests/shaders/workgroup.comp.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grovesNL/spirv_cross/aae970dee36e8f5eca528ee4a60c0e08d93641c1/spirv_cross/tests/shaders/workgroup.comp.spv
--------------------------------------------------------------------------------
/spirv_cross/tests/spirv_tests.rs:
--------------------------------------------------------------------------------
1 | use spirv_cross::{hlsl as lang, spirv};
2 |
3 | mod common;
4 | use crate::common::words_from_bytes;
5 |
6 | #[test]
7 | fn ast_gets_multiple_entry_points() {
8 | let module = spirv::Module::from_words(words_from_bytes(include_bytes!(
9 | "shaders/multiple_entry_points.cl.spv"
10 | )));
11 | let entry_points = spirv::Ast::::parse(&module)
12 | .unwrap()
13 | .get_entry_points()
14 | .unwrap();
15 |
16 | assert_eq!(entry_points.len(), 2);
17 | assert!(entry_points.iter().any(|e| e.name == "entry_1"));
18 | assert!(entry_points.iter().any(|e| e.name == "entry_2"));
19 | }
20 |
21 | #[test]
22 | fn ast_gets_shader_resources() {
23 | let module =
24 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
25 | let shader_resources = spirv::Ast::::parse(&module)
26 | .unwrap()
27 | .get_shader_resources()
28 | .unwrap();
29 |
30 | let spirv::ShaderResources {
31 | uniform_buffers,
32 | stage_inputs,
33 | stage_outputs,
34 | ..
35 | } = shader_resources;
36 |
37 | assert_eq!(uniform_buffers.len(), 1);
38 | assert_eq!(uniform_buffers[0].name, "uniform_buffer_object");
39 | assert_eq!(shader_resources.storage_buffers.len(), 0);
40 | assert_eq!(stage_inputs.len(), 2);
41 | assert!(stage_inputs
42 | .iter()
43 | .any(|stage_input| stage_input.name == "a_normal"));
44 | assert!(stage_inputs
45 | .iter()
46 | .any(|stage_input| stage_input.name == "a_position"));
47 | assert_eq!(stage_outputs.len(), 1);
48 | assert!(stage_outputs
49 | .iter()
50 | .any(|stage_output| stage_output.name == "v_normal"));
51 | assert_eq!(shader_resources.subpass_inputs.len(), 0);
52 | assert_eq!(shader_resources.storage_images.len(), 0);
53 | assert_eq!(shader_resources.sampled_images.len(), 0);
54 | assert_eq!(shader_resources.atomic_counters.len(), 0);
55 | assert_eq!(shader_resources.push_constant_buffers.len(), 0);
56 | assert_eq!(shader_resources.separate_images.len(), 0);
57 | assert_eq!(shader_resources.separate_samplers.len(), 0);
58 | }
59 |
60 | #[test]
61 | fn ast_gets_decoration() {
62 | let module =
63 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
64 | let ast = spirv::Ast::::parse(&module).unwrap();
65 |
66 | let stage_inputs = ast.get_shader_resources().unwrap().stage_inputs;
67 | let decoration = ast
68 | .get_decoration(stage_inputs[0].id, spirv::Decoration::DescriptorSet)
69 | .unwrap();
70 | assert_eq!(decoration, 0);
71 | }
72 |
73 | #[test]
74 | fn ast_sets_decoration() {
75 | let module =
76 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
77 | let mut ast = spirv::Ast::::parse(&module).unwrap();
78 |
79 | let stage_inputs = ast.get_shader_resources().unwrap().stage_inputs;
80 | let updated_value = 3;
81 | ast.set_decoration(
82 | stage_inputs[0].id,
83 | spirv::Decoration::DescriptorSet,
84 | updated_value,
85 | )
86 | .unwrap();
87 | assert_eq!(
88 | ast.get_decoration(stage_inputs[0].id, spirv::Decoration::DescriptorSet)
89 | .unwrap(),
90 | updated_value
91 | );
92 | }
93 |
94 | #[test]
95 | fn ast_gets_type_member_types_and_array() {
96 | let module =
97 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
98 | let ast = spirv::Ast::::parse(&module).unwrap();
99 |
100 | let uniform_buffers = ast.get_shader_resources().unwrap().uniform_buffers;
101 |
102 | let is_struct = match ast.get_type(uniform_buffers[0].base_type_id).unwrap() {
103 | spirv::Type::Struct {
104 | member_types,
105 | array,
106 | array_size_literal
107 | } => {
108 | assert_eq!(member_types.len(), 2);
109 | assert_eq!(array.len(), 0);
110 | assert_eq!(array_size_literal.len(), 0);
111 | true
112 | }
113 | _ => false,
114 | };
115 |
116 | assert!(is_struct);
117 | }
118 |
119 | #[test]
120 | fn ast_gets_array_dimensions() {
121 | let module =
122 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/array.vert.spv")));
123 | let ast = spirv::Ast::::parse(&module).unwrap();
124 |
125 | let uniform_buffers = ast.get_shader_resources().unwrap().uniform_buffers;
126 |
127 | let is_struct = match ast.get_type(uniform_buffers[0].base_type_id).unwrap() {
128 | spirv::Type::Struct { member_types, .. } => {
129 | assert_eq!(member_types.len(), 3);
130 | let is_float = match ast.get_type(member_types[2]).unwrap() {
131 | spirv::Type::Float {
132 | vecsize,
133 | columns,
134 | array,
135 | array_size_literal
136 | } => {
137 | assert_eq!(vecsize, 3);
138 | assert_eq!(columns, 1);
139 | assert_eq!(array.len(), 1);
140 | assert_eq!(array_size_literal.len(), 1);
141 | assert_eq!(array[0], 3);
142 | assert_eq!(array_size_literal[0], true);
143 | true
144 | }
145 | _ => false,
146 | };
147 | assert!(is_float);
148 | true
149 | }
150 | _ => false,
151 | };
152 |
153 | assert!(is_struct);
154 | }
155 |
156 | #[test]
157 | fn ast_gets_declared_struct_size_and_struct_member_size() {
158 | let module =
159 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
160 | let ast = spirv::Ast::::parse(&module).unwrap();
161 | let uniform_buffers = ast.get_shader_resources().unwrap().uniform_buffers;
162 | let mat4_size = 4 * 16;
163 | let float_size = 4;
164 | assert_eq!(
165 | ast.get_declared_struct_size(uniform_buffers[0].base_type_id)
166 | .unwrap(),
167 | mat4_size + float_size
168 | );
169 | assert_eq!(
170 | ast.get_declared_struct_member_size(uniform_buffers[0].base_type_id, 0)
171 | .unwrap(),
172 | mat4_size
173 | );
174 | assert_eq!(
175 | ast.get_declared_struct_member_size(uniform_buffers[0].base_type_id, 1)
176 | .unwrap(),
177 | float_size
178 | );
179 | }
180 |
181 | #[test]
182 | fn ast_gets_member_name() {
183 | let module =
184 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
185 | let ast = spirv::Ast::::parse(&module).unwrap();
186 |
187 | let uniform_buffers = ast.get_shader_resources().unwrap().uniform_buffers;
188 |
189 | assert_eq!(
190 | ast.get_member_name(uniform_buffers[0].base_type_id, 0)
191 | .unwrap(),
192 | "u_model_view_projection"
193 | );
194 | }
195 |
196 | #[test]
197 | fn ast_gets_member_decoration() {
198 | let module =
199 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
200 | let ast = spirv::Ast::::parse(&module).unwrap();
201 |
202 | let uniform_buffers = ast.get_shader_resources().unwrap().uniform_buffers;
203 |
204 | assert_eq!(
205 | ast.get_member_decoration(
206 | uniform_buffers[0].base_type_id,
207 | 1,
208 | spirv::Decoration::Offset
209 | )
210 | .unwrap(),
211 | 64
212 | );
213 | }
214 |
215 | #[test]
216 | fn ast_sets_member_decoration() {
217 | let module =
218 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/simple.vert.spv")));
219 | let mut ast = spirv::Ast::::parse(&module).unwrap();
220 |
221 | let uniform_buffers = ast.get_shader_resources().unwrap().uniform_buffers;
222 |
223 | let new_offset = 128;
224 |
225 | ast.set_member_decoration(
226 | uniform_buffers[0].base_type_id,
227 | 1,
228 | spirv::Decoration::Offset,
229 | new_offset,
230 | )
231 | .unwrap();
232 |
233 | assert_eq!(
234 | ast.get_member_decoration(
235 | uniform_buffers[0].base_type_id,
236 | 1,
237 | spirv::Decoration::Offset
238 | )
239 | .unwrap(),
240 | new_offset
241 | );
242 | }
243 |
244 | #[test]
245 | fn ast_gets_specialization_constants() {
246 | let comp = spirv::Module::from_words(words_from_bytes(include_bytes!(
247 | "shaders/specialization.comp.spv"
248 | )));
249 | let comp_ast = spirv::Ast::::parse(&comp).unwrap();
250 | let specialization_constants = comp_ast.get_specialization_constants().unwrap();
251 | assert_eq!(specialization_constants[0].constant_id, 10);
252 | }
253 |
254 | #[test]
255 | fn ast_gets_work_group_size_specialization_constants() {
256 | let comp = spirv::Module::from_words(words_from_bytes(include_bytes!(
257 | "shaders/workgroup.comp.spv"
258 | )));
259 | let comp_ast = spirv::Ast::::parse(&comp).unwrap();
260 | let work_group_size = comp_ast
261 | .get_work_group_size_specialization_constants()
262 | .unwrap();
263 | assert_eq!(
264 | work_group_size,
265 | spirv::WorkGroupSizeSpecializationConstants {
266 | x: spirv::SpecializationConstant {
267 | id: 7,
268 | constant_id: 5,
269 | },
270 | y: spirv::SpecializationConstant {
271 | id: 8,
272 | constant_id: 10,
273 | },
274 | z: spirv::SpecializationConstant {
275 | id: 9,
276 | constant_id: 15,
277 | },
278 | }
279 | );
280 | }
281 |
282 | #[test]
283 | fn ast_gets_active_buffer_ranges() {
284 | let module =
285 | spirv::Module::from_words(words_from_bytes(include_bytes!("shaders/two_ubo.vert.spv")));
286 | let ast = spirv::Ast::::parse(&module).unwrap();
287 |
288 | let uniform_buffers = ast.get_shader_resources().unwrap().uniform_buffers;
289 | assert_eq!(uniform_buffers.len(), 2);
290 |
291 | let ubo1 = ast.get_active_buffer_ranges(uniform_buffers[0].id).unwrap();
292 | assert_eq!(
293 | ubo1,
294 | [
295 | spirv::BufferRange {
296 | index: 0,
297 | offset: 0,
298 | range: 64,
299 | },
300 | spirv::BufferRange {
301 | index: 1,
302 | offset: 64,
303 | range: 16,
304 | },
305 | spirv::BufferRange {
306 | index: 2,
307 | offset: 80,
308 | range: 32,
309 | }
310 | ]
311 | );
312 |
313 | let ubo2 = ast.get_active_buffer_ranges(uniform_buffers[1].id).unwrap();
314 | assert_eq!(
315 | ubo2,
316 | [
317 | spirv::BufferRange {
318 | index: 0,
319 | offset: 0,
320 | range: 16,
321 | },
322 | spirv::BufferRange {
323 | index: 1,
324 | offset: 16,
325 | range: 16,
326 | },
327 | spirv::BufferRange {
328 | index: 2,
329 | offset: 32,
330 | range: 12,
331 | }
332 | ]
333 | );
334 | }
335 |
--------------------------------------------------------------------------------
/wasm/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "wasm"
3 | version = "0.1.0"
4 | authors = ["Joshua Groves "]
5 |
6 | [[bin]]
7 | name = "wasm"
8 | path = "src/main.rs"
9 |
--------------------------------------------------------------------------------
/wasm/spirv_cross_wrapper_glsl.js:
--------------------------------------------------------------------------------
1 |
2 | var sc_internal_wrapper = (function() {
3 | var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
4 | if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
5 | return (
6 | function(sc_internal_wrapper) {
7 | sc_internal_wrapper = sc_internal_wrapper || {};
8 |
9 | var a;a||(a=typeof sc_internal_wrapper !== 'undefined' ? sc_internal_wrapper : {});var g={},k;for(k in a)a.hasOwnProperty(k)&&(g[k]=a[k]);var l=!1,m=!1,n=!1,aa=!1,p=!1;l="object"===typeof window;m="function"===typeof importScripts;n=(aa="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node)&&!l&&!m;p=!l&&!n&&!m;var q="",r,t,u,v;
10 | if(n)q=__dirname+"/",r=function(b,c){u||(u=require("fs"));v||(v=require("path"));b=v.normalize(b);return u.readFileSync(b,c?null:"utf8")},t=function(b){b=r(b,!0);b.buffer||(b=new Uint8Array(b));b.buffer||w("Assertion failed: undefined");return b},1=e);)++d;if(16f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e}function F(b){return b?E(G,b,void 0):""}
15 | "undefined"!==typeof TextDecoder&&new TextDecoder("utf-16le");var buffer,H,G,I;function N(b){buffer=b;a.HEAP8=H=new Int8Array(b);a.HEAP16=new Int16Array(b);a.HEAP32=I=new Int32Array(b);a.HEAPU8=G=new Uint8Array(b);a.HEAPU16=new Uint16Array(b);a.HEAPU32=new Uint32Array(b);a.HEAPF32=new Float32Array(b);a.HEAPF64=new Float64Array(b)}var O=a.TOTAL_MEMORY||16777216;a.wasmMemory?A=a.wasmMemory:A=new WebAssembly.Memory({initial:O/65536});A&&(buffer=A.buffer);O=buffer.byteLength;N(buffer);I[10980]=5286960;
16 | function P(b){for(;0=d;d*=2){var e=c*(1+.2/d);e=Math.min(e,b+100663296);e=Math.max(16777216,b,e);0>16);N(A.buffer);var f=1;break a}catch(h){}f=
20 | void 0}if(f)return!0}return!1},i:function(){return 0},c:function(){return 0},h:function(b,c,d,e){try{for(var f=0,h=0;h>2],da=I[c+(8*h+4)>>2],J=0;J>2]=f;return 0}catch(M){return"undefined"!==typeof FS&&M instanceof FS.T||w(M),M.U}},memory:A,table:ba},ma=function(){function b(b){a.asm=b.exports;T--;a.monitorRunDependencies&&a.monitorRunDependencies(T);0==T&&(null!==U&&(clearInterval(U),
21 | U=null),V&&(b=V,V=null,b()))}function c(c){b(c.instance)}function d(b){return ia().then(function(b){return WebAssembly.instantiate(b,e)}).then(b,function(b){y("failed to asynchronously prepare wasm: "+b);w(b)})}var e={env:la,wasi_snapshot_preview1:la};T++;a.monitorRunDependencies&&a.monitorRunDependencies(T);if(a.instantiateWasm)try{return a.instantiateWasm(e,b)}catch(f){return y("Module.instantiateWasm callback failed with error: "+f),!1}(function(){if(z||"function"!==typeof WebAssembly.instantiateStreaming||
22 | W()||"function"!==typeof fetch)return d(c);fetch(X,{credentials:"same-origin"}).then(function(b){return WebAssembly.instantiateStreaming(b,e).then(c,function(b){y("wasm streaming compile failed: "+b);y("falling back to ArrayBuffer instantiation");d(c)})})})();return{}}();a.asm=ma;var ja=a.___wasm_call_ctors=function(){return(ja=a.___wasm_call_ctors=a.asm.j).apply(null,arguments)};
23 | a._sc_internal_get_latest_exception_message=function(){return(a._sc_internal_get_latest_exception_message=a.asm.k).apply(null,arguments)};a._sc_internal_compiler_glsl_new=function(){return(a._sc_internal_compiler_glsl_new=a.asm.l).apply(null,arguments)};a._sc_internal_compiler_glsl_set_options=function(){return(a._sc_internal_compiler_glsl_set_options=a.asm.m).apply(null,arguments)};
24 | a._sc_internal_compiler_glsl_build_combined_image_samplers=function(){return(a._sc_internal_compiler_glsl_build_combined_image_samplers=a.asm.n).apply(null,arguments)};a._sc_internal_compiler_glsl_get_combined_image_samplers=function(){return(a._sc_internal_compiler_glsl_get_combined_image_samplers=a.asm.o).apply(null,arguments)};a._sc_internal_compiler_glsl_add_header_line=function(){return(a._sc_internal_compiler_glsl_add_header_line=a.asm.p).apply(null,arguments)};
25 | a._sc_internal_compiler_glsl_flatten_buffer_block=function(){return(a._sc_internal_compiler_glsl_flatten_buffer_block=a.asm.q).apply(null,arguments)};a._sc_internal_compiler_get_decoration=function(){return(a._sc_internal_compiler_get_decoration=a.asm.r).apply(null,arguments)};a._sc_internal_compiler_unset_decoration=function(){return(a._sc_internal_compiler_unset_decoration=a.asm.s).apply(null,arguments)};
26 | a._sc_internal_compiler_set_decoration=function(){return(a._sc_internal_compiler_set_decoration=a.asm.t).apply(null,arguments)};a._sc_internal_compiler_get_name=function(){return(a._sc_internal_compiler_get_name=a.asm.u).apply(null,arguments)};a._sc_internal_compiler_set_name=function(){return(a._sc_internal_compiler_set_name=a.asm.v).apply(null,arguments)};a._sc_internal_compiler_get_entry_points=function(){return(a._sc_internal_compiler_get_entry_points=a.asm.w).apply(null,arguments)};
27 | a._malloc=function(){return(a._malloc=a.asm.x).apply(null,arguments)};a._free=function(){return(a._free=a.asm.y).apply(null,arguments)};a._sc_internal_compiler_get_cleansed_entry_point_name=function(){return(a._sc_internal_compiler_get_cleansed_entry_point_name=a.asm.z).apply(null,arguments)};a._sc_internal_compiler_get_shader_resources=function(){return(a._sc_internal_compiler_get_shader_resources=a.asm.A).apply(null,arguments)};
28 | a._sc_internal_compiler_get_specialization_constants=function(){return(a._sc_internal_compiler_get_specialization_constants=a.asm.B).apply(null,arguments)};a._sc_internal_compiler_set_scalar_constant=function(){return(a._sc_internal_compiler_set_scalar_constant=a.asm.C).apply(null,arguments)};a._sc_internal_compiler_get_type=function(){return(a._sc_internal_compiler_get_type=a.asm.D).apply(null,arguments)};
29 | a._sc_internal_compiler_get_member_name=function(){return(a._sc_internal_compiler_get_member_name=a.asm.E).apply(null,arguments)};a._sc_internal_compiler_get_member_decoration=function(){return(a._sc_internal_compiler_get_member_decoration=a.asm.F).apply(null,arguments)};a._sc_internal_compiler_set_member_decoration=function(){return(a._sc_internal_compiler_set_member_decoration=a.asm.G).apply(null,arguments)};
30 | a._sc_internal_compiler_get_declared_struct_size=function(){return(a._sc_internal_compiler_get_declared_struct_size=a.asm.H).apply(null,arguments)};a._sc_internal_compiler_get_declared_struct_member_size=function(){return(a._sc_internal_compiler_get_declared_struct_member_size=a.asm.I).apply(null,arguments)};a._sc_internal_compiler_rename_interface_variable=function(){return(a._sc_internal_compiler_rename_interface_variable=a.asm.J).apply(null,arguments)};
31 | a._sc_internal_compiler_get_work_group_size_specialization_constants=function(){return(a._sc_internal_compiler_get_work_group_size_specialization_constants=a.asm.K).apply(null,arguments)};a._sc_internal_compiler_set_entry_point=function(){return(a._sc_internal_compiler_set_entry_point=a.asm.L).apply(null,arguments)};a._sc_internal_compiler_compile=function(){return(a._sc_internal_compiler_compile=a.asm.M).apply(null,arguments)};
32 | a._sc_internal_compiler_delete=function(){return(a._sc_internal_compiler_delete=a.asm.N).apply(null,arguments)};a._sc_internal_free_pointer=function(){return(a._sc_internal_free_pointer=a.asm.O).apply(null,arguments)};a.dynCall_vi=function(){return(a.dynCall_vi=a.asm.P).apply(null,arguments)};a.dynCall_v=function(){return(a.dynCall_v=a.asm.Q).apply(null,arguments)};a.asm=ma;var Y;a.then=function(b){if(Y)b(a);else{var c=a.onRuntimeInitialized;a.onRuntimeInitialized=function(){c&&c();b(a)}}return a};
33 | V=function na(){Y||Z();Y||(V=na)};
34 | function Z(){function b(){if(!Y&&(Y=!0,!B)){P(R);P(ca);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;){var b=a.postRun.shift();S.unshift(b)}P(S)}}if(!(0