├── .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 |
5 | Safe wrapper around SPIR-V Cross 6 |
7 |
8 |
9 | Crate Travis Build Status Appveyor Build Status 10 |
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