├── .github ├── CODEOWNERS ├── pull_request_template.md ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── precompile.yml │ └── rust-ci.yml ├── .gitignore ├── spirv-tools-sys ├── generated │ ├── build-version.inc │ ├── spv-amd-shader-explicit-vertex-parameter.insts.inc │ ├── spv-amd-gcn-shader.insts.inc │ ├── spv-amd-shader-ballot.insts.inc │ ├── spv-amd-shader-trinary-minmax.insts.inc │ ├── generators.inc │ ├── extension_enum.inc │ ├── debuginfo.insts.inc │ ├── nonsemantic.clspvreflection.insts.inc │ ├── nonsemantic.shader.debuginfo.100.insts.inc │ ├── opencl.debuginfo.100.insts.inc │ ├── glsl.std.450.insts.inc │ └── NonSemanticShaderDebugInfo100.h ├── src │ ├── lib.rs │ ├── diagnostics.rs │ ├── assembler.rs │ ├── val.rs │ ├── c │ │ └── opt.cpp │ └── shared.rs ├── generate.sh ├── Cargo.toml ├── README.md ├── generate.rs └── build.rs ├── tests ├── assembled_content.spv ├── wgpu_example_shader.spv ├── test_content.txt ├── assembler.rs ├── val.rs ├── issue_22.rs └── optimizer.rs ├── examples └── assembler │ ├── Cargo.toml │ └── src │ └── main.rs ├── tools ├── install │ ├── Cargo.toml │ └── main.rs └── package │ ├── Cargo.toml │ └── main.rs ├── .gitmodules ├── src ├── lib.rs ├── assembler │ ├── tool.rs │ └── compiled.rs ├── opt.rs ├── val │ ├── tool.rs │ └── compiled.rs ├── assembler.rs ├── val.rs ├── binary.rs ├── error.rs ├── opt │ ├── tool.rs │ └── compiled.rs └── cmd.rs ├── .mergify.yml ├── release.toml ├── deny.toml ├── LICENSE-MIT ├── Cargo.toml ├── README.md ├── .cargo └── config.toml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CHANGELOG.md └── LICENSE-APACHE /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Jake-Shadle 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | spirv-tools-sys/target 3 | **/*.rs.bk 4 | Cargo.lock 5 | tools/bin 6 | tools/*.zst -------------------------------------------------------------------------------- /spirv-tools-sys/generated/build-version.inc: -------------------------------------------------------------------------------- 1 | "v2023.6", "SPIRV-Tools v2023.6 v2023.6.rc1-0-gf0cc85ef" 2 | -------------------------------------------------------------------------------- /tests/assembled_content.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmbarkStudios/spirv-tools-rs/HEAD/tests/assembled_content.spv -------------------------------------------------------------------------------- /tests/wgpu_example_shader.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmbarkStudios/spirv-tools-rs/HEAD/tests/wgpu_example_shader.spv -------------------------------------------------------------------------------- /examples/assembler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "assembler" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | clap = { version = "4.4", features = ["derive"] } 8 | spirv-tools = { path = "../../", features = ["use-compiled-tools"] } 9 | -------------------------------------------------------------------------------- /tools/install/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "install" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [[bin]] 8 | name = "install" 9 | path = "main.rs" 10 | test = false 11 | bench = false 12 | 13 | [dependencies] 14 | tar = "0.4" 15 | zstd = "0.13" 16 | -------------------------------------------------------------------------------- /tools/package/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "package" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [[bin]] 8 | name = "package" 9 | path = "main.rs" 10 | test = false 11 | bench = false 12 | 13 | [dependencies] 14 | tar = "0.4" 15 | zstd = "0.13" 16 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/spv-amd-shader-explicit-vertex-parameter.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t spv_amd_shader_explicit_vertex_parameter_entries[] = { 4 | {"InterpolateAtVertexAMD", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}} 5 | }; -------------------------------------------------------------------------------- /tests/test_content.txt: -------------------------------------------------------------------------------- 1 | OpCapability Shader 2 | OpMemoryModel Logical Simple 3 | OpEntryPoint GLCompute %3 "main" 4 | OpExecutionMode %3 LocalSize 64 64 1 5 | %1 = OpTypeVoid 6 | %2 = OpTypeFunction %1 7 | %3 = OpFunction %1 None %2 8 | %4 = OpLabel 9 | OpReturn 10 | OpFunctionEnd -------------------------------------------------------------------------------- /spirv-tools-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(any(feature = "use-installed-tools", feature = "use-compiled-tools")))] 2 | compile_error!("Enable at least one of `use-compiled-tools` or `use-installed-tools` features"); 3 | 4 | pub mod assembler; 5 | pub mod diagnostics; 6 | pub mod opt; 7 | pub mod shared; 8 | pub mod val; 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "spirv-tools-sys/spirv-headers"] 2 | path = spirv-tools-sys/spirv-headers 3 | url = https://github.com/KhronosGroup/SPIRV-Headers.git 4 | branch = vulkan-sdk-1.3.275 5 | [submodule "spirv-tools-sys/spirv-tools"] 6 | path = spirv-tools-sys/spirv-tools 7 | url = https://github.com/KhronosGroup/SPIRV-Tools 8 | branch = vulkan-sdk-1.3.275 9 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/spv-amd-gcn-shader.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t spv_amd_gcn_shader_entries[] = { 4 | {"CubeFaceIndexAMD", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 5 | {"CubeFaceCoordAMD", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 6 | {"TimeAMD", 3, 0, nullptr, {SPV_OPERAND_TYPE_NONE}} 7 | }; -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Checklist 2 | 3 | * [ ] I have read the [Contributor Guide](../../CONTRIBUTING.md) 4 | * [ ] I have read and agree to the [Code of Conduct](../../CODE_OF_CONDUCT.md) 5 | * [ ] I have added a description of my changes and why I'd like them included in the section below 6 | 7 | ### Description of Changes 8 | 9 | Describe your changes here 10 | 11 | ### Related Issues 12 | 13 | List related issues here 14 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unsafe_code)] 2 | 3 | #[cfg(not(any(feature = "use-installed-tools", feature = "use-compiled-tools")))] 4 | compile_error!("Enable at least one of `use-compiled-tools` or `use-installed-tools` features"); 5 | 6 | pub mod assembler; 7 | pub mod binary; 8 | pub mod opt; 9 | pub mod val; 10 | 11 | pub mod error; 12 | pub use error::{Error, SpirvResult}; 13 | 14 | pub use spirv_tools_sys::shared::TargetEnv; 15 | 16 | #[cfg(feature = "use-installed-tools")] 17 | pub(crate) mod cmd; 18 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: automatic merge when CI passes and 1 reviews 3 | conditions: 4 | - "#approved-reviews-by>=1" 5 | - "#review-requested=0" 6 | - "#changes-requested-reviews-by=0" 7 | - "#commented-reviews-by=0" 8 | - base=main 9 | - label!=work-in-progress 10 | actions: 11 | merge: 12 | method: squash 13 | - name: delete head branch after merge 14 | conditions: [] 15 | actions: 16 | delete_head_branch: {} 17 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/spv-amd-shader-ballot.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t spv_amd_shader_ballot_entries[] = { 4 | {"SwizzleInvocationsAMD", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 5 | {"SwizzleInvocationsMaskedAMD", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 6 | {"WriteInvocationAMD", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 7 | {"MbcntAMD", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}} 8 | }; -------------------------------------------------------------------------------- /spirv-tools-sys/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | dir=$(dirname "$(dirname "$0")") 5 | 6 | if ! [ -d "${dir}/target" ]; then 7 | mkdir "${dir}/target" 8 | fi 9 | 10 | # Compile our "script" if the binary doesn't already exist 11 | if [ "${1-}" == "-f" ] || ! [ -f "${dir}/target/generate" ]; then 12 | echo "Compiling generate..." 13 | 14 | rustc -g -o "${dir}/target/generate" "${dir}/spirv-tools-sys/generate.rs" 15 | 16 | if [ "${1-}" == "-f" ]; then 17 | # remove the force flag when sending the arguments to generate 18 | shift 19 | fi 20 | fi 21 | 22 | gen=$(realpath "${dir}/target/generate") 23 | (cd spirv-tools-sys && $gen "${@}") 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | pre-release-commit-message = "Release {{version}}" 2 | tag-message = "Release {{version}}" 3 | tag-name = "{{version}}" 4 | pre-release-replacements = [ 5 | { file = "CHANGELOG.md", search = "Unreleased", replace = "{{version}}" }, 6 | { file = "CHANGELOG.md", search = "\\.\\.\\.HEAD", replace = "...{{tag_name}}" }, 7 | { file = "CHANGELOG.md", search = "ReleaseDate", replace = "{{date}}" }, 8 | { file = "CHANGELOG.md", search = "", replace = "\n## [Unreleased] - ReleaseDate" }, 9 | { file = "CHANGELOG.md", search = "", replace = "\n[Unreleased]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/{{tag_name}}...HEAD" }, 10 | ] 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Device:** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | all-features = true 2 | # This is CI use only and doesn't affect the crates or downstream users 3 | exclude = ["package"] 4 | 5 | [advisories] 6 | vulnerability = "deny" 7 | unmaintained = "deny" 8 | yanked = "deny" 9 | notice = "deny" 10 | ignore = [] 11 | 12 | [licenses] 13 | unlicensed = "deny" 14 | allow = ["MIT", "Apache-2.0"] 15 | copyleft = "deny" 16 | allow-osi-fsf-free = "neither" 17 | default = "deny" 18 | exceptions = [] 19 | 20 | [bans] 21 | multiple-versions = "deny" 22 | wildcards = "deny" 23 | skip = [ 24 | # Use via redox_syscall which is removed from tempfile but not yet released 25 | # https://github.com/Stebalien/tempfile/pull/272 26 | { name = "bitflags", version = "=1.3.2" }, 27 | ] 28 | 29 | [sources] 30 | unknown-registry = "deny" 31 | unknown-git = "deny" 32 | allow-git = [] 33 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Embark Studios 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /.github/workflows/precompile.yml: -------------------------------------------------------------------------------- 1 | on: workflow_dispatch 2 | 3 | name: Precompile spirv-tools binaries 4 | jobs: 5 | build: 6 | name: Build 7 | strategy: 8 | matrix: 9 | include: 10 | - os: ubuntu-22.04 11 | target: x86_64-unknown-linux-gnu 12 | - os: windows-2022 13 | target: x86_64-pc-windows-msvc 14 | - os: macOS-13 15 | target: aarch64-apple-darwin 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | submodules: true 21 | - name: Mount Bazel cache 22 | uses: actions/cache@v4 23 | with: 24 | path: ~/.bazel/cache 25 | key: cache-${{ matrix.target }} 26 | - name: Build 27 | shell: bash 28 | run: cargo run -p package -- ${{ matrix.target }} ~/.bazel/cache 29 | - name: Upload 30 | id: upload 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: ${{ matrix.target }}-binaries 34 | path: tools/${{ matrix.target }}.tar.zst 35 | - run: echo 'Artifact ID is ${{ steps.upload.outputs.artifact-id }}' 36 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/spv-amd-shader-trinary-minmax.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t spv_amd_shader_trinary_minmax_entries[] = { 4 | {"FMin3AMD", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 5 | {"UMin3AMD", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 6 | {"SMin3AMD", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 7 | {"FMax3AMD", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 8 | {"UMax3AMD", 5, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 9 | {"SMax3AMD", 6, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 10 | {"FMid3AMD", 7, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 11 | {"UMid3AMD", 8, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 12 | {"SMid3AMD", 9, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}} 13 | }; -------------------------------------------------------------------------------- /tests/assembler.rs: -------------------------------------------------------------------------------- 1 | //const TEXT_INPUT: &str = include_str!("test_content.txt"); 2 | const ASSEMBLY_INPUT: &str = include_str!("test_content.txt"); 3 | 4 | use spirv_tools as spv; 5 | 6 | use spv::{assembler::Assembler, val::Validator}; 7 | 8 | #[test] 9 | fn assemblers_match() { 10 | let cas = spv::assembler::compiled::CompiledAssembler::default(); 11 | let ias = spv::assembler::tool::ToolAssembler::default(); 12 | 13 | let cval = spv::val::compiled::CompiledValidator::default(); 14 | let ival = spv::val::tool::ToolValidator::default(); 15 | 16 | let cassembled = cas 17 | .assemble(ASSEMBLY_INPUT, spv::assembler::AssemblerOptions::default()) 18 | .expect("compiled failed to assemble"); 19 | let iassembled = ias 20 | .assemble(ASSEMBLY_INPUT, spv::assembler::AssemblerOptions::default()) 21 | .expect("tool failed to assemble"); 22 | 23 | cval.validate(&cassembled, None) 24 | .expect("failed to validate input assembly"); 25 | 26 | ival.validate(&cassembled, None) 27 | .expect("failed to validate input assembly"); 28 | 29 | cval.validate(&iassembled, None) 30 | .expect("failed to validate input assembly"); 31 | 32 | ival.validate(&iassembled, None) 33 | .expect("failed to validate input assembly"); 34 | } 35 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | workspace = { members = ["tools/package", "tools/install"] } 2 | 3 | [package] 4 | name = "spirv-tools" 5 | description = "Wrapper crate for SPIRV-Tools" 6 | repository = "https://github.com/EmbarkStudios/spirv-tools-rs" 7 | version = "0.10.0" 8 | authors = ["Embark "] 9 | edition = "2021" 10 | license = "MIT OR Apache-2.0" 11 | readme = "README.md" 12 | documentation = "https://docs.rs/spirv-tools" 13 | homepage = "https://github.com/EmbarkStudios/spirv-tools-rs" 14 | keywords = ["spir-v", "rust-gpu"] 15 | categories = ["rendering::data-formats"] 16 | exclude = [".github", "release.toml"] 17 | 18 | [features] 19 | default = ["use-compiled-tools"] 20 | use-installed-tools = [ 21 | "spirv-tools-sys/use-installed-tools", 22 | "memchr", 23 | "tempfile", 24 | ] 25 | use-compiled-tools = ["spirv-tools-sys/use-compiled-tools"] 26 | 27 | [dependencies] 28 | spirv-tools-sys = { version = "0.8", path = "./spirv-tools-sys", default-features = false } 29 | # Used for parsing output when running binaries 30 | memchr = { version = "2.3", optional = true } 31 | tempfile = { version = "3.1", optional = true } 32 | 33 | [dev-dependencies] 34 | similar = "2.0" 35 | 36 | [[test]] 37 | name = "optimizer" 38 | required-features = ["use-compiled-tools", "use-installed-tools"] 39 | 40 | [[test]] 41 | name = "assembler" 42 | required-features = ["use-compiled-tools", "use-installed-tools"] 43 | 44 | [[test]] 45 | name = "issue_22" 46 | required-features = ["use-compiled-tools", "use-installed-tools"] 47 | -------------------------------------------------------------------------------- /spirv-tools-sys/src/diagnostics.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | pub struct Position { 3 | pub line: usize, 4 | pub column: usize, 5 | pub index: usize, 6 | } 7 | 8 | #[repr(C)] 9 | pub struct Diagnostic { 10 | pub position: Position, 11 | pub error: *const std::os::raw::c_char, 12 | pub is_text_source: bool, 13 | } 14 | 15 | #[derive(Copy, Clone, PartialEq, Debug)] 16 | #[repr(C)] 17 | pub enum MessageLevel { 18 | /// Unrecoverable error due to environment. 19 | /// Will exit the program immediately. E.g., 20 | /// out of memory. 21 | Fatal, 22 | /// Unrecoverable error due to SPIRV-Tools 23 | /// internals. 24 | /// Will exit the program immediately. E.g., 25 | /// unimplemented feature. 26 | InternalError, 27 | /// Normal error due to user input. 28 | Error, 29 | /// Warning information. 30 | Warning, 31 | /// General information. 32 | Info, 33 | /// Debug information. 34 | Debug, 35 | } 36 | 37 | pub type MessageCallback = extern "C" fn( 38 | MessageLevel, // level 39 | *const std::os::raw::c_char, // source 40 | *const Position, // source position 41 | *const std::os::raw::c_char, // the actual message 42 | *mut std::ffi::c_void, // context we use for mapping 43 | ); 44 | 45 | extern "C" { 46 | /// Destroys a diagnostic object. This is a no-op if diagnostic is a null 47 | /// pointer. 48 | #[link_name = "spvDiagnosticDestroy"] 49 | pub fn diagnostic_destroy(diag: *mut Diagnostic); 50 | } 51 | -------------------------------------------------------------------------------- /spirv-tools-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spirv-tools-sys" 3 | description = "Wrapper crate for SPIRV-Tools" 4 | repository = "https://github.com/EmbarkStudios/spirv-tools-rs" 5 | version = "0.8.0" 6 | authors = ["Embark "] 7 | edition = "2021" 8 | # This is the same license for the underlying SPIRV-Tools code 9 | license = "Apache-2.0" 10 | documentation = "https://docs.rs/spirv-tools-sys" 11 | readme = "README.md" 12 | homepage = "https://github.com/EmbarkStudios/spirv-tools-rs" 13 | keywords = ["spir-v", "rust-gpu"] 14 | categories = ["rendering::data-formats"] 15 | build = "build.rs" 16 | links = "spirv-tools" 17 | include = [ 18 | "generated", 19 | "spirv-headers/include", 20 | "spirv-tools/include", 21 | "!spirv-tools/source/diff", 22 | "!spirv-tools/source/fuzz", 23 | "!spirv-tools/source/link", 24 | "!spirv-tools/source/lint", 25 | "!spirv-tools/source/reduce", 26 | "!spirv-tools/source/wasm", 27 | "spirv-tools/source", 28 | "src/**", 29 | "build.rs", 30 | "Cargo.toml", 31 | "README.md", 32 | ] 33 | 34 | [features] 35 | default = ["use-compiled-tools"] 36 | # Using this feature disables the compilation in the build script, but 37 | # preserves the types so that spirv-tools can still work without needing 38 | # to keep copies of some of the basic enums etc 39 | use-installed-tools = [] 40 | # Forces compilation of the C++ code, even if `use-installed-tools` is enabled 41 | use-compiled-tools = [] 42 | 43 | [build-dependencies] 44 | cc = { version = "1.0", features = ["parallel"] } 45 | -------------------------------------------------------------------------------- /tests/val.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unnecessary_wraps)] 2 | 3 | const SPIRV_BIN: &[u8] = include_bytes!("wgpu_example_shader.spv"); 4 | 5 | fn validate_compiled(_input: &[u8]) -> Option> { 6 | #[cfg(feature = "use-compiled-tools")] 7 | { 8 | use spirv_tools::val::{compiled::CompiledValidator, Validator}; 9 | let cv = CompiledValidator::default(); 10 | Some(cv.validate(spirv_tools::binary::to_binary(_input).unwrap(), None)) 11 | } 12 | #[cfg(not(feature = "use-compiled-tools"))] 13 | None 14 | } 15 | 16 | fn validate_tool(_input: &[u8]) -> Option> { 17 | #[cfg(feature = "use-installed-tools")] 18 | { 19 | use spirv_tools::val::{tool::ToolValidator, Validator}; 20 | let cv = ToolValidator::default(); 21 | Some(cv.validate(spirv_tools::binary::to_binary(_input).unwrap(), None)) 22 | } 23 | #[cfg(not(feature = "use-installed-tools"))] 24 | None 25 | } 26 | 27 | #[test] 28 | fn gets_error_message() { 29 | let expected_msg = "error:0:0 - Loop header '6[%loop_header]' is targeted by 2 back-edge blocks but the standard requires exactly one"; 30 | let expected_notes = " %loop_header = OpLabel\n"; 31 | 32 | for res in validate_compiled(SPIRV_BIN) 33 | .into_iter() 34 | .chain(validate_tool(SPIRV_BIN).into_iter()) 35 | { 36 | let err = res.unwrap_err(); 37 | let diag = err.diagnostic.as_ref().unwrap(); 38 | assert_eq!(diag.line, 0); 39 | assert_eq!(diag.column, 0); 40 | assert_eq!(diag.message, &expected_msg[12..]); 41 | assert_eq!(diag.notes, expected_notes); 42 | 43 | let err_str = err.to_string(); 44 | assert_eq!(&err_str[..113], expected_msg); 45 | assert_eq!(&err_str[113 + 1..], expected_notes); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /spirv-tools-sys/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # `🛠 spirv-tools-sys` 4 | 5 | [![Embark](https://img.shields.io/badge/embark-open%20source-blueviolet.svg)](https://embark.dev) 6 | [![Embark](https://img.shields.io/badge/discord-ark-%237289da.svg?logo=discord)](https://discord.gg/dAuKfZS) 7 | [![Crates.io](https://img.shields.io/crates/v/spirv-tools-sys.svg)](https://crates.io/crates/spirv-tools-sys) 8 | [![Docs](https://docs.rs/spirv-tools-sys/badge.svg)](https://docs.rs/spirv-tools-sys) 9 | [![dependency status](https://deps.rs/repo/github/EmbarkStudios/spirv-tools-sys/status.svg)](https://deps.rs/repo/github/EmbarkStudios/spirv-tools) 10 | [![Build status](https://github.com/EmbarkStudios/spirv-tools-rs/workflows/CI/badge.svg)](https://github.com/EmbarkStudios/spirv-tools-rs/actions) 11 | 12 | This crate is an unofficial wrapper for [SPIR-V Tools], its primary use case is for the [rust-gpu] project. 13 | 14 |
15 | 16 | ## Status 17 | 18 | This is a very rough wrapper around the assembler, validator, and (most of the) optimizer tools available from [SPIR-V Tools], which is enough for the current needs of the [rust-gpu] project. See that project's code for more thorough usage examples. 19 | 20 | ## Contributing 21 | 22 | [![Contributor Covenant](https://img.shields.io/badge/contributor%20covenant-v1.4-ff69b4.svg)](../CODE_OF_CONDUCT.md) 23 | 24 | We welcome community contributions to this project. 25 | 26 | Please read our [Contributor Guide](../CONTRIBUTING.md) for more information on how to get started. 27 | 28 | ## License 29 | 30 | Apache License, Version 2.0, ([LICENSE-APACHE](spirv-tools/LICENSE) or ) 31 | 32 | ### Contribution 33 | 34 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions. 35 | 36 | [SPIR-V Tools]: https://github.com/KhronosGroup/SPIRV-Tools 37 | [rust-gpu]: https://github.com/EmbarkStudios/rust-gpu 38 | -------------------------------------------------------------------------------- /tests/issue_22.rs: -------------------------------------------------------------------------------- 1 | use spirv_tools as spv; 2 | use spv::{assembler::Assembler, opt::Optimizer, val::Validator}; 3 | 4 | const CONTENT: &str = r#"OpCapability Shader 5 | OpMemoryModel Logical Simple 6 | OpEntryPoint Fragment %main "main" 7 | OpExecutionMode %main OriginUpperLeft 8 | %file = OpString "file" 9 | %void = OpTypeVoid 10 | %3 = OpTypeFunction %void 11 | %main = OpFunction %void None %3 12 | %5 = OpLabel 13 | OpLine %file 1 1 14 | OpReturn 15 | OpFunctionEnd"#; 16 | 17 | #[test] 18 | fn issue() { 19 | let cas = spv::assembler::compiled::CompiledAssembler::default(); 20 | let assembled = cas 21 | .assemble(CONTENT, spv::assembler::AssemblerOptions::default()) 22 | .expect("compiled failed to assemble"); 23 | 24 | let val = spv::val::create(None); 25 | val.validate(&assembled, None) 26 | .expect("failed to validate input assembly"); 27 | 28 | let mut iopt = spv::opt::tool::ToolOptimizer::default(); 29 | iopt.register_pass(spv::opt::Passes::StripDebugInfo); 30 | let mut copt = spv::opt::compiled::CompiledOptimizer::default(); 31 | copt.register_pass(spv::opt::Passes::StripDebugInfo); 32 | 33 | let iopt_output = iopt 34 | .optimize( 35 | &assembled, 36 | &mut |msg| { 37 | eprintln!("[tool] optimizer message: {:#?}", msg); 38 | }, 39 | None, 40 | ) 41 | .expect("failed to run tool optimizer"); 42 | 43 | let copt_output = copt 44 | .optimize( 45 | &assembled, 46 | &mut |msg| { 47 | eprintln!("[compiled] optimizer message: {:#?}", msg); 48 | }, 49 | None, 50 | ) 51 | .expect("failed to run compiled optimizer"); 52 | 53 | val.validate(iopt_output, None) 54 | .expect("failed to validate tool output"); 55 | val.validate(copt_output, None) 56 | .expect("failed to validate compiled output"); 57 | } 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # `🛠 spirv-tools` 4 | 5 | **Unofficial wrapper for [SPIR-V Tools], primarily for the [rust-gpu] project** 6 | 7 | [![Embark](https://img.shields.io/badge/embark-open%20source-blueviolet.svg)](https://embark.dev) 8 | [![Embark](https://img.shields.io/badge/discord-ark-%237289da.svg?logo=discord)](https://discord.gg/dAuKfZS) 9 | [![Crates.io](https://img.shields.io/crates/v/spirv-tools.svg)](https://crates.io/crates/spirv-tools) 10 | [![Docs](https://docs.rs/spirv-tools/badge.svg)](https://docs.rs/spirv-tools) 11 | [![dependency status](https://deps.rs/repo/github/EmbarkStudios/spirv-tools/status.svg)](https://deps.rs/repo/github/EmbarkStudios/spirv-tools) 12 | [![Build status](https://github.com/EmbarkStudios/spirv-tools-rs/workflows/CI/badge.svg)](https://github.com/EmbarkStudios/spirv-tools-rs/actions) 13 | 14 |
15 | 16 | ## Status 17 | 18 | This is a very rough wrapper around the assembler, validator, and (most of the) optimizer tools available from [SPIR-V Tools], which is enough for the current needs of the [rust-gpu] project. See that project's code for more thorough usage examples. 19 | 20 | ## Contributing 21 | 22 | [![Contributor Covenant](https://img.shields.io/badge/contributor%20covenant-v1.4-ff69b4.svg)](CODE_OF_CONDUCT.md) 23 | 24 | We welcome community contributions to this project. 25 | 26 | Please read our [Contributor Guide](CONTRIBUTING.md) for more information on how to get started. 27 | 28 | ## License 29 | 30 | Licensed under either of 31 | 32 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) 33 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) 34 | 35 | at your option. 36 | 37 | ### Contribution 38 | 39 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. 40 | 41 | [SPIR-V Tools]: https://github.com/KhronosGroup/SPIRV-Tools 42 | [rust-gpu]: https://github.com/EmbarkStudios/rust-gpu 43 | -------------------------------------------------------------------------------- /tests/optimizer.rs: -------------------------------------------------------------------------------- 1 | //const TEXT_INPUT: &str = include_str!("test_content.txt"); 2 | const ASSEMBLY_INPUT: &[u8] = include_bytes!("assembled_content.spv"); 3 | 4 | use spirv_tools as spv; 5 | 6 | use spv::{assembler::Assembler, opt::Optimizer, val::Validator}; 7 | use std::convert::TryFrom; 8 | 9 | #[test] 10 | fn compiled_matches_binary() { 11 | let mut copt = spv::opt::compiled::CompiledOptimizer::default(); 12 | copt.register_size_passes(); 13 | let mut iopt = spv::opt::tool::ToolOptimizer::default(); 14 | iopt.register_size_passes(); 15 | 16 | let val = spv::val::create(None); 17 | 18 | let assembled = spv::binary::Binary::try_from(ASSEMBLY_INPUT.to_vec()) 19 | .expect("failed to load assembled output"); 20 | 21 | val.validate(&assembled, None) 22 | .expect("failed to validate input assembly"); 23 | 24 | let iopt_output = iopt 25 | .optimize( 26 | &assembled, 27 | &mut |msg| { 28 | eprintln!("[tool] optimizer message: {:#?}", msg); 29 | }, 30 | None, 31 | ) 32 | .expect("failed to run tool optimizer"); 33 | 34 | let copt_output = copt 35 | .optimize( 36 | &assembled, 37 | &mut |msg| { 38 | eprintln!("[compiled] optimizer message: {:#?}", msg); 39 | }, 40 | None, 41 | ) 42 | .expect("failed to run compiled optimizer"); 43 | 44 | let assembler = spv::assembler::create(None); 45 | 46 | let idisasm = assembler 47 | .disassemble(&iopt_output, spv::assembler::DisassembleOptions::default()) 48 | .unwrap() 49 | .unwrap(); 50 | let cdisasm = assembler 51 | .disassemble(&copt_output, spv::assembler::DisassembleOptions::default()) 52 | .unwrap() 53 | .unwrap(); 54 | 55 | if idisasm != cdisasm { 56 | let diff = similar::TextDiff::from_lines(&idisasm, &cdisasm); 57 | eprintln!("{}", diff.unified_diff().header("cli", "compiled")); 58 | 59 | panic!("the disassembled text for the cli and the compiled dissassembler did not match"); 60 | } 61 | 62 | val.validate(iopt_output, None) 63 | .expect("failed to validate tool output"); 64 | val.validate(copt_output, None) 65 | .expect("failed to validate compiled output"); 66 | } 67 | -------------------------------------------------------------------------------- /src/assembler/tool.rs: -------------------------------------------------------------------------------- 1 | pub struct ToolAssembler { 2 | target_env: crate::TargetEnv, 3 | } 4 | 5 | use super::Assembler; 6 | 7 | impl Assembler for ToolAssembler { 8 | fn with_env(target_env: crate::TargetEnv) -> Self { 9 | Self { target_env } 10 | } 11 | 12 | fn assemble( 13 | &self, 14 | text: &str, 15 | options: super::AssemblerOptions, 16 | ) -> Result { 17 | let mut cmd = std::process::Command::new("spirv-as"); 18 | cmd.arg("--target-env").arg(self.target_env.to_string()); 19 | 20 | if options.preserve_numeric_ids { 21 | cmd.arg("--preserve-numeric-ids"); 22 | } 23 | 24 | let cmd_output = 25 | crate::cmd::exec(cmd, Some(text.as_bytes()), crate::cmd::Output::Retrieve)?; 26 | 27 | crate::binary::Binary::try_from(cmd_output.binary) 28 | } 29 | 30 | fn disassemble( 31 | &self, 32 | binary: impl AsRef<[u32]>, 33 | options: super::DisassembleOptions, 34 | ) -> Result, crate::error::Error> { 35 | let mut cmd = std::process::Command::new("spirv-dis"); 36 | 37 | if options.color { 38 | cmd.arg("--color"); 39 | } 40 | 41 | if !options.indent { 42 | cmd.arg("--no-indent"); 43 | } 44 | 45 | if options.show_byte_offset { 46 | cmd.arg("--offsets"); 47 | } 48 | 49 | if options.no_header { 50 | cmd.arg("--no-header"); 51 | } 52 | 53 | if !options.use_friendly_names { 54 | cmd.arg("--raw-id"); 55 | } 56 | 57 | if options.comment { 58 | cmd.arg("--comment"); 59 | } 60 | 61 | let bytes = crate::binary::from_binary(binary.as_ref()); 62 | 63 | let cmd_output = crate::cmd::exec(cmd, Some(bytes), crate::cmd::Output::Retrieve)?; 64 | 65 | String::from_utf8(cmd_output.binary) 66 | .map_err(|e| crate::error::Error { 67 | inner: spirv_tools_sys::shared::SpirvResult::InvalidText, 68 | diagnostic: Some(format!("spirv disassemble returned non-utf8 text: {}", e).into()), 69 | }) 70 | .map(|s| if s.is_empty() { None } else { Some(s) }) 71 | } 72 | } 73 | 74 | impl Default for ToolAssembler { 75 | fn default() -> Self { 76 | Self::with_env(crate::TargetEnv::default()) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /examples/assembler/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | 3 | /// Create a SPIR-V binary module from SPIR-V assembly text 4 | #[derive(Parser)] 5 | struct Args { 6 | /// Set the output filename. Use '-' for stdout. 7 | #[clap(short, default_value = "out.spv")] 8 | output: String, 9 | /// Numeric IDs in the binary will have the same values as in the 10 | /// source. Non-numeric IDs are allocated by filling in the gaps, 11 | /// starting with 1 and going up. 12 | #[clap(long = "preserve-numeric-ids")] 13 | preserve_ids: bool, 14 | /// Use specified environment. 15 | #[clap(long = "target-env")] 16 | target_env: Option, 17 | /// The input file. Use '-' for stdin. 18 | #[clap(name = "FILE")] 19 | input: String, 20 | } 21 | 22 | fn main() { 23 | use spirv_tools::assembler::{self, Assembler}; 24 | 25 | let args = Args::parse(); 26 | 27 | let contents = if args.input == "-" { 28 | use std::io::Read; 29 | let mut v = Vec::with_capacity(1024); 30 | std::io::stdin() 31 | .read_to_end(&mut v) 32 | .expect("failed to read stdin"); 33 | String::from_utf8(v).expect("stdin had invalid utf-8") 34 | } else { 35 | std::fs::read_to_string(&args.input).expect("failed to read input file") 36 | }; 37 | 38 | let assembler_opts = assembler::AssemblerOptions { 39 | preserve_numeric_ids: args.preserve_ids, 40 | }; 41 | 42 | let assembler = 43 | assembler::compiled::CompiledAssembler::with_env(args.target_env.unwrap_or_default()); 44 | 45 | match assembler.assemble(&contents, assembler_opts) { 46 | Ok(binary) => { 47 | let len = binary.as_bytes().len(); 48 | 49 | if args.output == "-" { 50 | use std::io::Write; 51 | std::io::stdout() 52 | .lock() 53 | .write_all(binary.as_ref()) 54 | .expect("failed to write binary to stdout"); 55 | } else { 56 | std::fs::write(&args.output, &binary).expect("failed to write binary"); 57 | } 58 | 59 | println!( 60 | "wrote {len}b to {}", 61 | if args.output == "-" { 62 | "" 63 | } else { 64 | args.output.as_str() 65 | } 66 | ); 67 | } 68 | Err(e) => { 69 | eprintln!("{e}"); 70 | std::process::exit(1); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /.github/workflows/rust-ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | 7 | # Cancel PR actions on new commits 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 10 | cancel-in-progress: true 11 | 12 | name: CI 13 | jobs: 14 | lint: 15 | name: Lint 16 | runs-on: ubuntu-22.04 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | submodules: true 21 | - uses: dtolnay/rust-toolchain@stable 22 | with: 23 | components: clippy, rustfmt 24 | 25 | # make sure all code has been formatted with rustfmt 26 | - name: check rustfmt 27 | run: cargo fmt -- --check --color always 28 | 29 | # run clippy to verify we have no warnings 30 | - run: cargo fetch 31 | - name: cargo clippy 32 | run: cargo clippy --all-targets --all-features -- -D warnings 33 | 34 | test: 35 | name: Test 36 | strategy: 37 | matrix: 38 | include: 39 | - os: ubuntu-22.04 40 | target: x86_64-unknown-linux-gnu 41 | - os: windows-2022 42 | target: x86_64-pc-windows-msvc 43 | - os: macOS-14 44 | target: aarch64-apple-darwin 45 | runs-on: ${{ matrix.os }} 46 | steps: 47 | - uses: actions/checkout@v4 48 | with: 49 | submodules: true 50 | - uses: dtolnay/rust-toolchain@stable 51 | - run: cargo run -p install -- ${{matrix.target}} __internal__binaries__ "${{github.workspace}}/bin" 52 | - run: cargo fetch 53 | - name: cargo test build 54 | run: cargo build --tests --release --all-features 55 | - name: cargo test 56 | run: cargo test --release --all-features 57 | 58 | # Remove this check if you don't use cargo-deny in the repo 59 | deny-check: 60 | name: cargo-deny 61 | runs-on: ubuntu-22.04 62 | steps: 63 | - uses: actions/checkout@v4 64 | with: 65 | submodules: true 66 | - uses: EmbarkStudios/cargo-deny-action@v1 67 | 68 | # Remove this check if you don't publish the crate(s) from this repo 69 | publish-check: 70 | name: Publish Check 71 | runs-on: ubuntu-22.04 72 | steps: 73 | - uses: actions/checkout@v4 74 | with: 75 | submodules: true 76 | - uses: dtolnay/rust-toolchain@stable 77 | - run: cargo fetch 78 | - name: cargo publish check 79 | run: cargo publish --dry-run --manifest-path spirv-tools-sys/Cargo.toml 80 | - name: cargo publish check 81 | run: cargo publish --dry-run --manifest-path Cargo.toml 82 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/generators.inc: -------------------------------------------------------------------------------- 1 | {0, "Khronos", "", "Khronos"}, 2 | {1, "LunarG", "", "LunarG"}, 3 | {2, "Valve", "", "Valve"}, 4 | {3, "Codeplay", "", "Codeplay"}, 5 | {4, "NVIDIA", "", "NVIDIA"}, 6 | {5, "ARM", "", "ARM"}, 7 | {6, "Khronos", "LLVM/SPIR-V Translator", "Khronos LLVM/SPIR-V Translator"}, 8 | {7, "Khronos", "SPIR-V Tools Assembler", "Khronos SPIR-V Tools Assembler"}, 9 | {8, "Khronos", "Glslang Reference Front End", "Khronos Glslang Reference Front End"}, 10 | {9, "Qualcomm", "", "Qualcomm"}, 11 | {10, "AMD", "", "AMD"}, 12 | {11, "Intel", "", "Intel"}, 13 | {12, "Imagination", "", "Imagination"}, 14 | {13, "Google", "Shaderc over Glslang", "Google Shaderc over Glslang"}, 15 | {14, "Google", "spiregg", "Google spiregg"}, 16 | {15, "Google", "rspirv", "Google rspirv"}, 17 | {16, "X-LEGEND", "Mesa-IR/SPIR-V Translator", "X-LEGEND Mesa-IR/SPIR-V Translator"}, 18 | {17, "Khronos", "SPIR-V Tools Linker", "Khronos SPIR-V Tools Linker"}, 19 | {18, "Wine", "VKD3D Shader Compiler", "Wine VKD3D Shader Compiler"}, 20 | {19, "Tellusim", "Clay Shader Compiler", "Tellusim Clay Shader Compiler"}, 21 | {20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"}, 22 | {21, "Google", "Clspv", "Google Clspv"}, 23 | {22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"}, 24 | {23, "Google", "Tint Compiler", "Google Tint Compiler"}, 25 | {24, "Google", "ANGLE Shader Compiler", "Google ANGLE Shader Compiler"}, 26 | {25, "Netease Games", "Messiah Shader Compiler", "Netease Games Messiah Shader Compiler"}, 27 | {26, "Xenia", "Xenia Emulator Microcode Translator", "Xenia Xenia Emulator Microcode Translator"}, 28 | {27, "Embark Studios", "Rust GPU Compiler Backend", "Embark Studios Rust GPU Compiler Backend"}, 29 | {28, "gfx-rs community", "Naga", "gfx-rs community Naga"}, 30 | {29, "Mikkosoft Productions", "MSP Shader Compiler", "Mikkosoft Productions MSP Shader Compiler"}, 31 | {30, "SpvGenTwo community", "SpvGenTwo SPIR-V IR Tools", "SpvGenTwo community SpvGenTwo SPIR-V IR Tools"}, 32 | {31, "Google", "Skia SkSL", "Google Skia SkSL"}, 33 | {32, "TornadoVM", "Beehive SPIRV Toolkit", "TornadoVM Beehive SPIRV Toolkit"}, 34 | {33, "DragonJoker", "ShaderWriter", "DragonJoker ShaderWriter"}, 35 | {34, "Rayan Hatout", "SPIRVSmith", "Rayan Hatout SPIRVSmith"}, 36 | {35, "Saarland University", "Shady", "Saarland University Shady"}, 37 | {36, "Taichi Graphics", "Taichi", "Taichi Graphics Taichi"}, 38 | {37, "heroseh", "Hero C Compiler", "heroseh Hero C Compiler"}, 39 | {38, "Meta", "SparkSL", "Meta SparkSL"}, 40 | {39, "SirLynix", "Nazara ShaderLang Compiler", "SirLynix Nazara ShaderLang Compiler"}, 41 | {40, "NVIDIA", "Slang Compiler", "NVIDIA Slang Compiler"}, -------------------------------------------------------------------------------- /src/opt.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use-compiled-tools")] 2 | pub mod compiled; 3 | #[cfg(feature = "use-installed-tools")] 4 | pub mod tool; 5 | 6 | pub use spirv_tools_sys::opt::Passes; 7 | 8 | /// Options for specifying the behavior of the optimizer 9 | #[derive(Default, Clone)] 10 | pub struct Options { 11 | /// Records the validator options that should be passed to the validator, 12 | /// the validator will run with the options before optimizer. 13 | pub validator_options: Option, 14 | /// Records the maximum possible value for the id bound. 15 | pub max_id_bound: Option, 16 | /// Records whether all bindings within the module should be preserved. 17 | pub preserve_bindings: bool, 18 | /// Records whether all specialization constants within the module 19 | /// should be preserved. 20 | pub preserve_spec_constants: bool, 21 | } 22 | 23 | pub trait Optimizer { 24 | fn with_env(target_env: crate::TargetEnv) -> Self; 25 | 26 | fn optimize( 27 | &self, 28 | input: impl AsRef<[u32]>, 29 | msg_callback: &mut MC, 30 | options: Option, 31 | ) -> Result; 32 | 33 | /// Register a single pass with the the optimizer. 34 | fn register_pass(&mut self, pass: Passes) -> &mut Self; 35 | /// Registers passes that attempt to improve performance of generated code. 36 | /// This sequence of passes is subject to constant review and will change 37 | /// from time to time. 38 | fn register_performance_passes(&mut self) -> &mut Self; 39 | /// Registers passes that attempt to improve the size of generated code. 40 | /// This sequence of passes is subject to constant review and will change 41 | /// from time to time. 42 | fn register_size_passes(&mut self) -> &mut Self; 43 | /// Registers passes that attempt to legalize the generated code. 44 | /// 45 | /// Note: this recipe is specially designed for legalizing SPIR-V. It should be 46 | /// used by compilers after translating HLSL source code literally. It should 47 | /// *not* be used by general workloads for performance or size improvement. 48 | /// 49 | /// This sequence of passes is subject to constant review and will change 50 | /// from time to time. 51 | fn register_hlsl_legalization_passes(&mut self) -> &mut Self; 52 | } 53 | 54 | pub fn create(te: Option) -> impl Optimizer { 55 | let target_env = te.unwrap_or_default(); 56 | 57 | #[cfg(feature = "use-compiled-tools")] 58 | { 59 | compiled::CompiledOptimizer::with_env(target_env) 60 | } 61 | 62 | #[cfg(all(feature = "use-installed-tools", not(feature = "use-compiled-tools")))] 63 | { 64 | tool::ToolOptimizer::with_env(target_env) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /spirv-tools-sys/src/assembler.rs: -------------------------------------------------------------------------------- 1 | use crate::shared; 2 | 3 | #[repr(u32)] // SPV_FORCE_32_BIT_ENUM 4 | pub enum BinaryOptions { 5 | None = 0x1, 6 | PreserveNumberIds = 1 << 1, 7 | } 8 | 9 | #[repr(C)] 10 | pub struct Text { 11 | pub data: *const std::os::raw::c_char, 12 | pub length: usize, 13 | } 14 | 15 | pub enum DisassembleOptions { 16 | None = 0x1, 17 | /// Print to stdout 18 | Print = 0x2, 19 | /// Add color codes to output 20 | Color = 0x4, 21 | /// Indent assembly 22 | Indent = 0x8, 23 | ShowByteOffset = 0x10, 24 | /// Do not output the module header as leading comments in the assembly. 25 | NoHeader = 0x20, 26 | /// Use friendly names where possible. The heuristic may expand over 27 | /// time, but will use common names for scalar types, and debug names from 28 | /// OpName instructions. 29 | FriendlyNames = 0x40, 30 | /// Add some comments to the generated assembly 31 | Comment = 0x80, 32 | } 33 | 34 | extern "C" { 35 | /// Encodes the given SPIR-V assembly text to its binary representation. The 36 | /// length parameter specifies the number of bytes for text. Encoded binary will 37 | /// be stored into *binary. Any error will be written into *diagnostic if 38 | /// diagnostic is non-null, otherwise the context's message consumer will be 39 | /// used. The generated binary is independent of the context and may outlive it. 40 | /// The SPIR-V binary version is set to the highest version of SPIR-V supported 41 | /// by the context's target environment. 42 | /// 43 | /// The options parameter is a bit field of 44 | /// spv_text_to_binary_options_t. 45 | #[link_name = "spvTextToBinaryWithOptions"] 46 | pub fn assemble( 47 | tool: *const shared::ToolContext, 48 | text: *const std::os::raw::c_char, 49 | size: usize, 50 | options: u32, 51 | binary: *mut *mut shared::Binary, 52 | diagnostic: *mut *mut crate::diagnostics::Diagnostic, 53 | ) -> shared::SpirvResult; 54 | 55 | /// Decodes the given SPIR-V binary representation to its assembly text. The 56 | /// word_count parameter specifies the number of words for binary. The options 57 | /// parameter is a bit field of spv_binary_to_text_options_t. Decoded text will 58 | /// be stored into *text. Any error will be written into *diagnostic if 59 | /// diagnostic is non-null, otherwise the context's message consumer will be 60 | /// used. 61 | #[link_name = "spvBinaryToText"] 62 | pub fn disassemble( 63 | tool: *const shared::ToolContext, 64 | binary: *const u32, 65 | size: usize, 66 | options: u32, 67 | out_text: *mut *mut Text, 68 | diagnostic: *mut *mut crate::diagnostics::Diagnostic, 69 | ) -> shared::SpirvResult; 70 | 71 | /// Frees an allocated text stream. This is a no-op if the text parameter 72 | /// is a null pointer. 73 | #[link_name = "spvTextDestroy"] 74 | pub fn text_destroy(text: *mut Text); 75 | } 76 | -------------------------------------------------------------------------------- /src/val/tool.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | #[derive(Default)] 4 | pub struct ToolValidator { 5 | target_env: crate::TargetEnv, 6 | } 7 | 8 | use super::Validator; 9 | 10 | impl Validator for ToolValidator { 11 | fn with_env(target_env: crate::TargetEnv) -> Self { 12 | Self { target_env } 13 | } 14 | 15 | fn validate( 16 | &self, 17 | binary: impl AsRef<[u32]>, 18 | options: Option, 19 | ) -> Result<(), crate::error::Error> { 20 | let mut cmd = Command::new("spirv-val"); 21 | 22 | cmd.arg("--target-env").arg(self.target_env.to_string()); 23 | 24 | if let Some(opts) = options { 25 | // We reuse add options when we run the validator before optimizing, 26 | // however the optimizer does not recognize limits, so we split them 27 | // out into a separate function 28 | add_limits(&mut cmd, &opts.max_limits); 29 | add_options(&mut cmd, opts); 30 | } 31 | 32 | let input = crate::binary::from_binary(binary.as_ref()); 33 | 34 | crate::cmd::exec(cmd, Some(input), crate::cmd::Output::Ignore)?; 35 | Ok(()) 36 | } 37 | } 38 | 39 | pub(crate) fn add_options(cmd: &mut Command, opts: super::ValidatorOptions) { 40 | if opts.relax_logical_pointer { 41 | cmd.arg("--relax-logical-pointer"); 42 | } 43 | 44 | if let Some(true) = opts.relax_block_layout { 45 | cmd.arg("--relax-block-layout"); 46 | } 47 | 48 | if opts.uniform_buffer_standard_layout { 49 | cmd.arg("--uniform-buffer-standard-layout"); 50 | } 51 | 52 | if opts.scalar_block_layout { 53 | cmd.arg("--scalar-block-layout"); 54 | } 55 | 56 | if opts.skip_block_layout { 57 | cmd.arg("--skip-block-layout"); 58 | } 59 | 60 | if opts.relax_struct_store { 61 | cmd.arg("--relax-struct-store"); 62 | } 63 | 64 | if opts.before_legalization { 65 | cmd.arg("--before-hlsl-legalization"); 66 | } 67 | } 68 | 69 | fn add_limits(cmd: &mut Command, limits: &[(spirv_tools_sys::val::ValidatorLimits, u32)]) { 70 | use spirv_tools_sys::val::ValidatorLimits; 71 | 72 | for (limit, val) in limits { 73 | cmd.arg(format!( 74 | "--max-{}={}", 75 | match limit { 76 | ValidatorLimits::StructMembers => "struct-members", 77 | ValidatorLimits::StructDepth => "struct-depth", 78 | ValidatorLimits::LocalVariables => "local-variables", 79 | ValidatorLimits::GlobalVariables => "global-variables", 80 | ValidatorLimits::SwitchBranches => "switch-branches", 81 | ValidatorLimits::FunctionArgs => "function-args", 82 | ValidatorLimits::ControlFlowNestingDepth => "control-flow-nesting-depth", 83 | ValidatorLimits::AccessChainIndexes => "access-chain-indexes", 84 | ValidatorLimits::IdBound => "id-bound", 85 | }, 86 | val 87 | )); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | 2 | [target.'cfg(all())'] 3 | rustflags = [ 4 | # BEGIN - Embark standard lints v6 for Rust 1.55+ 5 | # do not change or add/remove here, but one can add exceptions after this section 6 | # for more info see: 7 | "-Dunsafe_code", 8 | "-Wclippy::all", 9 | "-Wclippy::await_holding_lock", 10 | "-Wclippy::char_lit_as_u8", 11 | "-Wclippy::checked_conversions", 12 | "-Wclippy::dbg_macro", 13 | "-Wclippy::debug_assert_with_mut_call", 14 | "-Wclippy::doc_markdown", 15 | "-Wclippy::empty_enum", 16 | "-Wclippy::enum_glob_use", 17 | "-Wclippy::exit", 18 | "-Wclippy::expl_impl_clone_on_copy", 19 | "-Wclippy::explicit_deref_methods", 20 | "-Wclippy::explicit_into_iter_loop", 21 | "-Wclippy::fallible_impl_from", 22 | "-Wclippy::filter_map_next", 23 | "-Wclippy::flat_map_option", 24 | "-Wclippy::float_cmp_const", 25 | "-Wclippy::fn_params_excessive_bools", 26 | "-Wclippy::from_iter_instead_of_collect", 27 | "-Wclippy::if_let_mutex", 28 | "-Wclippy::implicit_clone", 29 | "-Wclippy::imprecise_flops", 30 | "-Wclippy::inefficient_to_string", 31 | "-Wclippy::invalid_upcast_comparisons", 32 | "-Wclippy::large_digit_groups", 33 | "-Wclippy::large_stack_arrays", 34 | "-Wclippy::large_types_passed_by_value", 35 | "-Wclippy::let_unit_value", 36 | "-Wclippy::linkedlist", 37 | "-Wclippy::lossy_float_literal", 38 | "-Wclippy::macro_use_imports", 39 | "-Wclippy::manual_ok_or", 40 | "-Wclippy::map_err_ignore", 41 | "-Wclippy::map_flatten", 42 | "-Wclippy::map_unwrap_or", 43 | "-Wclippy::match_on_vec_items", 44 | "-Wclippy::match_same_arms", 45 | "-Wclippy::match_wild_err_arm", 46 | "-Wclippy::match_wildcard_for_single_variants", 47 | "-Wclippy::mem_forget", 48 | "-Wclippy::mismatched_target_os", 49 | "-Wclippy::missing_enforced_import_renames", 50 | "-Wclippy::mut_mut", 51 | "-Wclippy::mutex_integer", 52 | "-Wclippy::needless_borrow", 53 | "-Wclippy::needless_continue", 54 | "-Wclippy::needless_for_each", 55 | "-Wclippy::option_option", 56 | "-Wclippy::path_buf_push_overwrite", 57 | "-Wclippy::ptr_as_ptr", 58 | "-Wclippy::rc_mutex", 59 | "-Wclippy::ref_option_ref", 60 | "-Wclippy::rest_pat_in_fully_bound_structs", 61 | "-Wclippy::same_functions_in_if_condition", 62 | "-Wclippy::semicolon_if_nothing_returned", 63 | "-Wclippy::single_match_else", 64 | "-Wclippy::string_add_assign", 65 | "-Wclippy::string_add", 66 | "-Wclippy::string_lit_as_bytes", 67 | "-Wclippy::string_to_string", 68 | "-Wclippy::todo", 69 | "-Wclippy::trait_duplication_in_bounds", 70 | "-Wclippy::unimplemented", 71 | "-Wclippy::unnested_or_patterns", 72 | "-Wclippy::unused_self", 73 | "-Wclippy::useless_transmute", 74 | "-Wclippy::verbose_file_reads", 75 | "-Wclippy::zero_sized_map_values", 76 | "-Wfuture_incompatible", 77 | "-Wnonstandard_style", 78 | "-Wrust_2018_idioms", 79 | # END - Embark standard lints v6 for Rust 1.55+ 80 | ] -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at opensource@embark-studios.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Embark Contributor Guidelines 2 | 3 | Welcome! This project is created by the team at [Embark Studios](https://embark.games). We're glad you're interested in contributing! We welcome contributions from people of all backgrounds who are interested in making great software with us. 4 | 5 | At Embark, we aspire to empower everyone to create interactive experiences. To do this, we're exploring and pushing the boundaries of new technologies, and sharing our learnings with the open source community. 6 | 7 | If you have ideas for collaboration, email us at opensource@embark-studios.com. 8 | 9 | We're also hiring full-time engineers to work with us in Stockholm! Check out our current job postings [here](https://embark.games/careers). 10 | 11 | ## Issues 12 | 13 | ### Feature Requests 14 | 15 | If you have ideas or how to improve our projects, you can suggest features by opening a GitHub issue. Make sure to include details about the feature or change, and describe any uses cases it would enable. 16 | 17 | Feature requests will be tagged as `enhancement` and their status will be updated in the comments of the issue. 18 | 19 | ### Bugs 20 | 21 | When reporting a bug or unexpected behaviour in a project, make sure your issue describes steps to reproduce the behaviour, including the platform you were using, what steps you took, and any error messages. 22 | 23 | Reproducible bugs will be tagged as `bug` and their status will be updated in the comments of the issue. 24 | 25 | ### Wontfix 26 | 27 | Issues will be closed and tagged as `wontfix` if we decide that we do not wish to implement it, usually due to being misaligned with the project vision or out of scope. We will comment on the issue with more detailed reasoning. 28 | 29 | ## Contribution Workflow 30 | 31 | ### Open Issues 32 | 33 | If you're ready to contribute, start by looking at our open issues tagged as [`help wanted`](../../issues?q=is%3Aopen+is%3Aissue+label%3A"help+wanted") or [`good first issue`](../../issues?q=is%3Aopen+is%3Aissue+label%3A"good+first+issue"). 34 | 35 | You can comment on the issue to let others know you're interested in working on it or to ask questions. 36 | 37 | ### Making Changes 38 | 39 | 1. Fork the repository. 40 | 41 | 2. Create a new feature branch. 42 | 43 | 3. Make your changes. Ensure that there are no build errors by running the project with your changes locally. 44 | 45 | 4. Open a pull request with a name and description of what you did. You can read more about working with pull requests on GitHub [here](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork). 46 | 47 | 5. A maintainer will review your pull request and may ask you to make changes. 48 | 49 | ## Code Guidelines 50 | 51 | ### Rust 52 | 53 | You can read about our standards and recommendations for working with Rust [here](https://github.com/EmbarkStudios/rust-ecosystem/blob/main/guidelines.md). 54 | 55 | ### Python 56 | 57 | We recommend following [PEP8 conventions](https://www.python.org/dev/peps/pep-0008/) when working with Python modules. 58 | 59 | ### JavaScript 60 | 61 | We follow the [AirBnB JavaScript style guide](https://github.com/airbnb/javascript). You can find the ESLint configuration in relevant repositories. 62 | 63 | ## Licensing 64 | 65 | Unless otherwise specified, all Embark open source projects are licensed under a dual MIT OR Apache-2.0 license, allowing licensees to chose either at their option. You can read more in each project's respective README. 66 | 67 | ## Code of Conduct 68 | 69 | Please note that our projects are released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md) to ensure that they are welcoming places for everyone to contribute. By participating in any Embark open source project, you agree to abide by these terms. 70 | -------------------------------------------------------------------------------- /tools/install/main.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs, io::Write as _, process::Command}; 2 | 3 | struct Group(bool); 4 | 5 | impl Group { 6 | fn new(group: &str) -> Self { 7 | let is_gh = env::var_os("CI").is_some(); 8 | if is_gh { 9 | println!("::group::{group}"); 10 | } else { 11 | println!("{group}"); 12 | } 13 | Self(is_gh) 14 | } 15 | } 16 | 17 | impl Drop for Group { 18 | fn drop(&mut self) { 19 | if self.0 { 20 | println!("::endgroup::"); 21 | } 22 | } 23 | } 24 | 25 | fn main() { 26 | let (triple, release, td) = { 27 | let mut args = env::args().skip(1); 28 | let triple = args.next().expect("expected target triple"); 29 | let release = args.next().expect("expected release tag name"); 30 | let td = args.next().expect("expected output directory"); 31 | 32 | (triple, release, td) 33 | }; 34 | 35 | let compressed = { 36 | let _s = Group::new(&format!("downloading {triple} tarball")); 37 | let mut cmd = Command::new("curl"); 38 | cmd.args(["-f", "-L"]) 39 | .arg(format!("https://github.com/EmbarkStudios/spirv-tools-rs/releases/download/{release}/{triple}.tar.zst")) 40 | .stdout(std::process::Stdio::piped()); 41 | 42 | let output = cmd 43 | .spawn() 44 | .expect("curl is not installed") 45 | .wait_with_output() 46 | .expect("failed to wait for curl"); 47 | 48 | if !output.status.success() { 49 | panic!("failed to download tarball via curl"); 50 | } 51 | 52 | output.stdout 53 | }; 54 | 55 | let decoded = { 56 | let _s = Group::new(&format!("decompressing {triple} tarball")); 57 | // All archives are <8MiB decompressed 58 | let uncompressed = Vec::with_capacity(8 * 1024 * 1024); 59 | let mut decoder = 60 | zstd::stream::write::Decoder::new(uncompressed).expect("failed to create decoder"); 61 | decoder 62 | .write_all(&compressed) 63 | .expect("failed to decompress"); 64 | decoder.flush().expect("failed to flush decompress stream"); 65 | 66 | decoder.into_inner() 67 | }; 68 | 69 | { 70 | let _s = Group::new(&format!("untarring {triple} tarball")); 71 | { 72 | let mut tar = tar::Archive::new(std::io::Cursor::new(&decoded)); 73 | 74 | if tar 75 | .entries() 76 | .expect("failed to retrieve entries") 77 | .filter(|ent| ent.is_ok()) 78 | .count() 79 | == 0 80 | { 81 | panic!("no valid entries found in tarball"); 82 | } 83 | } 84 | 85 | let mut tar = tar::Archive::new(std::io::Cursor::new(decoded)); 86 | tar.unpack(&td).expect("failed to untar files"); 87 | } 88 | 89 | if let Some(gh_path) = env::var_os("GITHUB_PATH") { 90 | let _s = Group::new(&format!("adding '{td}' to $GITHUB_PATH ({gh_path:?})")); 91 | 92 | // emulate >> for both empty and non-empty files 93 | let has_contents = fs::metadata(&gh_path).map_or(false, |md| md.len() > 0); 94 | 95 | let mut file = fs::OpenOptions::new() 96 | .append(true) 97 | .open(gh_path) 98 | .expect("failed to open $GITHUB_PATH"); 99 | 100 | let td = if has_contents { 101 | format!("\n{td}\n") 102 | } else { 103 | td 104 | }; 105 | 106 | file.write_all(td.as_bytes()) 107 | .expect("failed to write to $GITHUB_PATH"); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/val/compiled.rs: -------------------------------------------------------------------------------- 1 | use spirv_tools_sys::{shared, val}; 2 | 3 | pub struct Options { 4 | pub(crate) inner: *mut val::ValidatorOptions, 5 | } 6 | 7 | impl From for Options { 8 | fn from(vo: super::ValidatorOptions) -> Self { 9 | unsafe { 10 | let inner = val::validator_options_create(); 11 | 12 | // This is AFAICT the only one that _can_ default to true based on our target 13 | // so we treat it differently 14 | if let Some(relax) = vo.relax_block_layout { 15 | val::validator_options_set_relax_block_layout(inner, relax); 16 | } 17 | 18 | if vo.relax_struct_store { 19 | val::validator_options_set_relax_store_struct(inner, true); 20 | } 21 | 22 | if vo.relax_logical_pointer { 23 | val::validator_options_set_relax_logical_pointer(inner, true); 24 | } 25 | 26 | if vo.before_legalization { 27 | val::validator_options_set_before_legalization(inner, true); 28 | } 29 | 30 | if vo.uniform_buffer_standard_layout { 31 | val::validator_options_set_uniform_buffer_standard_layout(inner, true); 32 | } 33 | 34 | if vo.scalar_block_layout { 35 | val::validator_options_set_scalar_block_layout(inner, true); 36 | } 37 | 38 | if vo.skip_block_layout { 39 | val::validator_options_set_skip_block_layout(inner, true); 40 | } 41 | 42 | for (limit, val) in vo.max_limits { 43 | val::validator_options_set_limit(inner, limit, val); 44 | } 45 | 46 | Self { inner } 47 | } 48 | } 49 | } 50 | 51 | impl Drop for Options { 52 | fn drop(&mut self) { 53 | unsafe { val::validator_options_destroy(self.inner) } 54 | } 55 | } 56 | 57 | pub struct CompiledValidator { 58 | inner: *mut shared::ToolContext, 59 | } 60 | 61 | use super::Validator; 62 | 63 | impl Validator for CompiledValidator { 64 | fn with_env(target_env: crate::TargetEnv) -> Self { 65 | Self { 66 | inner: unsafe { shared::context_create(target_env) }, 67 | } 68 | } 69 | 70 | fn validate( 71 | &self, 72 | binary: impl AsRef<[u32]>, 73 | options: Option, 74 | ) -> Result<(), crate::error::Error> { 75 | unsafe { 76 | let mut diagnostic = std::ptr::null_mut(); 77 | 78 | let options = options.map(Options::from); 79 | 80 | let binary = binary.as_ref(); 81 | 82 | let input = shared::Binary { 83 | code: binary.as_ptr(), 84 | size: binary.len(), 85 | }; 86 | 87 | let res = match options { 88 | Some(opts) => { 89 | val::validate_with_options(self.inner, opts.inner, &input, &mut diagnostic) 90 | } 91 | None => val::validate(self.inner, &input, &mut diagnostic), 92 | }; 93 | 94 | let diagnostic = crate::error::Diagnostic::from_diag(diagnostic).ok(); 95 | 96 | match res { 97 | shared::SpirvResult::Success => Ok(()), 98 | other => Err(crate::error::Error { 99 | inner: other, 100 | diagnostic, 101 | }), 102 | } 103 | } 104 | } 105 | } 106 | 107 | impl Default for CompiledValidator { 108 | fn default() -> Self { 109 | Self::with_env(crate::TargetEnv::default()) 110 | } 111 | } 112 | 113 | impl Drop for CompiledValidator { 114 | fn drop(&mut self) { 115 | unsafe { shared::context_destroy(self.inner) } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tools/package/main.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs, path, process::Command}; 2 | 3 | struct Group; 4 | 5 | impl Group { 6 | fn new(group: &str) -> Self { 7 | println!("::group::{group}"); 8 | Self 9 | } 10 | } 11 | 12 | impl Drop for Group { 13 | fn drop(&mut self) { 14 | println!("::endgroup::"); 15 | } 16 | } 17 | 18 | fn main() { 19 | let (triple, bazel_cache) = { 20 | let mut args = env::args().skip(1); 21 | let triple = args.next().expect("expected target triple"); 22 | 23 | let bc = if env::var_os("CI").is_some() { 24 | Some(args.next().expect("expected bazel cache directory")) 25 | } else { 26 | None 27 | }; 28 | 29 | (triple, bc) 30 | }; 31 | 32 | let cwd = "spirv-tools-sys/spirv-tools"; 33 | 34 | // Sigh 35 | { 36 | let _s = Group::new("synchronizing additional dependencies"); 37 | let mut cmd = Command::new("python"); 38 | cmd.arg("utils/git-sync-deps"); 39 | cmd.current_dir(cwd); 40 | 41 | if !cmd.status().expect("python not installed").success() { 42 | panic!("failed to run utils/git-sync-deps"); 43 | } 44 | } 45 | 46 | const BINARIES: &[&str] = &["spirv-as", "spirv-opt", "spirv-val"]; 47 | 48 | // Build the select binaries we/rust-gpu need 49 | { 50 | let _s = Group::new("building binaries with Bazel"); 51 | let mut cmd = Command::new("bazel"); 52 | // We use a specific root so that CI can take advantage of the cache, 53 | // this doesn't change the location of the outputs eg bazel-bin of the 54 | // workspace 55 | if let Some(bc) = bazel_cache { 56 | cmd.arg(format!("--output_user_root={bc}")); 57 | } 58 | 59 | cmd.args(["build", "--compilation_mode", "opt", "--strip", "always"]); 60 | 61 | cmd.args(BINARIES.iter().map(|b| format!(":{b}"))); 62 | cmd.current_dir(cwd); 63 | 64 | println!("{cmd:#?}"); 65 | 66 | if !cmd.status().expect("bazel not installed").success() { 67 | panic!("failed to run bazel build"); 68 | } 69 | } 70 | 71 | { 72 | let _s = Group::new("creating tarball"); 73 | 74 | let tar_path = format!("tools/{triple}.tar.zst"); 75 | 76 | // Finally, package a zstd compressed tarball 77 | let tar_file = fs::File::create(&tar_path).expect("failed to create tarball"); 78 | let zstd_stream = 79 | zstd::stream::write::Encoder::new(tar_file, 3).expect("failed to create zstd encoder"); 80 | 81 | let mut tar = tar::Builder::new(zstd_stream); 82 | 83 | // This is the default, but this just makes sure we aren't adding symlinks 84 | // but rather the files themselves 85 | tar.follow_symlinks(true); 86 | 87 | let ext = if cfg!(windows) { "exe" } else { "" }; 88 | let out = path::Path::new("spirv-tools-sys/spirv-tools/bazel-bin"); 89 | 90 | for exe in BINARIES { 91 | let src = { 92 | let mut pb = out.join(exe); 93 | pb.set_extension(ext); 94 | pb 95 | }; 96 | 97 | let name = if ext.is_empty() { 98 | exe.to_string() 99 | } else { 100 | format!("{exe}.{ext}") 101 | }; 102 | 103 | if let Err(err) = tar.append_path_with_name(&src, name) { 104 | panic!("failed to append {src:?} to tarball: {err}"); 105 | } 106 | 107 | println!("appended '{exe}'"); 108 | } 109 | 110 | let zstd_stream = tar.into_inner().expect("failed to finish writing tarball"); 111 | let tar_file = zstd_stream.finish().expect("failed to compress tarball"); 112 | tar_file 113 | .sync_all() 114 | .expect("failed to flush tarball to disk"); 115 | 116 | println!("'{tar_path}' written to disk"); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/assembler.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use-compiled-tools")] 2 | pub mod compiled; 3 | 4 | #[cfg(feature = "use-installed-tools")] 5 | pub mod tool; 6 | 7 | #[derive(Copy, Clone, Default)] 8 | pub struct AssemblerOptions { 9 | /// Numeric IDs in the binary will have the same values as in the source. 10 | /// Non-numeric IDs are allocated by filling in the gaps, starting with 1 11 | /// and going up. 12 | pub preserve_numeric_ids: bool, 13 | } 14 | 15 | #[allow(clippy::from_over_into)] 16 | impl Into for AssemblerOptions { 17 | fn into(self) -> u32 { 18 | // This is weird, the "none" is 1, so I'm not sure if that means having 19 | // it disables all other options or...? 20 | let mut res = 0; //assembler::BinaryOptions::None as u32; 21 | 22 | if self.preserve_numeric_ids { 23 | res |= spirv_tools_sys::assembler::BinaryOptions::PreserveNumberIds as u32; 24 | } 25 | 26 | res 27 | } 28 | } 29 | 30 | #[derive(Copy, Clone)] 31 | pub struct DisassembleOptions { 32 | /// Print to stdout. 33 | pub print: bool, 34 | /// Add color codes to output 35 | pub color: bool, 36 | /// Indent assembly 37 | pub indent: bool, 38 | pub show_byte_offset: bool, 39 | /// Do not output the module header as leading comments in the assembly. 40 | pub no_header: bool, 41 | /// Use friendly names where possible. The heuristic may expand over 42 | /// time, but will use common names for scalar types, and debug names from 43 | /// OpName instructions. 44 | pub use_friendly_names: bool, 45 | /// Add some comments to the generated assembly 46 | pub comment: bool, 47 | } 48 | 49 | impl Default for DisassembleOptions { 50 | fn default() -> Self { 51 | Self { 52 | print: false, 53 | color: false, 54 | indent: true, 55 | show_byte_offset: false, 56 | no_header: false, 57 | use_friendly_names: true, 58 | comment: true, 59 | } 60 | } 61 | } 62 | 63 | #[allow(clippy::from_over_into)] 64 | impl Into for DisassembleOptions { 65 | fn into(self) -> u32 { 66 | let mut res = 0; 67 | 68 | if self.print { 69 | res |= spirv_tools_sys::assembler::DisassembleOptions::Print as u32; 70 | } 71 | 72 | if self.color { 73 | res |= spirv_tools_sys::assembler::DisassembleOptions::Color as u32; 74 | } 75 | 76 | if self.indent { 77 | res |= spirv_tools_sys::assembler::DisassembleOptions::Indent as u32; 78 | } 79 | 80 | if self.show_byte_offset { 81 | res |= spirv_tools_sys::assembler::DisassembleOptions::ShowByteOffset as u32; 82 | } 83 | 84 | if self.no_header { 85 | res |= spirv_tools_sys::assembler::DisassembleOptions::NoHeader as u32; 86 | } 87 | 88 | if self.use_friendly_names { 89 | res |= spirv_tools_sys::assembler::DisassembleOptions::FriendlyNames as u32; 90 | } 91 | 92 | if self.comment { 93 | res |= spirv_tools_sys::assembler::DisassembleOptions::Comment as u32; 94 | } 95 | 96 | res 97 | } 98 | } 99 | 100 | pub trait Assembler: Default { 101 | fn with_env(target_env: crate::TargetEnv) -> Self; 102 | fn assemble( 103 | &self, 104 | text: &str, 105 | options: AssemblerOptions, 106 | ) -> Result; 107 | fn disassemble( 108 | &self, 109 | binary: impl AsRef<[u32]>, 110 | options: DisassembleOptions, 111 | ) -> Result, crate::error::Error>; 112 | } 113 | 114 | pub fn create(te: Option) -> impl Assembler { 115 | let target_env = te.unwrap_or_default(); 116 | 117 | #[cfg(feature = "use-compiled-tools")] 118 | { 119 | compiled::CompiledAssembler::with_env(target_env) 120 | } 121 | 122 | #[cfg(all(feature = "use-installed-tools", not(feature = "use-compiled-tools")))] 123 | { 124 | tool::ToolAssembler::with_env(target_env) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/assembler/compiled.rs: -------------------------------------------------------------------------------- 1 | use spirv_tools_sys::{assembler, shared}; 2 | 3 | pub struct CompiledAssembler { 4 | inner: *mut shared::ToolContext, 5 | } 6 | 7 | use super::Assembler; 8 | 9 | impl Assembler for CompiledAssembler { 10 | fn with_env(target_env: crate::TargetEnv) -> Self { 11 | Self { 12 | inner: unsafe { shared::context_create(target_env) }, 13 | } 14 | } 15 | 16 | fn assemble( 17 | &self, 18 | text: &str, 19 | options: super::AssemblerOptions, 20 | ) -> Result { 21 | unsafe { 22 | let mut binary = std::ptr::null_mut(); 23 | let mut diagnostic = std::ptr::null_mut(); 24 | 25 | let res = assembler::assemble( 26 | self.inner, 27 | text.as_ptr().cast(), 28 | text.len(), 29 | options.into(), 30 | &mut binary, 31 | &mut diagnostic, 32 | ); 33 | 34 | // Always wrap diagnostic, it's fine if it's null 35 | let diagnostic = crate::error::Diagnostic::from_diag(diagnostic).ok(); 36 | 37 | match res { 38 | shared::SpirvResult::Success => { 39 | if binary.is_null() { 40 | return Err(crate::error::Error { 41 | inner: shared::SpirvResult::InternalError, 42 | diagnostic: Some("spirv assemble indicated success but did not return a valid binary".to_owned().into()), 43 | }); 44 | } 45 | 46 | let bin = crate::binary::external::ExternalBinary::new(binary); 47 | Ok(crate::binary::Binary::External(bin)) 48 | } 49 | other => Err(crate::error::Error { 50 | inner: other, 51 | diagnostic, 52 | }), 53 | } 54 | } 55 | } 56 | 57 | fn disassemble( 58 | &self, 59 | binary: impl AsRef<[u32]>, 60 | options: super::DisassembleOptions, 61 | ) -> Result, crate::error::Error> { 62 | unsafe { 63 | let mut text = std::ptr::null_mut(); 64 | let mut diagnostic = std::ptr::null_mut(); 65 | 66 | let binary = binary.as_ref(); 67 | 68 | let res = assembler::disassemble( 69 | self.inner, 70 | binary.as_ptr().cast(), 71 | binary.len(), 72 | options.into(), 73 | &mut text, 74 | &mut diagnostic, 75 | ); 76 | 77 | // Always wrap diagnostic, it's fine if it's null 78 | let diagnostic = crate::error::Diagnostic::from_diag(diagnostic).ok(); 79 | 80 | match res { 81 | shared::SpirvResult::Success => { 82 | if text.is_null() { 83 | return Ok(None); 84 | } 85 | 86 | // Sanity check the text first 87 | let disassemble_res = std::str::from_utf8(std::slice::from_raw_parts( 88 | (*text).data.cast::(), 89 | (*text).length, 90 | )) 91 | .map(|disasm| Some(disasm.to_owned())) 92 | .map_err(|e| crate::error::Error { 93 | inner: shared::SpirvResult::InvalidText, 94 | diagnostic: Some( 95 | format!("spirv disassemble returned non-utf8 text: {}", e).into(), 96 | ), 97 | }); 98 | 99 | assembler::text_destroy(text); 100 | 101 | disassemble_res 102 | } 103 | other => Err(crate::error::Error { 104 | inner: other, 105 | diagnostic, 106 | }), 107 | } 108 | } 109 | } 110 | } 111 | 112 | impl Default for CompiledAssembler { 113 | fn default() -> Self { 114 | Self::with_env(crate::TargetEnv::default()) 115 | } 116 | } 117 | 118 | impl Drop for CompiledAssembler { 119 | fn drop(&mut self) { 120 | unsafe { 121 | shared::context_destroy(self.inner); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/extension_enum.inc: -------------------------------------------------------------------------------- 1 | kSPV_AMDX_shader_enqueue, 2 | kSPV_AMD_gcn_shader, 3 | kSPV_AMD_gpu_shader_half_float, 4 | kSPV_AMD_gpu_shader_half_float_fetch, 5 | kSPV_AMD_gpu_shader_int16, 6 | kSPV_AMD_shader_ballot, 7 | kSPV_AMD_shader_early_and_late_fragment_tests, 8 | kSPV_AMD_shader_explicit_vertex_parameter, 9 | kSPV_AMD_shader_fragment_mask, 10 | kSPV_AMD_shader_image_load_store_lod, 11 | kSPV_AMD_shader_trinary_minmax, 12 | kSPV_AMD_texture_gather_bias_lod, 13 | kSPV_ARM_core_builtins, 14 | kSPV_EXT_demote_to_helper_invocation, 15 | kSPV_EXT_descriptor_indexing, 16 | kSPV_EXT_fragment_fully_covered, 17 | kSPV_EXT_fragment_invocation_density, 18 | kSPV_EXT_fragment_shader_interlock, 19 | kSPV_EXT_mesh_shader, 20 | kSPV_EXT_opacity_micromap, 21 | kSPV_EXT_physical_storage_buffer, 22 | kSPV_EXT_shader_atomic_float16_add, 23 | kSPV_EXT_shader_atomic_float_add, 24 | kSPV_EXT_shader_atomic_float_min_max, 25 | kSPV_EXT_shader_image_int64, 26 | kSPV_EXT_shader_stencil_export, 27 | kSPV_EXT_shader_tile_image, 28 | kSPV_EXT_shader_viewport_index_layer, 29 | kSPV_GOOGLE_decorate_string, 30 | kSPV_GOOGLE_hlsl_functionality1, 31 | kSPV_GOOGLE_user_type, 32 | kSPV_INTEL_arbitrary_precision_fixed_point, 33 | kSPV_INTEL_arbitrary_precision_floating_point, 34 | kSPV_INTEL_arbitrary_precision_integers, 35 | kSPV_INTEL_bfloat16_conversion, 36 | kSPV_INTEL_blocking_pipes, 37 | kSPV_INTEL_cache_controls, 38 | kSPV_INTEL_debug_module, 39 | kSPV_INTEL_device_side_avc_motion_estimation, 40 | kSPV_INTEL_float_controls2, 41 | kSPV_INTEL_fp_fast_math_mode, 42 | kSPV_INTEL_fp_max_error, 43 | kSPV_INTEL_fpga_argument_interfaces, 44 | kSPV_INTEL_fpga_buffer_location, 45 | kSPV_INTEL_fpga_cluster_attributes, 46 | kSPV_INTEL_fpga_dsp_control, 47 | kSPV_INTEL_fpga_invocation_pipelining_attributes, 48 | kSPV_INTEL_fpga_latency_control, 49 | kSPV_INTEL_fpga_loop_controls, 50 | kSPV_INTEL_fpga_memory_accesses, 51 | kSPV_INTEL_fpga_memory_attributes, 52 | kSPV_INTEL_fpga_reg, 53 | kSPV_INTEL_function_pointers, 54 | kSPV_INTEL_global_variable_fpga_decorations, 55 | kSPV_INTEL_global_variable_host_access, 56 | kSPV_INTEL_inline_assembly, 57 | kSPV_INTEL_io_pipes, 58 | kSPV_INTEL_kernel_attributes, 59 | kSPV_INTEL_long_composites, 60 | kSPV_INTEL_loop_fuse, 61 | kSPV_INTEL_media_block_io, 62 | kSPV_INTEL_memory_access_aliasing, 63 | kSPV_INTEL_optnone, 64 | kSPV_INTEL_runtime_aligned, 65 | kSPV_INTEL_shader_integer_functions2, 66 | kSPV_INTEL_split_barrier, 67 | kSPV_INTEL_subgroups, 68 | kSPV_INTEL_unstructured_loop_controls, 69 | kSPV_INTEL_usm_storage_classes, 70 | kSPV_INTEL_variable_length_array, 71 | kSPV_INTEL_vector_compute, 72 | kSPV_KHR_16bit_storage, 73 | kSPV_KHR_8bit_storage, 74 | kSPV_KHR_bit_instructions, 75 | kSPV_KHR_cooperative_matrix, 76 | kSPV_KHR_device_group, 77 | kSPV_KHR_expect_assume, 78 | kSPV_KHR_float_controls, 79 | kSPV_KHR_fragment_shader_barycentric, 80 | kSPV_KHR_fragment_shading_rate, 81 | kSPV_KHR_integer_dot_product, 82 | kSPV_KHR_linkonce_odr, 83 | kSPV_KHR_multiview, 84 | kSPV_KHR_no_integer_wrap_decoration, 85 | kSPV_KHR_non_semantic_info, 86 | kSPV_KHR_physical_storage_buffer, 87 | kSPV_KHR_post_depth_coverage, 88 | kSPV_KHR_ray_cull_mask, 89 | kSPV_KHR_ray_query, 90 | kSPV_KHR_ray_tracing, 91 | kSPV_KHR_ray_tracing_position_fetch, 92 | kSPV_KHR_shader_atomic_counter_ops, 93 | kSPV_KHR_shader_ballot, 94 | kSPV_KHR_shader_clock, 95 | kSPV_KHR_shader_draw_parameters, 96 | kSPV_KHR_storage_buffer_storage_class, 97 | kSPV_KHR_subgroup_rotate, 98 | kSPV_KHR_subgroup_uniform_control_flow, 99 | kSPV_KHR_subgroup_vote, 100 | kSPV_KHR_terminate_invocation, 101 | kSPV_KHR_uniform_group_instructions, 102 | kSPV_KHR_variable_pointers, 103 | kSPV_KHR_vulkan_memory_model, 104 | kSPV_KHR_workgroup_memory_explicit_layout, 105 | kSPV_NVX_multiview_per_view_attributes, 106 | kSPV_NV_bindless_texture, 107 | kSPV_NV_compute_shader_derivatives, 108 | kSPV_NV_cooperative_matrix, 109 | kSPV_NV_displacement_micromap, 110 | kSPV_NV_fragment_shader_barycentric, 111 | kSPV_NV_geometry_shader_passthrough, 112 | kSPV_NV_mesh_shader, 113 | kSPV_NV_ray_tracing, 114 | kSPV_NV_ray_tracing_motion_blur, 115 | kSPV_NV_sample_mask_override_coverage, 116 | kSPV_NV_shader_image_footprint, 117 | kSPV_NV_shader_invocation_reorder, 118 | kSPV_NV_shader_sm_builtins, 119 | kSPV_NV_shader_subgroup_partitioned, 120 | kSPV_NV_shading_rate, 121 | kSPV_NV_stereo_view_rendering, 122 | kSPV_NV_viewport_array2, 123 | kSPV_QCOM_image_processing, 124 | kSPV_VALIDATOR_ignore_type_decl_unique -------------------------------------------------------------------------------- /src/val.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use-compiled-tools")] 2 | pub mod compiled; 3 | #[cfg(feature = "use-installed-tools")] 4 | pub mod tool; 5 | 6 | pub use spirv_tools_sys::val::ValidatorLimits; 7 | 8 | #[derive(Default, Clone)] 9 | pub struct ValidatorOptions { 10 | /// Record whether or not the validator should relax the rules on types for 11 | /// stores to structs. When relaxed, it will allow a type mismatch as long as 12 | /// the types are structs with the same layout. Two structs have the same layout 13 | /// if 14 | /// 15 | /// 1) the members of the structs are either the same type or are structs with 16 | /// same layout, and 17 | /// 18 | /// 2) the decorations that affect the memory layout are identical for both 19 | /// types. Other decorations are not relevant. 20 | pub relax_struct_store: bool, 21 | /// Records whether or not the validator should relax the rules on pointer usage 22 | /// in logical addressing mode. 23 | /// 24 | /// When relaxed, it will allow the following usage cases of pointers: 25 | /// 1) OpVariable allocating an object whose type is a pointer type 26 | /// 2) OpReturnValue returning a pointer value 27 | pub relax_logical_pointer: bool, 28 | /// Records whether or not the validator should relax the rules because it is 29 | /// expected that the optimizations will make the code legal. 30 | /// 31 | /// When relaxed, it will allow the following: 32 | /// 1) It will allow relaxed logical pointers. Setting this option will also 33 | /// set that option. 34 | /// 2) Pointers that are pass as parameters to function calls do not have to 35 | /// match the storage class of the formal parameter. 36 | /// 3) Pointers that are actaul parameters on function calls do not have to point 37 | /// to the same type pointed as the formal parameter. The types just need to 38 | /// logically match. 39 | pub before_legalization: bool, 40 | /// Records whether the validator should use "relaxed" block layout rules. 41 | /// Relaxed layout rules are described by Vulkan extension 42 | /// VK_KHR_relaxed_block_layout, and they affect uniform blocks, storage blocks, 43 | /// and push constants. 44 | /// 45 | /// This is enabled by default when targeting Vulkan 1.1 or later. 46 | /// Relaxed layout is more permissive than the default rules in Vulkan 1.0. 47 | pub relax_block_layout: Option, 48 | /// Records whether the validator should use standard block layout rules for 49 | /// uniform blocks. 50 | pub uniform_buffer_standard_layout: bool, 51 | /// Records whether the validator should use "scalar" block layout rules. 52 | /// Scalar layout rules are more permissive than relaxed block layout. 53 | /// 54 | /// See Vulkan extnesion VK_EXT_scalar_block_layout. The scalar alignment is 55 | /// defined as follows: 56 | /// - scalar alignment of a scalar is the scalar size 57 | /// - scalar alignment of a vector is the scalar alignment of its component 58 | /// - scalar alignment of a matrix is the scalar alignment of its component 59 | /// - scalar alignment of an array is the scalar alignment of its element 60 | /// - scalar alignment of a struct is the max scalar alignment among its 61 | /// members 62 | /// 63 | /// For a struct in Uniform, StorageClass, or PushConstant: 64 | /// - a member Offset must be a multiple of the member's scalar alignment 65 | /// - ArrayStride or MatrixStride must be a multiple of the array or matrix 66 | /// scalar alignment 67 | pub scalar_block_layout: bool, 68 | /// Records whether or not the validator should skip validating standard 69 | /// uniform/storage block layout. 70 | pub skip_block_layout: bool, 71 | /// Applies a maximum to one or more Universal limits 72 | pub max_limits: Vec<(ValidatorLimits, u32)>, 73 | } 74 | 75 | pub trait Validator: Default { 76 | fn with_env(target_env: crate::TargetEnv) -> Self; 77 | fn validate( 78 | &self, 79 | binary: impl AsRef<[u32]>, 80 | options: Option, 81 | ) -> Result<(), crate::error::Error>; 82 | } 83 | 84 | pub fn create(te: Option) -> impl Validator { 85 | let target_env = te.unwrap_or_default(); 86 | 87 | #[cfg(feature = "use-compiled-tools")] 88 | { 89 | compiled::CompiledValidator::with_env(target_env) 90 | } 91 | 92 | #[cfg(all(feature = "use-installed-tools", not(feature = "use-compiled-tools")))] 93 | { 94 | tool::ToolValidator::with_env(target_env) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/binary.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "use-compiled-tools")] 2 | pub mod external { 3 | use spirv_tools_sys::shared; 4 | 5 | pub struct ExternalBinary { 6 | inner: *mut shared::Binary, 7 | } 8 | 9 | impl ExternalBinary { 10 | #[inline] 11 | pub(crate) fn new(bin: *mut shared::Binary) -> Self { 12 | Self { inner: bin } 13 | } 14 | } 15 | 16 | impl AsRef<[u32]> for ExternalBinary { 17 | #[inline] 18 | fn as_ref(&self) -> &[u32] { 19 | unsafe { std::slice::from_raw_parts((*self.inner).code, (*self.inner).size) } 20 | } 21 | } 22 | 23 | impl AsRef<[u8]> for ExternalBinary { 24 | #[inline] 25 | fn as_ref(&self) -> &[u8] { 26 | unsafe { 27 | std::slice::from_raw_parts( 28 | (*self.inner).code.cast(), 29 | (*self.inner).size * std::mem::size_of::(), 30 | ) 31 | } 32 | } 33 | } 34 | 35 | impl Drop for ExternalBinary { 36 | #[inline] 37 | fn drop(&mut self) { 38 | unsafe { 39 | shared::binary_destroy(self.inner); 40 | } 41 | } 42 | } 43 | } 44 | 45 | pub enum Binary { 46 | #[cfg(feature = "use-compiled-tools")] 47 | External(self::external::ExternalBinary), 48 | OwnedU32(Vec), 49 | OwnedU8(Vec), 50 | } 51 | 52 | impl Binary { 53 | /// Gets a byte array for binary 54 | #[inline] 55 | pub fn as_bytes(&self) -> &[u8] { 56 | self.as_ref() 57 | } 58 | 59 | /// Gets the words for the binary 60 | #[inline] 61 | pub fn as_words(&self) -> &[u32] { 62 | self.as_ref() 63 | } 64 | } 65 | 66 | impl std::convert::TryFrom> for Binary { 67 | type Error = crate::Error; 68 | 69 | #[inline] 70 | fn try_from(v: Vec) -> Result { 71 | if v.len() % std::mem::size_of::() != 0 { 72 | Err(crate::Error { 73 | inner: spirv_tools_sys::shared::SpirvResult::InvalidBinary, 74 | diagnostic: None, 75 | }) 76 | } else { 77 | Ok(Binary::OwnedU8(v)) 78 | } 79 | } 80 | } 81 | 82 | impl AsRef<[u32]> for Binary { 83 | #[inline] 84 | fn as_ref(&self) -> &[u32] { 85 | match self { 86 | #[cfg(feature = "use-compiled-tools")] 87 | Self::External(bin) => bin.as_ref(), 88 | Self::OwnedU32(v) => v, 89 | Self::OwnedU8(v) => { 90 | // If you hit a panic here it's because try_from wasn't used ;) 91 | to_binary(v).unwrap() 92 | } 93 | } 94 | } 95 | } 96 | 97 | impl AsRef<[u8]> for Binary { 98 | #[inline] 99 | fn as_ref(&self) -> &[u8] { 100 | match self { 101 | #[cfg(feature = "use-compiled-tools")] 102 | Self::External(bin) => bin.as_ref(), 103 | Self::OwnedU32(v) => from_binary(v), 104 | Self::OwnedU8(v) => v, 105 | } 106 | } 107 | } 108 | 109 | use std::fmt; 110 | 111 | impl fmt::Debug for Binary { 112 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 113 | let mut ds = match self { 114 | #[cfg(feature = "use-compiled-tools")] 115 | Self::External(_) => f.debug_struct("External"), 116 | Self::OwnedU32(_) => f.debug_struct("OwnedU32"), 117 | Self::OwnedU8(_) => f.debug_struct("OwnedU8"), 118 | }; 119 | 120 | ds.field("word_count", &self.as_words().len()).finish() 121 | } 122 | } 123 | 124 | /// Transmutes a SPIRV binary, which are stored as 32 bit words, into a more 125 | /// digestible byte array 126 | #[inline] 127 | pub fn from_binary(bin: &[u32]) -> &[u8] { 128 | unsafe { std::slice::from_raw_parts(bin.as_ptr().cast(), std::mem::size_of_val(bin)) } 129 | } 130 | 131 | /// Transmutes a regular byte array into a SPIRV binary of 32 bit words. This 132 | /// will fail if the input is not `% sizeof(u32)` 133 | #[inline] 134 | pub fn to_binary(bytes: &[u8]) -> Result<&[u32], crate::Error> { 135 | if bytes.len() % std::mem::size_of::() != 0 { 136 | return Err(crate::Error { 137 | inner: spirv_tools_sys::shared::SpirvResult::InvalidBinary, 138 | diagnostic: None, 139 | }); 140 | } 141 | 142 | #[allow(clippy::size_of_in_element_count)] 143 | Ok(unsafe { 144 | std::slice::from_raw_parts( 145 | bytes.as_ptr().cast(), 146 | bytes.len() / std::mem::size_of::(), 147 | ) 148 | }) 149 | } 150 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/debuginfo.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t debuginfo_entries[] = { 4 | {"DebugInfoNone", 0, 0, nullptr, {SPV_OPERAND_TYPE_NONE}}, 5 | {"DebugCompilationUnit", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 6 | {"DebugTypeBasic", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING, SPV_OPERAND_TYPE_NONE}}, 7 | {"DebugTypePointer", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_NONE}}, 8 | {"DebugTypeQualifier", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER, SPV_OPERAND_TYPE_NONE}}, 9 | {"DebugTypeArray", 5, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 10 | {"DebugTypeVector", 6, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 11 | {"DebugTypedef", 7, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 12 | {"DebugTypeFunction", 8, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 13 | {"DebugTypeEnum", 9, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 14 | {"DebugTypeComposite", 10, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 15 | {"DebugTypeMember", 11, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 16 | {"DebugTypeInheritance", 12, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_NONE}}, 17 | {"DebugTypePtrToMember", 13, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 18 | {"DebugTypeTemplate", 14, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 19 | {"DebugTypeTemplateParameter", 15, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 20 | {"DebugTypeTemplateTemplateParameter", 16, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 21 | {"DebugTypeTemplateParameterPack", 17, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 22 | {"DebugGlobalVariable", 18, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 23 | {"DebugFunctionDeclaration", 19, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_NONE}}, 24 | {"DebugFunction", 20, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 25 | {"DebugLexicalBlock", 21, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 26 | {"DebugLexicalBlockDiscriminator", 22, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 27 | {"DebugScope", 23, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 28 | {"DebugNoScope", 24, 0, nullptr, {SPV_OPERAND_TYPE_NONE}}, 29 | {"DebugInlinedAt", 25, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 30 | {"DebugLocalVariable", 26, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 31 | {"DebugInlinedVariable", 27, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 32 | {"DebugDeclare", 28, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 33 | {"DebugValue", 29, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 34 | {"DebugOperation", 30, 0, nullptr, {SPV_OPERAND_TYPE_DEBUG_OPERATION, SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 35 | {"DebugExpression", 31, 0, nullptr, {SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 36 | {"DebugMacroDef", 32, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 37 | {"DebugMacroUndef", 33, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}} 38 | }; -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Changelog 4 | All notable changes to this project will be documented in this file. 5 | 6 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 7 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 8 | 9 | 10 | ## [Unreleased] - ReleaseDate 11 | ## [0.10.0] - 2024-02-05 12 | ### Changed 13 | - [PR#38](https://github.com/EmbarkStudios/spirv-tools-rs/pull/38) updated to `vulkan-sdk-1.3.275`. 14 | - [PR#37](https://github.com/EmbarkStudios/spirv-tools-rs/pull/37) added `impl Clone` for `Diagnostic`. 15 | 16 | ### Fixed 17 | - [PR#36](https://github.com/EmbarkStudios/spirv-tools-rs/pull/36) fixed the parsing if diagnostic messages from spirv-tools binaries. 18 | 19 | ## [0.9.0] - 2022-10-17 20 | ### Changed 21 | - [PR#30](https://github.com/EmbarkStudios/spirv-tools-rs/pull/30) updated to [v2022.2](https://github.com/KhronosGroup/SPIRV-Tools/blob/cb96abbf7affd986016f17dd09f9f971138a922b/CHANGES#L6-L43) of spirv-tools. 22 | - [PR#33](https://github.com/EmbarkStudios/spirv-tools-rs/pull/33) updated to [v2022.3](https://github.com/KhronosGroup/SPIRV-Tools/blob/b53d3a6be38b032dedbc72639dfc6249b5e92697/CHANGES#L30-L54) and [v2022.4](https://github.com/KhronosGroup/SPIRV-Tools/blob/b53d3a6be38b032dedbc72639dfc6249b5e92697/CHANGES#L6-L28) 23 | 24 | ### Fixed 25 | - [PR#32](https://github.com/EmbarkStudios/spirv-tools-rs/pull/32) fixed compilation on MacOS. 26 | 27 | ## [0.8.0] - 2022-02-04 28 | ### Changed 29 | - [PR#29](https://github.com/EmbarkStudios/spirv-tools-rs/pull/29) updated to v2022.1 of spirv-tools. 30 | 31 | ## [0.7.1] - 2021-09-20 32 | ### Fixed 33 | - [PR#28](https://github.com/EmbarkStudios/spirv-tools-rs/pull/28) fixed [#27](https://github.com/EmbarkStudios/spirv-tools-rs/issues/27) by changing the `TryFrom` into a crate private method. 34 | 35 | ## [0.7.0] - 2021-09-17 36 | ### Changed 37 | - [PR#26](https://github.com/EmbarkStudios/spirv-tools-rs/pull/26) updated to SPIRV-Tools [v2021.3](https://github.com/KhronosGroup/SPIRV-Tools/releases/tag/v2021.3). 38 | 39 | ## [0.6.1] - 2021-05-05 40 | ### Fixed 41 | - [PR#21](https://github.com/EmbarkStudios/spirv-tools-rs/pull/21) updated spirv-tools C++ code to address a GCC11 warning which caused compile failures due to warnings as errors. 42 | - [PR#23](https://github.com/EmbarkStudios/spirv-tools-rs/pull/23) fixed [#22](https://github.com/EmbarkStudios/spirv-tools-rs/issues/22) by correcting a mismatch between optimization passes between the compiled and tool mode of the optimizer. 43 | 44 | ## [0.6.0] - 2021-03-25 45 | ### Changed 46 | - [PR#20](https://github.com/EmbarkStudios/spirv-tools-rs/pull/20) changed the format of `Error::Display` to not include the spirv result code as it differs between compiled and tool mode since the spirv binaries don't provide the actual error that occurred. 47 | 48 | ## [0.5.0] - 2021-03-16 49 | ### Changed 50 | - [PR#18](https://github.com/EmbarkStudios/spirv-tools-rs/pull/18) updated the upstream spirv-tools to `v2021.0-dev`, `SPIRV-Tools v2021.0-dev v2020.5-198-g5af051b0`. 51 | - [PR#18](https://github.com/EmbarkStudios/spirv-tools-rs/pull/18) changed `Assembler::disassemble` to return a `Option` instead of just `String` for an `Ok`, in the cases where the call succeeded, but the actual string was null/empty. 52 | 53 | ## [0.4.0] - 2021-02-01 54 | ### Changed 55 | - [PR#15](https://github.com/EmbarkStudios/spirv-tools-rs/pull/15) updated the upstream spirv-tools to `v2020.7-dev`, `SPIRV-Tools v2020.7-dev v2020.6-50-g0a3a1712`. 56 | 57 | ### Fixed 58 | - [PR#14](https://github.com/EmbarkStudios/spirv-tools-rs/pull/14) fixed an issue where an error was reported if the disassembled text was directly printed. Thanks [@Danielmelody](https://github.com/Danielmelody)! 59 | 60 | ## [0.3.1] - 2020-12-17 61 | ### Fixed 62 | - [PR#13](https://github.com/EmbarkStudios/spirv-tools-rs/pull/13) Fix the spirv-as and spirv-val tool arguments that were broken by [PR#12](https://github.com/EmbarkStudios/spirv-tools-rs/pull/12). 63 | 64 | ## [0.3.0] - 2020-12-17 65 | ### Added 66 | - [PR#12](https://github.com/EmbarkStudios/spirv-tools-rs/pull/12) Added the ability to disassemble binary to text. 67 | 68 | ### Fixed 69 | - [PR#12](https://github.com/EmbarkStudios/spirv-tools-rs/pull/12) Fixed several bugs in the optimizer, as well as the command line for the validator. 70 | 71 | ## [0.2.0] - 2020-12-14 72 | ### Fixed 73 | - [PR#9](https://github.com/EmbarkStudios/spirv-tools-rs/pull/9) Fixed bug in the compiled optimizer that resulted in no output. Thanks [@khyperia](https://github.com/khyperia)! 74 | 75 | ## [0.1.1] - 2020-11-18 76 | ### Added 77 | - [PR#4](https://github.com/EmbarkStudios/spirv-tools-rs/pull/4) added more clear compile errors if neither of the `use-*-tools` features are enabled for either `spirv-tools` or `spirv-tools-sys`. 78 | 79 | ### Changed 80 | - [PR#4](https://github.com/EmbarkStudios/spirv-tools-rs/pull/4) made `use-compiled-tools` the default feature for `spirv-tools-sys`. This would only affect direct consumers of `spirv-tools-sys`. 81 | 82 | ## [0.1.0] - 2020-11-13 83 | ### Added 84 | - Added initial implementation, which includes the assembler, validator, and most of the optimizer, which meets the current needs of rust-gpu. 85 | 86 | 87 | [Unreleased]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.10.0...HEAD 88 | [0.10.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.9.0...0.10.0 89 | [0.9.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.8.0...0.9.0 90 | [0.8.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.7.1...0.8.0 91 | [0.7.1]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.7.0...0.7.1 92 | [0.7.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.6.1...0.7.0 93 | [0.6.1]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.6.0...0.6.1 94 | [0.6.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.5.0...0.6.0 95 | [0.5.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.4.0...0.5.0 96 | [0.4.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.3.1...0.4.0 97 | [0.3.1]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.3.0...0.3.1 98 | [0.3.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.2.0...0.3.0 99 | [0.2.0]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.1.1...0.2.0 100 | [0.1.1]: https://github.com/EmbarkStudios/spirv-tools-rs/compare/0.1.0...0.1.1 101 | [0.1.0]: https://github.com/EmbarkStudios/spirv-tools-rs/releases/tag/0.1.0 102 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/nonsemantic.clspvreflection.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t nonsemantic_clspvreflection_entries[] = { 4 | {"Kernel", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 5 | {"ArgumentInfo", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 6 | {"ArgumentStorageBuffer", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 7 | {"ArgumentUniform", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 8 | {"ArgumentPodStorageBuffer", 5, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 9 | {"ArgumentPodUniform", 6, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 10 | {"ArgumentPodPushConstant", 7, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 11 | {"ArgumentSampledImage", 8, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 12 | {"ArgumentStorageImage", 9, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 13 | {"ArgumentSampler", 10, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 14 | {"ArgumentWorkgroup", 11, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 15 | {"SpecConstantWorkgroupSize", 12, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 16 | {"SpecConstantGlobalOffset", 13, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 17 | {"SpecConstantWorkDim", 14, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 18 | {"PushConstantGlobalOffset", 15, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 19 | {"PushConstantEnqueuedLocalSize", 16, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 20 | {"PushConstantGlobalSize", 17, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 21 | {"PushConstantRegionOffset", 18, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 22 | {"PushConstantNumWorkgroups", 19, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 23 | {"PushConstantRegionGroupOffset", 20, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 24 | {"ConstantDataStorageBuffer", 21, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 25 | {"ConstantDataUniform", 22, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 26 | {"LiteralSampler", 23, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 27 | {"PropertyRequiredWorkgroupSize", 24, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 28 | {"SpecConstantSubgroupMaxSize", 25, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 29 | {"ArgumentPointerPushConstant", 26, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 30 | {"ArgumentPointerUniform", 27, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 31 | {"ProgramScopeVariablesStorageBuffer", 28, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 32 | {"ProgramScopeVariablePointerRelocation", 29, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 33 | {"ImageArgumentInfoChannelOrderPushConstant", 30, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 34 | {"ImageArgumentInfoChannelDataTypePushConstant", 31, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 35 | {"ImageArgumentInfoChannelOrderUniform", 32, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 36 | {"ImageArgumentInfoChannelDataTypeUniform", 33, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 37 | {"ArgumentStorageTexelBuffer", 34, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 38 | {"ArgumentUniformTexelBuffer", 35, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 39 | {"ConstantDataPointerPushConstant", 36, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 40 | {"ProgramScopeVariablePointerPushConstant", 37, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 41 | {"PrintfInfo", 38, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 42 | {"PrintfBufferStorageBuffer", 39, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 43 | {"PrintfBufferPointerPushConstant", 40, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 44 | {"NormalizedSamplerMaskPushConstant", 41, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}} 45 | }; -------------------------------------------------------------------------------- /spirv-tools-sys/generated/nonsemantic.shader.debuginfo.100.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t nonsemantic_shader_debuginfo_100_entries[] = { 4 | {"DebugInfoNone", 0, 0, nullptr, {SPV_OPERAND_TYPE_NONE}}, 5 | {"DebugCompilationUnit", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 6 | {"DebugTypeBasic", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 7 | {"DebugTypePointer", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 8 | {"DebugTypeQualifier", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 9 | {"DebugTypeArray", 5, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 10 | {"DebugTypeVector", 6, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 11 | {"DebugTypedef", 7, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 12 | {"DebugTypeFunction", 8, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 13 | {"DebugTypeEnum", 9, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 14 | {"DebugTypeComposite", 10, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 15 | {"DebugTypeMember", 11, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 16 | {"DebugTypeInheritance", 12, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 17 | {"DebugTypePtrToMember", 13, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 18 | {"DebugTypeTemplate", 14, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 19 | {"DebugTypeTemplateParameter", 15, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 20 | {"DebugTypeTemplateTemplateParameter", 16, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 21 | {"DebugTypeTemplateParameterPack", 17, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 22 | {"DebugGlobalVariable", 18, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 23 | {"DebugFunctionDeclaration", 19, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 24 | {"DebugFunction", 20, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 25 | {"DebugLexicalBlock", 21, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 26 | {"DebugLexicalBlockDiscriminator", 22, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 27 | {"DebugScope", 23, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 28 | {"DebugNoScope", 24, 0, nullptr, {SPV_OPERAND_TYPE_NONE}}, 29 | {"DebugInlinedAt", 25, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 30 | {"DebugLocalVariable", 26, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 31 | {"DebugInlinedVariable", 27, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 32 | {"DebugDeclare", 28, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 33 | {"DebugValue", 29, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 34 | {"DebugOperation", 30, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 35 | {"DebugExpression", 31, 0, nullptr, {SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 36 | {"DebugMacroDef", 32, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 37 | {"DebugMacroUndef", 33, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 38 | {"DebugImportedEntity", 34, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 39 | {"DebugSource", 35, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 40 | {"DebugFunctionDefinition", 101, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 41 | {"DebugSourceContinued", 102, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 42 | {"DebugLine", 103, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 43 | {"DebugNoLine", 104, 0, nullptr, {SPV_OPERAND_TYPE_NONE}}, 44 | {"DebugBuildIdentifier", 105, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 45 | {"DebugStoragePath", 106, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 46 | {"DebugEntryPoint", 107, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 47 | {"DebugTypeMatrix", 108, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}} 48 | }; -------------------------------------------------------------------------------- /spirv-tools-sys/generate.rs: -------------------------------------------------------------------------------- 1 | // The spirv tools use generated code, for now we just replicate the minimum 2 | // generation we need here by calling the *shudders* python script(s) we need 3 | // to in a simple script and commit them to source control, as they only need 4 | // to be regenerated when spirv-headers is updated 5 | 6 | use std::{fs, process::Command}; 7 | 8 | fn python>(args: impl IntoIterator) -> Result<(), i32> { 9 | Command::new("python") 10 | .args(args.into_iter()) 11 | .status() 12 | .map_err(|_| -1) 13 | .and_then(|es| { 14 | if es.success() { 15 | Ok(()) 16 | } else { 17 | Err(es.code().unwrap_or(-1)) 18 | } 19 | }) 20 | } 21 | 22 | fn main() { 23 | fs::create_dir_all("generated").expect("unable to create 'generated'"); 24 | 25 | python(&[ 26 | "spirv-tools/utils/update_build_version.py", 27 | "spirv-tools/CHANGES", 28 | "generated/build-version.inc", 29 | ]) 30 | .expect("failed to generate build version from spirv-headers"); 31 | 32 | enum_string_mapping("unified1"); 33 | core_table("unified1"); 34 | glsl_table("unified1"); 35 | opencl_table("unified1"); 36 | 37 | vendor_table("spv-amd-shader-explicit-vertex-parameter", None); 38 | vendor_table("spv-amd-shader-trinary-minmax", None); 39 | vendor_table("spv-amd-gcn-shader", None); 40 | vendor_table("spv-amd-shader-ballot", None); 41 | vendor_table("debuginfo", None); 42 | vendor_table("nonsemantic.clspvreflection", None); 43 | vendor_table("opencl.debuginfo.100", Some("CLDEBUG100_")); 44 | 45 | // This will eventually be moved to spirv-headers 46 | vendor_table("nonsemantic.shader.debuginfo.100", Some("SHDEBUG100_")); 47 | generate_header( 48 | "NonSemanticShaderDebugInfo100", 49 | "nonsemantic.shader.debuginfo.100", 50 | ); 51 | 52 | registry_table(); 53 | } 54 | 55 | const HEADERS: &str = "spirv-headers/include/spirv"; 56 | 57 | fn enum_string_mapping(version: &str) { 58 | python(&[ 59 | "spirv-tools/utils/generate_grammar_tables.py".to_owned(), 60 | format!("--spirv-core-grammar={HEADERS}/{version}/spirv.core.grammar.json"), 61 | format!("--extinst-debuginfo-grammar={HEADERS}/unified1/extinst.debuginfo.grammar.json"), 62 | format!("--extinst-cldebuginfo100-grammar={HEADERS}/unified1/extinst.opencl.debuginfo.100.grammar.json"), 63 | "--extension-enum-output=generated/extension_enum.inc".to_owned(), 64 | "--enum-string-mapping-output=generated/enum_string_mapping.inc".to_owned(), 65 | "--output-language=c++".into(), 66 | ]).expect("failed to generate enum includes from spirv-headers"); 67 | } 68 | 69 | fn vendor_table(which: &str, prefix: Option<&str>) { 70 | python(&[ 71 | "spirv-tools/utils/generate_grammar_tables.py".to_owned(), 72 | format!("--extinst-vendor-grammar={HEADERS}/unified1/extinst.{which}.grammar.json",), 73 | format!("--vendor-insts-output=generated/{which}.insts.inc"), 74 | format!( 75 | "--vendor-operand-kind-prefix={}", 76 | prefix.unwrap_or_default() 77 | ), 78 | ]) 79 | .expect("failed to generate vendor table"); 80 | } 81 | 82 | // fn vendor_table_local(which: &str, prefix: Option<&str>) { 83 | // python(&[ 84 | // "spirv-tools/utils/generate_grammar_tables.py".to_owned(), 85 | // format!( 86 | // "--extinst-vendor-grammar=spirv-tools/source/extinst.{}.grammar.json", 87 | // which 88 | // ), 89 | // format!("--vendor-insts-output=generated/{}.insts.inc", which), 90 | // format!( 91 | // "--vendor-operand-kind-prefix={}", 92 | // prefix.unwrap_or_default() 93 | // ), 94 | // ]) 95 | // .expect("failed to generate vendor table"); 96 | // } 97 | 98 | fn core_table(which: &str) { 99 | python(&[ 100 | "spirv-tools/utils/generate_grammar_tables.py".to_owned(), 101 | format!("--spirv-core-grammar={HEADERS}/unified1/spirv.core.grammar.json"), 102 | format!("--core-insts-output=generated/core.insts-{which}.inc"), 103 | format!("--extinst-debuginfo-grammar={HEADERS}/unified1/extinst.debuginfo.grammar.json"), 104 | format!("--extinst-cldebuginfo100-grammar={HEADERS}/unified1/extinst.opencl.debuginfo.100.grammar.json"), 105 | format!("--operand-kinds-output=generated/operand.kinds-{which}.inc"), 106 | "--output-language=c++".into(), 107 | ]).expect("failed to generate core table from spirv-headers"); 108 | } 109 | 110 | fn registry_table() { 111 | python(&[ 112 | "spirv-tools/utils/generate_registry_tables.py", 113 | "--xml=spirv-headers/include/spirv/spir-v.xml", 114 | "--generator=generated/generators.inc", 115 | ]) 116 | .expect("failed to generate core table from spirv-headers"); 117 | } 118 | 119 | fn glsl_table(version: &str) { 120 | python(&[ 121 | "spirv-tools/utils/generate_grammar_tables.py".to_owned(), 122 | format!("--spirv-core-grammar={HEADERS}/{version}/spirv.core.grammar.json"), 123 | format!("--extinst-debuginfo-grammar={HEADERS}/unified1/extinst.debuginfo.grammar.json"), 124 | format!("--extinst-cldebuginfo100-grammar={HEADERS}/unified1/extinst.opencl.debuginfo.100.grammar.json"), 125 | format!("--extinst-glsl-grammar={HEADERS}/{version}/extinst.glsl.std.450.grammar.json"), 126 | "--glsl-insts-output=generated/glsl.std.450.insts.inc".to_owned(), 127 | "--output-language=c++".into(), 128 | ]).expect("failed to generate glsl table from spirv-headers"); 129 | } 130 | 131 | fn opencl_table(version: &str) { 132 | python(&[ 133 | "spirv-tools/utils/generate_grammar_tables.py".to_owned(), 134 | format!("--spirv-core-grammar={HEADERS}/{version}/spirv.core.grammar.json"), 135 | format!("--extinst-debuginfo-grammar={HEADERS}/unified1/extinst.debuginfo.grammar.json"), 136 | format!("--extinst-cldebuginfo100-grammar={HEADERS}/unified1/extinst.opencl.debuginfo.100.grammar.json"), 137 | format!("--extinst-opencl-grammar={HEADERS}/{version}/extinst.opencl.std.100.grammar.json"), 138 | "--opencl-insts-output=generated/opencl.std.insts.inc".to_owned(), 139 | "--output-language=c++".into(), 140 | ]).expect("failed to generate glsl table from spirv-headers"); 141 | } 142 | 143 | fn generate_header(header_name: &str, grammar: &str) { 144 | python(&[ 145 | "spirv-tools/utils/generate_language_headers.py".to_owned(), 146 | format!("--extinst-grammar={HEADERS}/unified1/extinst.{grammar}.grammar.json",), 147 | format!("--extinst-output-path=generated/{}.h", header_name), 148 | ]) 149 | .expect("failed to generate C header") 150 | } 151 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/opencl.debuginfo.100.insts.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | static const spv_ext_inst_desc_t opencl_debuginfo_100_entries[] = { 4 | {"DebugInfoNone", 0, 0, nullptr, {SPV_OPERAND_TYPE_NONE}}, 5 | {"DebugCompilationUnit", 1, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_SOURCE_LANGUAGE, SPV_OPERAND_TYPE_NONE}}, 6 | {"DebugTypeBasic", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING, SPV_OPERAND_TYPE_NONE}}, 7 | {"DebugTypePointer", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_NONE}}, 8 | {"DebugTypeQualifier", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER, SPV_OPERAND_TYPE_NONE}}, 9 | {"DebugTypeArray", 5, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 10 | {"DebugTypeVector", 6, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 11 | {"DebugTypedef", 7, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 12 | {"DebugTypeFunction", 8, 0, nullptr, {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 13 | {"DebugTypeEnum", 9, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 14 | {"DebugTypeComposite", 10, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 15 | {"DebugTypeMember", 11, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 16 | {"DebugTypeInheritance", 12, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_NONE}}, 17 | {"DebugTypePtrToMember", 13, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 18 | {"DebugTypeTemplate", 14, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 19 | {"DebugTypeTemplateParameter", 15, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 20 | {"DebugTypeTemplateTemplateParameter", 16, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 21 | {"DebugTypeTemplateParameterPack", 17, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 22 | {"DebugGlobalVariable", 18, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 23 | {"DebugFunctionDeclaration", 19, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_NONE}}, 24 | {"DebugFunction", 20, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 25 | {"DebugLexicalBlock", 21, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 26 | {"DebugLexicalBlockDiscriminator", 22, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 27 | {"DebugScope", 23, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 28 | {"DebugNoScope", 24, 0, nullptr, {SPV_OPERAND_TYPE_NONE}}, 29 | {"DebugInlinedAt", 25, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 30 | {"DebugLocalVariable", 26, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 31 | {"DebugInlinedVariable", 27, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 32 | {"DebugDeclare", 28, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 33 | {"DebugValue", 29, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 34 | {"DebugOperation", 30, 0, nullptr, {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, 35 | {"DebugExpression", 31, 0, nullptr, {SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_NONE}}, 36 | {"DebugMacroDef", 32, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 37 | {"DebugMacroUndef", 33, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 38 | {"DebugImportedEntity", 34, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 39 | {"DebugSource", 35, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_NONE}}, 40 | {"DebugModuleINTEL", 36, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}} 41 | }; -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use spirv_tools_sys::{diagnostics, shared}; 2 | 3 | pub use diagnostics::MessageLevel; 4 | pub use shared::SpirvResult; 5 | 6 | #[derive(Debug, PartialEq)] 7 | pub struct Error { 8 | pub inner: shared::SpirvResult, 9 | pub diagnostic: Option, 10 | } 11 | 12 | use std::fmt; 13 | 14 | impl fmt::Display for Error { 15 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 16 | match &self.diagnostic { 17 | Some(diag) => { 18 | f.write_fmt(format_args!( 19 | "error:{}:{} - {}", 20 | diag.line, diag.column, diag.message 21 | ))?; 22 | 23 | if !diag.notes.is_empty() { 24 | f.write_fmt(format_args!("\n{}", diag.notes))?; 25 | } 26 | 27 | Ok(()) 28 | } 29 | None => f.write_str("an unknown error occurred"), 30 | } 31 | } 32 | } 33 | 34 | impl std::error::Error for Error { 35 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 36 | Some(&self.inner) 37 | } 38 | } 39 | 40 | #[derive(Debug, Clone, PartialEq, Eq)] 41 | pub struct Diagnostic { 42 | pub line: usize, 43 | pub column: usize, 44 | pub index: usize, 45 | pub message: String, 46 | pub notes: String, 47 | pub is_text: bool, 48 | } 49 | 50 | #[cfg(feature = "use-compiled-tools")] 51 | impl Diagnostic { 52 | pub(crate) unsafe fn from_diag( 53 | diag: *mut diagnostics::Diagnostic, 54 | ) -> Result { 55 | if diag.is_null() { 56 | return Err(shared::SpirvResult::Success); 57 | } 58 | 59 | let (message, notes) = Message::message_and_notes_from_cstr((*diag).error); 60 | 61 | let res = Self { 62 | line: (*diag).position.line, 63 | column: (*diag).position.column, 64 | index: (*diag).position.index, 65 | message, 66 | notes, 67 | is_text: (*diag).is_text_source, 68 | }; 69 | 70 | diagnostics::diagnostic_destroy(diag); 71 | Ok(res) 72 | } 73 | } 74 | 75 | impl From for Diagnostic { 76 | fn from(message: String) -> Self { 77 | Self { 78 | line: 0, 79 | column: 0, 80 | index: 0, 81 | is_text: false, 82 | message, 83 | notes: String::new(), 84 | } 85 | } 86 | } 87 | 88 | impl From for Diagnostic { 89 | fn from(msg: Message) -> Self { 90 | Self { 91 | line: msg.line, 92 | column: msg.column, 93 | index: msg.index, 94 | message: msg.message, 95 | notes: msg.notes, 96 | is_text: false, 97 | } 98 | } 99 | } 100 | 101 | #[derive(Debug)] 102 | pub struct Message { 103 | pub level: MessageLevel, 104 | pub source: Option, 105 | pub line: usize, 106 | pub column: usize, 107 | pub index: usize, 108 | pub message: String, 109 | /// Some messages can include additional information, typically instructions 110 | pub notes: String, 111 | } 112 | 113 | impl Message { 114 | #[cfg(feature = "use-installed-tools")] 115 | pub(crate) fn fatal(message: String) -> Self { 116 | Self { 117 | level: MessageLevel::Fatal, 118 | source: None, 119 | line: 0, 120 | column: 0, 121 | index: 0, 122 | message, 123 | notes: String::new(), 124 | } 125 | } 126 | 127 | #[cfg(feature = "use-compiled-tools")] 128 | unsafe fn message_and_notes_from_cstr(msg: *const std::os::raw::c_char) -> (String, String) { 129 | let full_message = std::ffi::CStr::from_ptr(msg).to_string_lossy(); 130 | 131 | if let Some(ind) = full_message.find('\n') { 132 | ( 133 | full_message[..ind].to_owned(), 134 | full_message[ind + 1..].to_owned(), 135 | ) 136 | } else { 137 | (full_message.into_owned(), String::new()) 138 | } 139 | } 140 | 141 | #[cfg(feature = "use-compiled-tools")] 142 | pub(crate) fn from_parts( 143 | level: MessageLevel, 144 | source: *const std::os::raw::c_char, 145 | source_pos: *const diagnostics::Position, 146 | msg: *const std::os::raw::c_char, 147 | ) -> Self { 148 | unsafe { 149 | let source = if source.is_null() { 150 | None 151 | } else { 152 | Some(std::ffi::CStr::from_ptr(source).to_string_lossy()) 153 | }; 154 | 155 | let (message, notes) = Self::message_and_notes_from_cstr(msg); 156 | 157 | let (line, column, index) = if source_pos.is_null() { 158 | (0, 0, 0) 159 | } else { 160 | ( 161 | (*source_pos).line, 162 | (*source_pos).column, 163 | (*source_pos).index, 164 | ) 165 | }; 166 | 167 | Self { 168 | level, 169 | source: source.and_then(|source| { 170 | if source.is_empty() { 171 | None 172 | } else { 173 | Some(source.into_owned()) 174 | } 175 | }), 176 | line, 177 | column, 178 | index, 179 | message, 180 | notes, 181 | } 182 | } 183 | } 184 | 185 | #[cfg(feature = "use-installed-tools")] 186 | pub(crate) fn parse(s: &str) -> Option { 187 | s.find(": ") 188 | .and_then(|i| { 189 | let level = match &s[..i] { 190 | "error" => MessageLevel::Error, 191 | "warning" => MessageLevel::Warning, 192 | "info" => MessageLevel::Info, 193 | _ => return None, 194 | }; 195 | 196 | Some((level, i)) 197 | }) 198 | .and_then(|(level, i)| { 199 | s[i + 7..] 200 | .find(": ") 201 | .and_then(|i2| { 202 | s[i + 7..i + 7 + i2] 203 | .parse::() 204 | .ok() 205 | .map(|index| (index, i2)) 206 | }) 207 | .map(|(index, i2)| (level, index, i + 7 + i2 + 2)) 208 | }) 209 | .map(|(level, index, last)| Self { 210 | level, 211 | index, 212 | message: s[last..].to_owned(), 213 | source: None, 214 | line: 0, 215 | column: 0, 216 | notes: String::new(), 217 | }) 218 | } 219 | } 220 | 221 | pub trait MessageCallback { 222 | fn on_message(&mut self, msg: Message); 223 | } 224 | 225 | impl MessageCallback for F 226 | where 227 | F: FnMut(Message), 228 | { 229 | fn on_message(&mut self, msg: Message) { 230 | self(msg); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/glsl.std.450.insts.inc: -------------------------------------------------------------------------------- 1 | static const spv::Capability pygen_variable_caps_Float64[] = {spv::Capability::Float64}; 2 | static const spv::Capability pygen_variable_caps_InterpolationFunction[] = {spv::Capability::InterpolationFunction}; 3 | 4 | static const spv_ext_inst_desc_t glsl_entries[] = { 5 | {"Round", 1, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 6 | {"RoundEven", 2, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 7 | {"Trunc", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 8 | {"FAbs", 4, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 9 | {"SAbs", 5, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 10 | {"FSign", 6, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 11 | {"SSign", 7, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 12 | {"Floor", 8, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 13 | {"Ceil", 9, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 14 | {"Fract", 10, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 15 | {"Radians", 11, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 16 | {"Degrees", 12, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 17 | {"Sin", 13, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 18 | {"Cos", 14, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 19 | {"Tan", 15, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 20 | {"Asin", 16, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 21 | {"Acos", 17, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 22 | {"Atan", 18, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 23 | {"Sinh", 19, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 24 | {"Cosh", 20, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 25 | {"Tanh", 21, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 26 | {"Asinh", 22, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 27 | {"Acosh", 23, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 28 | {"Atanh", 24, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 29 | {"Atan2", 25, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 30 | {"Pow", 26, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 31 | {"Exp", 27, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 32 | {"Log", 28, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 33 | {"Exp2", 29, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 34 | {"Log2", 30, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 35 | {"Sqrt", 31, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 36 | {"InverseSqrt", 32, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 37 | {"Determinant", 33, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 38 | {"MatrixInverse", 34, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 39 | {"Modf", 35, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 40 | {"ModfStruct", 36, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 41 | {"FMin", 37, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 42 | {"UMin", 38, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 43 | {"SMin", 39, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 44 | {"FMax", 40, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 45 | {"UMax", 41, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 46 | {"SMax", 42, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 47 | {"FClamp", 43, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 48 | {"UClamp", 44, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 49 | {"SClamp", 45, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 50 | {"FMix", 46, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 51 | {"IMix", 47, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 52 | {"Step", 48, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 53 | {"SmoothStep", 49, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 54 | {"Fma", 50, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 55 | {"Frexp", 51, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 56 | {"FrexpStruct", 52, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 57 | {"Ldexp", 53, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 58 | {"PackSnorm4x8", 54, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 59 | {"PackUnorm4x8", 55, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 60 | {"PackSnorm2x16", 56, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 61 | {"PackUnorm2x16", 57, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 62 | {"PackHalf2x16", 58, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 63 | {"PackDouble2x32", 59, 1, pygen_variable_caps_Float64, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 64 | {"UnpackSnorm2x16", 60, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 65 | {"UnpackUnorm2x16", 61, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 66 | {"UnpackHalf2x16", 62, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 67 | {"UnpackSnorm4x8", 63, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 68 | {"UnpackUnorm4x8", 64, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 69 | {"UnpackDouble2x32", 65, 1, pygen_variable_caps_Float64, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 70 | {"Length", 66, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 71 | {"Distance", 67, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 72 | {"Cross", 68, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 73 | {"Normalize", 69, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 74 | {"FaceForward", 70, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 75 | {"Reflect", 71, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 76 | {"Refract", 72, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 77 | {"FindILsb", 73, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 78 | {"FindSMsb", 74, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 79 | {"FindUMsb", 75, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 80 | {"InterpolateAtCentroid", 76, 1, pygen_variable_caps_InterpolationFunction, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 81 | {"InterpolateAtSample", 77, 1, pygen_variable_caps_InterpolationFunction, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 82 | {"InterpolateAtOffset", 78, 1, pygen_variable_caps_InterpolationFunction, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 83 | {"NMin", 79, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 84 | {"NMax", 80, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, 85 | {"NClamp", 81, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}} 86 | }; -------------------------------------------------------------------------------- /src/opt/tool.rs: -------------------------------------------------------------------------------- 1 | use crate::error; 2 | 3 | #[derive(Default)] 4 | pub struct ToolOptimizer { 5 | target_env: crate::TargetEnv, 6 | passes: Vec, 7 | use_perf_passes: bool, 8 | use_size_passes: bool, 9 | //use_vulkan_to_webgpu: bool, 10 | //use_webgpu_to_vulkan: bool, 11 | legalize_hlsl: bool, 12 | } 13 | 14 | use super::Optimizer; 15 | 16 | impl Optimizer for ToolOptimizer { 17 | fn with_env(target_env: crate::TargetEnv) -> Self { 18 | Self { 19 | target_env, 20 | ..Default::default() 21 | } 22 | } 23 | 24 | fn optimize( 25 | &self, 26 | input: impl AsRef<[u32]>, 27 | msg_callback: &mut MC, 28 | options: Option, 29 | ) -> Result { 30 | let mut cmd = std::process::Command::new("spirv-opt"); 31 | 32 | // Note here that we don't do cmd.arg("--target-env").arg(self.target_env.to_string()); 33 | // like with the other tools, because opt is "special" and will fail to parse 34 | // command line options correctly if we don't give join them with the = 35 | cmd.arg(format!("--target-env={}", self.target_env)); 36 | 37 | cmd.args( 38 | self.passes 39 | .iter() 40 | .filter_map(|p| pass_to_string(*p).map(|s| format!("--{}", s))), 41 | ); 42 | 43 | if self.use_perf_passes { 44 | cmd.arg("-O"); 45 | } 46 | 47 | if self.use_size_passes { 48 | cmd.arg("-Os"); 49 | } 50 | 51 | if self.legalize_hlsl { 52 | cmd.arg("--legalize-hlsl"); 53 | } 54 | 55 | if let Some(opts) = options { 56 | if let Some(max_id_bound) = opts.max_id_bound { 57 | cmd.arg(format!("--max-id-bound={}", max_id_bound)); 58 | } 59 | 60 | if opts.preserve_bindings { 61 | cmd.arg("--preserve-bindings"); 62 | } 63 | 64 | if opts.preserve_spec_constants { 65 | cmd.arg("--preserve-spec-constants"); 66 | } 67 | 68 | if let Some(vopts) = opts.validator_options { 69 | crate::val::tool::add_options(&mut cmd, vopts); 70 | } 71 | } 72 | 73 | let input = crate::binary::from_binary(input.as_ref()); 74 | 75 | let cmd_output = crate::cmd::exec(cmd, Some(input), crate::cmd::Output::Retrieve)?; 76 | 77 | for msg in cmd_output.messages { 78 | msg_callback.on_message(msg); 79 | } 80 | 81 | crate::binary::Binary::try_from(cmd_output.binary) 82 | } 83 | 84 | /// Register a single pass with the the optimizer. 85 | #[inline] 86 | fn register_pass(&mut self, pass: super::Passes) -> &mut Self { 87 | self.passes.push(pass); 88 | self 89 | } 90 | 91 | /// Registers passes that attempt to improve performance of generated code. 92 | /// This sequence of passes is subject to constant review and will change 93 | /// from time to time. 94 | #[inline] 95 | fn register_performance_passes(&mut self) -> &mut Self { 96 | self.use_perf_passes = true; 97 | self 98 | } 99 | 100 | /// Registers passes that attempt to improve the size of generated code. 101 | /// This sequence of passes is subject to constant review and will change 102 | /// from time to time. 103 | #[inline] 104 | fn register_size_passes(&mut self) -> &mut Self { 105 | self.use_size_passes = true; 106 | self 107 | } 108 | 109 | /// Registers passes that attempt to legalize the generated code. 110 | /// 111 | /// Note: this recipe is specially designed for legalizing SPIR-V. It should be 112 | /// used by compilers after translating HLSL source code literally. It should 113 | /// *not* be used by general workloads for performance or size improvement. 114 | /// 115 | /// This sequence of passes is subject to constant review and will change 116 | /// from time to time. 117 | #[inline] 118 | fn register_hlsl_legalization_passes(&mut self) -> &mut Self { 119 | self.legalize_hlsl = true; 120 | self 121 | } 122 | } 123 | 124 | fn pass_to_string(pass: super::Passes) -> Option<&'static str> { 125 | #[allow(clippy::enum_glob_use)] 126 | use super::Passes::*; 127 | 128 | Some(match pass { 129 | AggressiveDCE => "eliminate-dead-code-aggressive", 130 | AmdExtToKhr => "amd-ext-to-khr", 131 | BlockMerge => "merge-blocks", 132 | CFGCleanup => "cfg-cleanup", 133 | CodeSinking => "code-sink", 134 | CombineAccessChains => "combine-access-chains", 135 | CompactIds => "compact-ids", 136 | ConditionalConstantPropagation => "ccp", 137 | ConvertRelaxedToHalf => "convert-relaxed-to-half", 138 | CopyPropagateArrays => "copy-propagate-arrays", 139 | DeadBranchElim => "eliminate-dead-branches", 140 | DeadInsertElim => "eliminate-dead-inserts", 141 | DeadVariableElimination => "eliminate-dead-variables", 142 | DescriptorScalarReplacement => "descriptor-scalar-replacement", 143 | EliminateDeadConstant => "eliminate-dead-const", 144 | EliminateDeadFunctions => "eliminate-dead-functions", 145 | EliminateDeadMembers => "eliminate-dead-members", 146 | FixStorageClass => "fix-storage-class", 147 | FlattenDecoration => "flatten-decorations", 148 | FoldSpecConstantOpAndComposite => "fold-spec-const-op-composite", 149 | FreezeSpecConstantValue => "freeze-spec-const", 150 | GraphicsRobustAccess => "graphics-robust-access", 151 | IfConversion => "if-conversion", 152 | InlineExhaustive => "inline-entry-points-exhaustive", 153 | InlineOpaque => "inline-entry-points-opaque", 154 | InsertExtractElim => "eliminate-insert-extract", 155 | // This is only part of the --legalize-hlsl meta pass 156 | InterpolateFixup | Null => return None, 157 | LocalAccessChainConvert => "convert-local-access-chains", 158 | LocalMultiStoreElim => "eliminate-local-multi-store", 159 | LocalRedundancyElimination => "local-redundancy-elimination", 160 | LocalSingleBlockLoadStoreElim => "eliminate-local-single-block", 161 | LocalSingleStoreElim => "eliminate-local-single-store", 162 | LoopInvariantCodeMotion => "loop-invariant-code-motion", 163 | LoopPeeling => "loop-peeling", 164 | LoopUnswitch => "loop-unswitch", 165 | MergeReturn => "merge-return", 166 | PrivateToLocal => "private-to-local", 167 | PropagateLineInfo => "propagate-line-info", 168 | ReduceLoadSize => "reduce-load-size", 169 | RedundancyElimination => "redundancy-elimination", 170 | RedundantLineInfoElim => "eliminate-redundant-line-info", 171 | RemoveUnusedInterfaceVariables => "remove-unused-interface-variables", 172 | RelaxFloatOps => "relax-float-ops", 173 | RemoveDuplicates => "remove-duplicates", 174 | ReplaceInvalidOpcode => "replace-invalid-opcode", 175 | Simplification => "simplify-instructions", 176 | SSARewrite => "ssa-rewrite", 177 | StrengthReduction => "strength-reduction", 178 | StripDebugInfo => "strip-debug", 179 | StripNonSemanticInfo => "strip-nonsemantic", 180 | UnifyConstant => "unify-const", 181 | UpgradeMemoryModel => "upgrade-memory-model", 182 | VectorDCE => "vector-dce", 183 | Workaround1209 => "workaround-1209", 184 | WrapOpKill => "wrap-opkill", 185 | }) 186 | } 187 | -------------------------------------------------------------------------------- /spirv-tools-sys/src/val.rs: -------------------------------------------------------------------------------- 1 | use crate::shared; 2 | 3 | #[repr(C)] 4 | pub struct ValidatorOptions { 5 | _unused: [u8; 0], 6 | } 7 | 8 | #[derive(Copy, Clone, Debug)] 9 | #[repr(C)] 10 | pub enum ValidatorLimits { 11 | StructMembers, 12 | StructDepth, 13 | LocalVariables, 14 | GlobalVariables, 15 | SwitchBranches, 16 | FunctionArgs, 17 | ControlFlowNestingDepth, 18 | AccessChainIndexes, 19 | IdBound, 20 | } 21 | 22 | extern "C" { 23 | /// Validates a SPIR-V binary for correctness. Any errors will be written into 24 | /// *diagnostic if diagnostic is non-null, otherwise the context's message 25 | /// consumer will be used. 26 | /// 27 | /// Validate for SPIR-V spec rules for the SPIR-V version named in the 28 | /// binary's header (at word offset 1). Additionally, if the context target 29 | /// environment is a client API (such as Vulkan 1.1), then validate for that 30 | /// client API version, to the extent that it is verifiable from data in the 31 | /// binary itself. 32 | #[link_name = "spvValidate"] 33 | pub fn validate( 34 | tool: *const shared::ToolContext, 35 | binary: *const shared::Binary, 36 | diagnostic: *mut *mut crate::diagnostics::Diagnostic, 37 | ) -> crate::shared::SpirvResult; 38 | 39 | /// Validates a SPIR-V binary for correctness. Uses the provided Validator 40 | /// options. Any errors will be written into *diagnostic if diagnostic is 41 | /// non-null, otherwise the context's message consumer will be used. 42 | /// 43 | /// Validate for SPIR-V spec rules for the SPIR-V version named in the 44 | /// binary's header (at word offset 1). Additionally, if the context target 45 | /// environment is a client API (such as Vulkan 1.1), then validate for that 46 | /// client API version, to the extent that it is verifiable from data in the 47 | /// binary itself, or in the validator options. 48 | #[link_name = "spvValidateWithOptions"] 49 | pub fn validate_with_options( 50 | tool: *const shared::ToolContext, 51 | options: *const ValidatorOptions, 52 | binary: *const shared::Binary, 53 | diagnostic: *mut *mut crate::diagnostics::Diagnostic, 54 | ) -> crate::shared::SpirvResult; 55 | 56 | /// Creates a Validator options object with default options. Returns a valid 57 | /// options object. The object remains valid until it is passed into 58 | /// spvValidatorOptionsDestroy. 59 | #[link_name = "spvValidatorOptionsCreate"] 60 | pub fn validator_options_create() -> *mut ValidatorOptions; 61 | 62 | /// Destroys the given Validator options object. 63 | #[link_name = "spvValidatorOptionsDestroy"] 64 | pub fn validator_options_destroy(opts: *mut ValidatorOptions); 65 | 66 | /// Records the maximum Universal Limit that is considered valid in the given 67 | /// Validator options object. argument must be a valid options object. 68 | #[link_name = "spvValidatorOptionsSetUniversalLimit"] 69 | pub fn validator_options_set_limit( 70 | opts: *mut ValidatorOptions, 71 | limit_type: ValidatorLimits, 72 | limit: u32, 73 | ); 74 | 75 | /// Record whether or not the validator should relax the rules on types for 76 | /// stores to structs. When relaxed, it will allow a type mismatch as long as 77 | /// the types are structs with the same layout. Two structs have the same layout 78 | /// if 79 | /// 80 | /// 1) the members of the structs are either the same type or are structs with 81 | /// same layout, and 82 | /// 83 | /// 2) the decorations that affect the memory layout are identical for both 84 | /// types. Other decorations are not relevant. 85 | #[link_name = "spvValidatorOptionsSetRelaxStoreStruct"] 86 | pub fn validator_options_set_relax_store_struct(opts: *mut ValidatorOptions, toggle: bool); 87 | 88 | /// Records whether or not the validator should relax the rules on pointer usage 89 | /// in logical addressing mode. 90 | /// 91 | /// When relaxed, it will allow the following usage cases of pointers: 92 | /// 1) OpVariable allocating an object whose type is a pointer type 93 | /// 2) OpReturnValue returning a pointer value 94 | #[link_name = "spvValidatorOptionsSetRelaxLogicalPointer"] 95 | pub fn validator_options_set_relax_logical_pointer(opts: *mut ValidatorOptions, toggle: bool); 96 | 97 | /// Records whether or not the validator should relax the rules because it is 98 | /// expected that the optimizations will make the code legal. 99 | /// 100 | /// When relaxed, it will allow the following: 101 | /// 1) It will allow relaxed logical pointers. Setting this option will also 102 | /// set that option. 103 | /// 2) Pointers that are pass as parameters to function calls do not have to 104 | /// match the storage class of the formal parameter. 105 | /// 3) Pointers that are actaul parameters on function calls do not have to point 106 | /// to the same type pointed as the formal parameter. The types just need to 107 | /// logically match. 108 | #[link_name = "spvValidatorOptionsSetBeforeHlslLegalization"] 109 | pub fn validator_options_set_before_legalization(opts: *mut ValidatorOptions, toggle: bool); 110 | 111 | /// Records whether the validator should use "relaxed" block layout rules. 112 | /// Relaxed layout rules are described by Vulkan extension 113 | /// VK_KHR_relaxed_block_layout, and they affect uniform blocks, storage blocks, 114 | /// and push constants. 115 | /// 116 | /// This is enabled by default when targeting Vulkan 1.1 or later. 117 | /// Relaxed layout is more permissive than the default rules in Vulkan 1.0. 118 | #[link_name = "spvValidatorOptionsSetRelaxBlockLayout"] 119 | pub fn validator_options_set_relax_block_layout(opts: *mut ValidatorOptions, toggle: bool); 120 | 121 | /// Records whether the validator should use standard block layout rules for 122 | /// uniform blocks. 123 | #[link_name = "spvValidatorOptionsSetUniformBufferStandardLayout"] 124 | pub fn validator_options_set_uniform_buffer_standard_layout( 125 | opts: *mut ValidatorOptions, 126 | toggle: bool, 127 | ); 128 | 129 | /// Records whether the validator should use "scalar" block layout rules. 130 | /// Scalar layout rules are more permissive than relaxed block layout. 131 | /// 132 | /// See Vulkan extnesion VK_EXT_scalar_block_layout. The scalar alignment is 133 | /// defined as follows: 134 | /// - scalar alignment of a scalar is the scalar size 135 | /// - scalar alignment of a vector is the scalar alignment of its component 136 | /// - scalar alignment of a matrix is the scalar alignment of its component 137 | /// - scalar alignment of an array is the scalar alignment of its element 138 | /// - scalar alignment of a struct is the max scalar alignment among its 139 | /// members 140 | /// 141 | /// For a struct in Uniform, StorageClass, or PushConstant: 142 | /// - a member Offset must be a multiple of the member's scalar alignment 143 | /// - ArrayStride or MatrixStride must be a multiple of the array or matrix 144 | /// scalar alignment 145 | #[link_name = "spvValidatorOptionsSetScalarBlockLayout"] 146 | pub fn validator_options_set_scalar_block_layout(opts: *mut ValidatorOptions, toggle: bool); 147 | 148 | /// Records whether or not the validator should skip validating standard 149 | /// uniform/storage block layout. 150 | #[link_name = "spvValidatorOptionsSetSkipBlockLayout"] 151 | pub fn validator_options_set_skip_block_layout(opts: *mut ValidatorOptions, toggle: bool); 152 | } 153 | -------------------------------------------------------------------------------- /src/opt/compiled.rs: -------------------------------------------------------------------------------- 1 | use crate::error; 2 | use spirv_tools_sys::opt; 3 | 4 | pub struct Options { 5 | pub(crate) inner: *mut opt::OptimizerOptions, 6 | } 7 | 8 | impl From for Options { 9 | fn from(o: super::Options) -> Self { 10 | unsafe { 11 | let inner = opt::optimizer_options_create(); 12 | 13 | if let Some(vopts) = o.validator_options { 14 | let vopts = crate::val::compiled::Options::from(vopts); 15 | 16 | opt::optimizer_options_run_validator(inner, true); 17 | 18 | // The validator options are copied, so it's fine to drop vopts 19 | // after this call 20 | opt::optimizer_options_set_validator_options(inner, vopts.inner); 21 | } 22 | 23 | if let Some(max_bound) = o.max_id_bound { 24 | opt::optimizer_options_set_max_id_bound(inner, max_bound); 25 | } 26 | 27 | if o.preserve_bindings { 28 | opt::optimizer_options_preserve_bindings(inner, true); 29 | } 30 | 31 | if o.preserve_spec_constants { 32 | opt::optimizer_options_preserve_spec_constants(inner, true); 33 | } 34 | 35 | Self { inner } 36 | } 37 | } 38 | } 39 | 40 | impl Drop for Options { 41 | #[inline] 42 | fn drop(&mut self) { 43 | unsafe { opt::optimizer_options_destroy(self.inner) } 44 | } 45 | } 46 | 47 | pub struct CompiledOptimizer { 48 | inner: *mut opt::Optimizer, 49 | } 50 | 51 | use super::Optimizer; 52 | 53 | impl Optimizer for CompiledOptimizer { 54 | fn with_env(target: crate::TargetEnv) -> Self { 55 | Self { 56 | inner: unsafe { opt::optimizer_create(target) }, 57 | } 58 | } 59 | 60 | fn optimize( 61 | &self, 62 | input: impl AsRef<[u32]>, 63 | msg_callback: &mut MC, 64 | options: Option, 65 | ) -> Result { 66 | unsafe { 67 | struct Ctx<'a> { 68 | cb: &'a mut dyn error::MessageCallback, 69 | } 70 | 71 | let mut ctx = Ctx { cb: msg_callback }; 72 | 73 | let cb_ctx: *mut std::ffi::c_void = (&mut ctx as *mut Ctx<'_>).cast(); 74 | 75 | extern "C" fn callback( 76 | level: spirv_tools_sys::diagnostics::MessageLevel, 77 | source: *const std::os::raw::c_char, 78 | source_pos: *const spirv_tools_sys::diagnostics::Position, 79 | msg: *const std::os::raw::c_char, 80 | ctx: *mut std::ffi::c_void, 81 | ) { 82 | unsafe { 83 | let ctx: &mut Ctx<'_> = &mut *(ctx.cast::>()); 84 | 85 | let msg = error::Message::from_parts(level, source, source_pos, msg); 86 | 87 | ctx.cb.on_message(msg); 88 | } 89 | } 90 | 91 | let mut binary = std::ptr::null_mut(); 92 | 93 | let options = options.map(Options::from); 94 | 95 | let options = match &options { 96 | Some(opts) => opts.inner, 97 | None => std::ptr::null(), 98 | }; 99 | 100 | let input = input.as_ref(); 101 | 102 | let res = opt::optimizer_run( 103 | self.inner, 104 | input.as_ptr(), 105 | input.len(), 106 | &mut binary, 107 | callback, 108 | cb_ctx, 109 | options, 110 | ); 111 | 112 | match res { 113 | spirv_tools_sys::shared::SpirvResult::Success => { 114 | if binary.is_null() { 115 | return Err(error::Error { 116 | inner: spirv_tools_sys::shared::SpirvResult::InternalError, 117 | diagnostic: Some(crate::error::Diagnostic { 118 | line: 0, 119 | column: 0, 120 | index: 0, 121 | message: "spirv optimizer indicated success but did not return a valid binary".to_owned(), 122 | notes: String::new(), 123 | is_text: false, 124 | }), 125 | }); 126 | } 127 | 128 | Ok(crate::binary::Binary::External( 129 | crate::binary::external::ExternalBinary::new(binary), 130 | )) 131 | } 132 | other => Err(error::Error { 133 | inner: other, 134 | diagnostic: None, 135 | }), 136 | } 137 | } 138 | } 139 | 140 | /// Register a single pass with the the optimizer. 141 | #[inline] 142 | fn register_pass(&mut self, pass: super::Passes) -> &mut Self { 143 | unsafe { opt::optimizer_register_pass(self.inner, pass) } 144 | self 145 | } 146 | 147 | /// Registers passes that attempt to improve performance of generated code. 148 | /// This sequence of passes is subject to constant review and will change 149 | /// from time to time. 150 | #[inline] 151 | fn register_performance_passes(&mut self) -> &mut Self { 152 | unsafe { opt::optimizer_register_performance_passes(self.inner) } 153 | self 154 | } 155 | 156 | /// Registers passes that attempt to improve the size of generated code. 157 | /// This sequence of passes is subject to constant review and will change 158 | /// from time to time. 159 | #[inline] 160 | fn register_size_passes(&mut self) -> &mut Self { 161 | unsafe { opt::optimizer_register_size_passes(self.inner) } 162 | self 163 | } 164 | 165 | // /// Registers passes that have been prescribed for converting from Vulkan to 166 | // /// WebGPU. This sequence of passes is subject to constant review and will 167 | // /// change from time to time. 168 | // #[inline] 169 | // pub fn register_vulkan_to_webgpu_passes(&mut self) -> &mut Self { 170 | // unsafe { opt::optimizer_register_vulkan_to_webgpu_passes(self.inner) } 171 | // self 172 | // } 173 | 174 | // /// Registers passes that have been prescribed for converting from WebGPU to 175 | // /// Vulkan. This sequence of passes is subject to constant review and will 176 | // /// change from time to time. 177 | // #[inline] 178 | // pub fn register_webgpu_to_vulkan_passes(&mut self) -> &mut Self { 179 | // unsafe { opt::optimizer_register_webgpu_to_vulkan_passes(self.inner) } 180 | // self 181 | // } 182 | 183 | /// Registers passes that attempt to legalize the generated code. 184 | /// 185 | /// Note: this recipe is specially designed for legalizing SPIR-V. It should be 186 | /// used by compilers after translating HLSL source code literally. It should 187 | /// *not* be used by general workloads for performance or size improvement. 188 | /// 189 | /// This sequence of passes is subject to constant review and will change 190 | /// from time to time. 191 | #[inline] 192 | fn register_hlsl_legalization_passes(&mut self) -> &mut Self { 193 | unsafe { opt::optimizer_register_hlsl_legalization_passes(self.inner) } 194 | self 195 | } 196 | } 197 | 198 | impl Default for CompiledOptimizer { 199 | fn default() -> Self { 200 | Self::with_env(crate::TargetEnv::default()) 201 | } 202 | } 203 | 204 | impl Drop for CompiledOptimizer { 205 | #[inline] 206 | fn drop(&mut self) { 207 | unsafe { opt::optimizer_destroy(self.inner) } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/cmd.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Message; 2 | use std::process::{Command, Stdio}; 3 | 4 | pub enum CmdError { 5 | /// The binary failed to spawn, probably because it's not installed 6 | /// or not in PATH 7 | BinaryNotFound(std::io::Error), 8 | /// An I/O error occurred accessing the process' pipes 9 | Io(std::io::Error), 10 | /// The binary ran, but returned a non-zero exit code and (hopefully) 11 | /// diagnostics 12 | ToolErrors { 13 | exit_code: i32, 14 | /// Messages that were parsed from the output 15 | messages: Vec, 16 | }, 17 | } 18 | 19 | impl From for crate::error::Error { 20 | fn from(ce: CmdError) -> Self { 21 | use crate::SpirvResult; 22 | 23 | match ce { 24 | CmdError::BinaryNotFound(err) => Self { 25 | inner: SpirvResult::Unsupported, 26 | diagnostic: Some(format!("failed to spawn executable: {err}").into()), 27 | }, 28 | CmdError::Io(err) => Self { 29 | inner: SpirvResult::EndOfStream, 30 | diagnostic: Some( 31 | format!("i/o error occurred communicating with executable: {err}").into(), 32 | ), 33 | }, 34 | CmdError::ToolErrors { 35 | exit_code, 36 | messages, 37 | } => { 38 | // The C API just puts the last message as the diagnostic, so just do the 39 | // same for now 40 | let diagnostic = messages.into_iter().last().map_or_else( 41 | || { 42 | crate::error::Diagnostic::from(format!( 43 | "tool exited with code `{exit_code}` and no output" 44 | )) 45 | }, 46 | crate::error::Diagnostic::from, 47 | ); 48 | 49 | Self { 50 | // this isn't really correct, but the spirv binaries don't 51 | // provide the error code in any meaningful way, either by the 52 | // status code of the binary, or in diagnostic output 53 | inner: SpirvResult::InternalError, 54 | diagnostic: Some(diagnostic), 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | pub struct CmdOutput { 62 | /// The output the command is actually supposed to give back 63 | pub binary: Vec, 64 | /// Warning or Info level diagnostics that were gathered during execution 65 | pub messages: Vec, 66 | } 67 | 68 | #[derive(PartialEq, Eq, Copy, Clone)] 69 | pub enum Output { 70 | /// Doesn't try to read stdout for tool output (other than diagnostics) 71 | Ignore, 72 | /// Attempts to retrieve the tool's output from stdout 73 | Retrieve, 74 | } 75 | 76 | pub fn exec( 77 | mut cmd: Command, 78 | input: Option<&[u8]>, 79 | retrieve_output: Output, 80 | ) -> Result { 81 | cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); 82 | 83 | // Create a temp dir for the input and/or output of the tool 84 | let temp_dir = tempfile::tempdir().map_err(CmdError::Io)?; 85 | 86 | // Output 87 | let output_path = temp_dir.path().join("output"); 88 | if retrieve_output == Output::Retrieve { 89 | cmd.arg("-o").arg(&output_path); 90 | } 91 | 92 | // Input 93 | if let Some(input) = input { 94 | let input_path = temp_dir.path().join("input"); 95 | std::fs::write(&input_path, input).map_err(CmdError::Io)?; 96 | 97 | cmd.arg(&input_path); 98 | } 99 | 100 | let child = cmd.spawn().map_err(CmdError::BinaryNotFound)?; 101 | 102 | let output = child.wait_with_output().map_err(CmdError::Io)?; 103 | 104 | let code = if let Some(code) = output.status.code() { 105 | code 106 | } else { 107 | #[cfg(unix)] 108 | let message = { 109 | use std::os::unix::process::ExitStatusExt; 110 | format!( 111 | "process terminated by signal: {}", 112 | output.status.signal().unwrap_or(666) 113 | ) 114 | }; 115 | #[cfg(not(unix))] 116 | let message = "process ended in an unknown state".to_owned(); 117 | 118 | return Err(CmdError::ToolErrors { 119 | exit_code: -1, 120 | messages: vec![Message::fatal(message)], 121 | }); 122 | }; 123 | 124 | // stderr should only ever contain error+ level diagnostics 125 | if code != 0 { 126 | use crate::error::*; 127 | let messages: Vec<_> = match String::from_utf8(output.stderr) { 128 | Ok(errors) => { 129 | let mut messages = Vec::new(); 130 | 131 | for line in errors.lines() { 132 | if let Some(msg) = Message::parse(line) { 133 | messages.push(msg); 134 | } else if let Some(msg) = messages.last_mut() { 135 | if !msg.notes.is_empty() { 136 | msg.notes.push('\n'); 137 | } 138 | 139 | msg.notes.push_str(line); 140 | } else { 141 | // We somewhow got a message that didn't conform to how 142 | // messages are supposed to look, as the first one 143 | messages.push(Message { 144 | level: MessageLevel::Error, 145 | source: None, 146 | line: 0, 147 | column: 0, 148 | index: 0, 149 | message: line.to_owned(), 150 | notes: String::new(), 151 | }); 152 | } 153 | } 154 | 155 | messages 156 | } 157 | Err(err) => vec![Message::fatal(format!( 158 | "unable to read stderr ({err}) but process exited with code {code}", 159 | ))], 160 | }; 161 | 162 | return Err(CmdError::ToolErrors { 163 | exit_code: code, 164 | messages, 165 | }); 166 | } 167 | 168 | fn split(haystack: &[u8], needle: u8) -> impl Iterator { 169 | struct Split<'a> { 170 | haystack: &'a [u8], 171 | needle: u8, 172 | } 173 | 174 | impl<'a> Iterator for Split<'a> { 175 | type Item = &'a [u8]; 176 | 177 | fn next(&mut self) -> Option<&'a [u8]> { 178 | if self.haystack.is_empty() { 179 | return None; 180 | } 181 | let (ret, remaining) = match memchr::memchr(self.needle, self.haystack) { 182 | Some(pos) => (&self.haystack[..pos], &self.haystack[pos + 1..]), 183 | None => (self.haystack, &[][..]), 184 | }; 185 | self.haystack = remaining; 186 | Some(ret) 187 | } 188 | } 189 | 190 | Split { haystack, needle } 191 | } 192 | 193 | let binary = match retrieve_output { 194 | Output::Retrieve => std::fs::read(&output_path).map_err(CmdError::Io)?, 195 | Output::Ignore => Vec::new(), 196 | }; 197 | 198 | // Since we are retrieving the results via stdout, but it can also contain 199 | // diagnostic messages, we need to be careful 200 | let mut messages = Vec::new(); 201 | 202 | for line in split(&output.stdout, b'\n') { 203 | if let Ok(s) = std::str::from_utf8(line) { 204 | if let Some(msg) = crate::error::Message::parse(s) { 205 | messages.push(msg); 206 | continue; 207 | } 208 | } 209 | 210 | break; 211 | } 212 | 213 | Ok(CmdOutput { binary, messages }) 214 | } 215 | -------------------------------------------------------------------------------- /spirv-tools-sys/src/c/opt.cpp: -------------------------------------------------------------------------------- 1 | #include "spirv-tools/optimizer.hpp" 2 | #include 3 | 4 | struct Optimus; 5 | 6 | enum Passes { 7 | AggressiveDCE, 8 | AmdExtToKhr, 9 | BlockMerge, 10 | CCP, 11 | CFGCleanup, 12 | CodeSinking, 13 | CombineAccessChains, 14 | CompactIds, 15 | ConvertRelaxedToHalf, 16 | CopyPropagateArrays, 17 | DeadBranchElim, 18 | DeadInsertElim, 19 | DeadVariableElimination, 20 | DescriptorScalarReplacement, 21 | EliminateDeadConstant, 22 | EliminateDeadFunctions, 23 | EliminateDeadMembers, 24 | FixStorageClass, 25 | FlattenDecoration, 26 | FoldSpecConstantOpAndComposite, 27 | FreezeSpecConstantValue, 28 | GraphicsRobustAccess, 29 | IfConversion, 30 | InlineExhaustive, 31 | InlineOpaque, 32 | InsertExtractElim, 33 | InterpolateFixup, 34 | LocalAccessChainConvert, 35 | LocalMultiStoreElim, 36 | LocalRedundancyElimination, 37 | LocalSingleBlockLoadStoreElim, 38 | LocalSingleStoreElim, 39 | LoopInvariantCodeMotion, 40 | LoopPeeling, 41 | LoopUnswitch, 42 | MergeReturn, 43 | Null, 44 | PrivateToLocal, 45 | PropagateLineInfo, 46 | ReduceLoadSize, 47 | RedundancyElimination, 48 | RedundantLineInfoElim, 49 | RelaxFloatOps, 50 | RemoveDuplicates, 51 | RemoveUnusedInterfaceVariables, 52 | ReplaceInvalidOpcode, 53 | Simplification, 54 | SSARewrite, 55 | StrengthReduction, 56 | StripDebugInfo, 57 | StripNonSemanticInfo, 58 | UnifyConstant, 59 | UpgradeMemoryModel, 60 | VectorDCE, 61 | Workaround1209, 62 | WrapOpKill, 63 | }; 64 | 65 | typedef void (*message_callback)( 66 | spv_message_level_t level, 67 | const char* source, 68 | const spv_position_t* position, 69 | const char* message, 70 | void* ctx 71 | ); 72 | 73 | extern "C" { 74 | SPIRV_TOOLS_EXPORT Optimus* optimizer_create(spv_target_env target_env) { 75 | auto* optimizer = new spvtools::Optimizer(target_env); 76 | 77 | return (Optimus*)optimizer; 78 | } 79 | 80 | SPIRV_TOOLS_EXPORT void optimizer_destroy(Optimus* optimizer) { 81 | delete (spvtools::Optimizer*)optimizer; 82 | } 83 | 84 | SPIRV_TOOLS_EXPORT spv_result_t optimizer_run( 85 | const Optimus* optimizer, 86 | const uint32_t* input_ptr, 87 | size_t input_size, 88 | spv_binary* out_binary, 89 | message_callback msg_callback, 90 | void* ctx, 91 | const spv_optimizer_options options 92 | ) { 93 | if (input_ptr == nullptr) { 94 | return SPV_ERROR_INVALID_POINTER; 95 | } 96 | 97 | if (out_binary == nullptr) { 98 | return SPV_ERROR_INVALID_POINTER; 99 | } 100 | 101 | auto op = (spvtools::Optimizer*)optimizer; 102 | 103 | if (msg_callback) { 104 | op->SetMessageConsumer([msg_callback, ctx]( 105 | spv_message_level_t level, 106 | const char* source, 107 | const spv_position_t& position, 108 | const char* message) { 109 | msg_callback(level, source, &position, message, ctx); 110 | }); 111 | } else { 112 | // The optimizer keeps the message consumer as state, so if no 113 | // callback is passed to us, we insert a noop callback to ensure 114 | // we don't use the state from a previous optimizer run 115 | op->SetMessageConsumer([]( 116 | spv_message_level_t, 117 | const char*, 118 | const spv_position_t&, 119 | const char*) 120 | {} 121 | ); 122 | } 123 | 124 | auto output_buff = std::vector(); 125 | bool success = false; 126 | if (options == nullptr) { 127 | success = op->Run(input_ptr, input_size, &output_buff); 128 | } else { 129 | success = op->Run(input_ptr, input_size, &output_buff, options); 130 | } 131 | 132 | if (!success) { 133 | return SPV_ERROR_INTERNAL; 134 | } 135 | 136 | auto word_count = output_buff.size(); 137 | auto data_byte_count = word_count * 4; 138 | 139 | uint32_t* data = new uint32_t[word_count]; 140 | if (data == nullptr) { 141 | return SPV_ERROR_OUT_OF_MEMORY; 142 | } 143 | 144 | spv_binary binary = new spv_binary_t { data, word_count }; 145 | if (binary == nullptr) { 146 | delete[] data; 147 | return SPV_ERROR_OUT_OF_MEMORY; 148 | } 149 | 150 | memcpy(data, output_buff.data(), data_byte_count); 151 | *out_binary = binary; 152 | 153 | return SPV_SUCCESS; 154 | } 155 | 156 | SPIRV_TOOLS_EXPORT void optimizer_register_pass(Optimus* optimizer, Passes pass) { 157 | #define PASTEB(a, b) a ## b 158 | #define PASTEA(a, b) PASTEB(a, b) 159 | #define PASS(name) \ 160 | case name: \ 161 | op->RegisterPass(spvtools::PASTEA(PASTEA(Create, name), Pass)()); \ 162 | break; 163 | 164 | spvtools::Optimizer* op = (spvtools::Optimizer*)optimizer; 165 | 166 | switch (pass) { 167 | PASS(AggressiveDCE) 168 | PASS(AmdExtToKhr) 169 | PASS(BlockMerge) 170 | PASS(CCP) 171 | PASS(CFGCleanup) 172 | PASS(CodeSinking) 173 | PASS(CombineAccessChains) 174 | PASS(CompactIds) 175 | PASS(ConvertRelaxedToHalf) 176 | PASS(CopyPropagateArrays) 177 | PASS(DeadBranchElim) 178 | PASS(DeadInsertElim) 179 | PASS(DeadVariableElimination) 180 | PASS(DescriptorScalarReplacement) 181 | PASS(EliminateDeadConstant) 182 | PASS(EliminateDeadFunctions) 183 | PASS(EliminateDeadMembers) 184 | PASS(FixStorageClass) 185 | PASS(FlattenDecoration) 186 | PASS(FoldSpecConstantOpAndComposite) 187 | PASS(FreezeSpecConstantValue) 188 | PASS(GraphicsRobustAccess) 189 | PASS(IfConversion) 190 | PASS(InlineExhaustive) 191 | PASS(InlineOpaque) 192 | PASS(InsertExtractElim) 193 | PASS(InterpolateFixup) 194 | PASS(LocalAccessChainConvert) 195 | PASS(LocalMultiStoreElim) 196 | PASS(LocalRedundancyElimination) 197 | PASS(LocalSingleBlockLoadStoreElim) 198 | PASS(LocalSingleStoreElim) 199 | PASS(LoopInvariantCodeMotion) 200 | PASS(LoopPeeling) 201 | PASS(LoopUnswitch) 202 | PASS(MergeReturn) 203 | PASS(Null) 204 | PASS(PrivateToLocal) 205 | PASS(PropagateLineInfo) 206 | PASS(ReduceLoadSize) 207 | PASS(RedundancyElimination) 208 | PASS(RedundantLineInfoElim) 209 | PASS(RelaxFloatOps) 210 | PASS(RemoveDuplicates) 211 | PASS(RemoveUnusedInterfaceVariables) 212 | PASS(ReplaceInvalidOpcode) 213 | PASS(Simplification) 214 | PASS(SSARewrite) 215 | PASS(StrengthReduction) 216 | PASS(StripDebugInfo) 217 | PASS(StripNonSemanticInfo) 218 | PASS(UnifyConstant) 219 | PASS(UpgradeMemoryModel) 220 | PASS(VectorDCE) 221 | PASS(Workaround1209) 222 | PASS(WrapOpKill) 223 | } 224 | } 225 | 226 | SPIRV_TOOLS_EXPORT void optimizer_register_performance_passes(Optimus* optimizer) { 227 | ((spvtools::Optimizer*)optimizer)->RegisterPerformancePasses(); 228 | } 229 | 230 | SPIRV_TOOLS_EXPORT void optimizer_register_size_passes(Optimus* optimizer) { 231 | ((spvtools::Optimizer*)optimizer)->RegisterSizePasses(); 232 | } 233 | 234 | SPIRV_TOOLS_EXPORT void optimizer_register_hlsl_legalization_passes(Optimus* optimizer) { 235 | ((spvtools::Optimizer*)optimizer)->RegisterLegalizationPasses(); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /spirv-tools-sys/generated/NonSemanticShaderDebugInfo100.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 The Khronos Group Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and/or associated documentation files (the "Materials"), 5 | // to deal in the Materials without restriction, including without limitation 6 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | // and/or sell copies of the Materials, and to permit persons to whom the 8 | // Materials are furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Materials. 12 | // 13 | // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS 14 | // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND 15 | // HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ 16 | // 17 | // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS 23 | // IN THE MATERIALS. 24 | 25 | #ifndef SPIRV_EXTINST_NonSemanticShaderDebugInfo100_H_ 26 | #define SPIRV_EXTINST_NonSemanticShaderDebugInfo100_H_ 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | enum { NonSemanticShaderDebugInfo100Version = 100, NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff }; 33 | enum { NonSemanticShaderDebugInfo100Revision = 6, NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff }; 34 | 35 | enum NonSemanticShaderDebugInfo100Instructions { 36 | NonSemanticShaderDebugInfo100DebugInfoNone = 0, 37 | NonSemanticShaderDebugInfo100DebugCompilationUnit = 1, 38 | NonSemanticShaderDebugInfo100DebugTypeBasic = 2, 39 | NonSemanticShaderDebugInfo100DebugTypePointer = 3, 40 | NonSemanticShaderDebugInfo100DebugTypeQualifier = 4, 41 | NonSemanticShaderDebugInfo100DebugTypeArray = 5, 42 | NonSemanticShaderDebugInfo100DebugTypeVector = 6, 43 | NonSemanticShaderDebugInfo100DebugTypedef = 7, 44 | NonSemanticShaderDebugInfo100DebugTypeFunction = 8, 45 | NonSemanticShaderDebugInfo100DebugTypeEnum = 9, 46 | NonSemanticShaderDebugInfo100DebugTypeComposite = 10, 47 | NonSemanticShaderDebugInfo100DebugTypeMember = 11, 48 | NonSemanticShaderDebugInfo100DebugTypeInheritance = 12, 49 | NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13, 50 | NonSemanticShaderDebugInfo100DebugTypeTemplate = 14, 51 | NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15, 52 | NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16, 53 | NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17, 54 | NonSemanticShaderDebugInfo100DebugGlobalVariable = 18, 55 | NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19, 56 | NonSemanticShaderDebugInfo100DebugFunction = 20, 57 | NonSemanticShaderDebugInfo100DebugLexicalBlock = 21, 58 | NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22, 59 | NonSemanticShaderDebugInfo100DebugScope = 23, 60 | NonSemanticShaderDebugInfo100DebugNoScope = 24, 61 | NonSemanticShaderDebugInfo100DebugInlinedAt = 25, 62 | NonSemanticShaderDebugInfo100DebugLocalVariable = 26, 63 | NonSemanticShaderDebugInfo100DebugInlinedVariable = 27, 64 | NonSemanticShaderDebugInfo100DebugDeclare = 28, 65 | NonSemanticShaderDebugInfo100DebugValue = 29, 66 | NonSemanticShaderDebugInfo100DebugOperation = 30, 67 | NonSemanticShaderDebugInfo100DebugExpression = 31, 68 | NonSemanticShaderDebugInfo100DebugMacroDef = 32, 69 | NonSemanticShaderDebugInfo100DebugMacroUndef = 33, 70 | NonSemanticShaderDebugInfo100DebugImportedEntity = 34, 71 | NonSemanticShaderDebugInfo100DebugSource = 35, 72 | NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101, 73 | NonSemanticShaderDebugInfo100DebugSourceContinued = 102, 74 | NonSemanticShaderDebugInfo100DebugLine = 103, 75 | NonSemanticShaderDebugInfo100DebugNoLine = 104, 76 | NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105, 77 | NonSemanticShaderDebugInfo100DebugStoragePath = 106, 78 | NonSemanticShaderDebugInfo100DebugEntryPoint = 107, 79 | NonSemanticShaderDebugInfo100DebugTypeMatrix = 108, 80 | NonSemanticShaderDebugInfo100InstructionsMax = 0x7ffffff 81 | }; 82 | 83 | 84 | enum NonSemanticShaderDebugInfo100DebugInfoFlags { 85 | NonSemanticShaderDebugInfo100None = 0x0000, 86 | NonSemanticShaderDebugInfo100FlagIsProtected = 0x01, 87 | NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02, 88 | NonSemanticShaderDebugInfo100FlagIsPublic = 0x03, 89 | NonSemanticShaderDebugInfo100FlagIsLocal = 0x04, 90 | NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08, 91 | NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10, 92 | NonSemanticShaderDebugInfo100FlagArtificial = 0x20, 93 | NonSemanticShaderDebugInfo100FlagExplicit = 0x40, 94 | NonSemanticShaderDebugInfo100FlagPrototyped = 0x80, 95 | NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100, 96 | NonSemanticShaderDebugInfo100FlagStaticMember = 0x200, 97 | NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400, 98 | NonSemanticShaderDebugInfo100FlagLValueReference = 0x800, 99 | NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000, 100 | NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000, 101 | NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000, 102 | NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000, 103 | NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000, 104 | NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000, 105 | NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7ffffff 106 | }; 107 | 108 | enum NonSemanticShaderDebugInfo100BuildIdentifierFlags { 109 | NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01, 110 | NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7ffffff 111 | }; 112 | 113 | enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding { 114 | NonSemanticShaderDebugInfo100Unspecified = 0, 115 | NonSemanticShaderDebugInfo100Address = 1, 116 | NonSemanticShaderDebugInfo100Boolean = 2, 117 | NonSemanticShaderDebugInfo100Float = 3, 118 | NonSemanticShaderDebugInfo100Signed = 4, 119 | NonSemanticShaderDebugInfo100SignedChar = 5, 120 | NonSemanticShaderDebugInfo100Unsigned = 6, 121 | NonSemanticShaderDebugInfo100UnsignedChar = 7, 122 | NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7ffffff 123 | }; 124 | 125 | enum NonSemanticShaderDebugInfo100DebugCompositeType { 126 | NonSemanticShaderDebugInfo100Class = 0, 127 | NonSemanticShaderDebugInfo100Structure = 1, 128 | NonSemanticShaderDebugInfo100Union = 2, 129 | NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7ffffff 130 | }; 131 | 132 | enum NonSemanticShaderDebugInfo100DebugTypeQualifier { 133 | NonSemanticShaderDebugInfo100ConstType = 0, 134 | NonSemanticShaderDebugInfo100VolatileType = 1, 135 | NonSemanticShaderDebugInfo100RestrictType = 2, 136 | NonSemanticShaderDebugInfo100AtomicType = 3, 137 | NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7ffffff 138 | }; 139 | 140 | enum NonSemanticShaderDebugInfo100DebugOperation { 141 | NonSemanticShaderDebugInfo100Deref = 0, 142 | NonSemanticShaderDebugInfo100Plus = 1, 143 | NonSemanticShaderDebugInfo100Minus = 2, 144 | NonSemanticShaderDebugInfo100PlusUconst = 3, 145 | NonSemanticShaderDebugInfo100BitPiece = 4, 146 | NonSemanticShaderDebugInfo100Swap = 5, 147 | NonSemanticShaderDebugInfo100Xderef = 6, 148 | NonSemanticShaderDebugInfo100StackValue = 7, 149 | NonSemanticShaderDebugInfo100Constu = 8, 150 | NonSemanticShaderDebugInfo100Fragment = 9, 151 | NonSemanticShaderDebugInfo100DebugOperationMax = 0x7ffffff 152 | }; 153 | 154 | enum NonSemanticShaderDebugInfo100DebugImportedEntity { 155 | NonSemanticShaderDebugInfo100ImportedModule = 0, 156 | NonSemanticShaderDebugInfo100ImportedDeclaration = 1, 157 | NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7ffffff 158 | }; 159 | 160 | 161 | #ifdef __cplusplus 162 | } 163 | #endif 164 | 165 | #endif // SPIRV_EXTINST_NonSemanticShaderDebugInfo100_H_ -------------------------------------------------------------------------------- /spirv-tools-sys/src/shared.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | /// Certain target environments impose additional restrictions on SPIR-V, so it's 4 | /// often necessary to specify which one applies. `Universal_*` implies an 5 | /// environment-agnostic SPIR-V. 6 | /// 7 | /// When an API method needs to derive a SPIR-V version from a target environment 8 | /// the method will choose the highest version of SPIR-V supported by the target 9 | /// environment. Examples: 10 | /// 11 | /// ``` 12 | /// SPV_ENV_VULKAN_1_0 -> SPIR-V 1.0 13 | /// SPV_ENV_VULKAN_1_1 -> SPIR-V 1.3 14 | /// SPV_ENV_VULKAN_1_1_SPIRV_1_4 -> SPIR-V 1.4 15 | /// SPV_ENV_VULKAN_1_2 -> SPIR-V 1.5 16 | /// ``` 17 | /// 18 | /// Consult the description of API entry points for specific rules. 19 | #[derive(Copy, Clone, Debug, PartialEq)] 20 | #[repr(C)] 21 | #[allow(non_camel_case_types, clippy::upper_case_acronyms)] 22 | pub enum TargetEnv { 23 | /// SPIR-V 1.0 latest revision, no other restrictions. 24 | Universal_1_0, 25 | /// Vulkan 1.0 latest revision. 26 | Vulkan_1_0, 27 | /// SPIR-V 1.1 latest revision, no other restrictions. 28 | Universal_1_1, 29 | /// OpenCL Full Profile 2.1 latest revision. 30 | OpenCL_2_1, 31 | /// OpenCL Full Profile 2.2 latest revision. 32 | OpenCL_2_2, 33 | /// OpenGL 4.0 plus GL_ARB_gl_spirv, latest revisions. 34 | OpenGL_4_0, 35 | /// OpenGL 4.1 plus GL_ARB_gl_spirv, latest revisions. 36 | OpenGL_4_1, 37 | /// OpenGL 4.2 plus GL_ARB_gl_spirv, latest revisions. 38 | OpenGL_4_2, 39 | /// OpenGL 4.3 plus GL_ARB_gl_spirv, latest revisions. 40 | OpenGL_4_3, 41 | /// OpenGL 4.5 plus GL_ARB_gl_spirv, latest revisions. 42 | OpenGL_4_5, 43 | /// SPIR-V 1.2, latest revision, no other restrictions. 44 | Universal_1_2, 45 | /// OpenCL Full Profile 1.2 plus cl_khr_il_program, latest revision. 46 | OpenCL_1_2, 47 | /// OpenCL Embedded Profile 1.2 plus cl_khr_il_program, latest revision. 48 | OpenCLEmbedded_1_2, 49 | /// OpenCL Full Profile 2.0 plus cl_khr_il_program, latest revision. 50 | OpenCL_2_0, 51 | /// OpenCL Embedded Profile 2.0 plus cl_khr_il_program, latest revision. 52 | OpenCLEmbedded_2_0, 53 | /// OpenCL Embedded Profile 2.1 latest revision. 54 | OpenCLEmbedded_2_1, 55 | /// OpenCL Embedded Profile 2.2 latest revision. 56 | OpenCLEmbedded_2_2, 57 | /// SPIR-V 1.3 latest revision, no other restrictions. 58 | Universal_1_3, 59 | /// Vulkan 1.1 latest revision. 60 | Vulkan_1_1, 61 | /// Work in progress WebGPU 1.0. 62 | WebGPU_0, 63 | /// SPIR-V 1.4 latest revision, no other restrictions. 64 | Universal_1_4, 65 | /// Vulkan 1.1 with VK_KHR_spirv_1_4, i.e. SPIR-V 1.4 binary. 66 | Vulkan_1_1_Spirv_1_4, 67 | /// SPIR-V 1.5 latest revision, no other restrictions. 68 | Universal_1_5, 69 | /// Vulkan 1.2 latest revision. 70 | Vulkan_1_2, 71 | } 72 | 73 | impl Default for TargetEnv { 74 | fn default() -> Self { 75 | // This is the default target environment for (AFAICT) all spirv-tools 76 | Self::Universal_1_5 77 | } 78 | } 79 | 80 | impl std::str::FromStr for TargetEnv { 81 | type Err = SpirvResult; 82 | 83 | fn from_str(s: &str) -> Result { 84 | Ok(match s { 85 | "vulkan1.1spv1.4" => Self::Vulkan_1_1_Spirv_1_4, 86 | "vulkan1.0" => Self::Vulkan_1_0, 87 | "vulkan1.1" => Self::Vulkan_1_1, 88 | "vulkan1.2" => Self::Vulkan_1_2, 89 | "spv1.0" => Self::Universal_1_0, 90 | "spv1.1" => Self::Universal_1_1, 91 | "spv1.2" => Self::Universal_1_2, 92 | "spv1.3" => Self::Universal_1_3, 93 | "spv1.4" => Self::Universal_1_4, 94 | "spv1.5" => Self::Universal_1_5, 95 | "opencl1.2embedded" => Self::OpenCLEmbedded_1_2, 96 | "opencl1.2" => Self::OpenCL_1_2, 97 | "opencl2.0embedded" => Self::OpenCLEmbedded_2_0, 98 | "opencl2.0" => Self::OpenCL_2_0, 99 | "opencl2.1embedded" => Self::OpenCLEmbedded_2_1, 100 | "opencl2.1" => Self::OpenCL_2_1, 101 | "opencl2.2embedded" => Self::OpenCLEmbedded_2_2, 102 | "opencl2.2" => Self::OpenCL_2_2, 103 | "opengl4.0" => Self::OpenGL_4_0, 104 | "opengl4.1" => Self::OpenGL_4_1, 105 | "opengl4.2" => Self::OpenGL_4_2, 106 | "opengl4.3" => Self::OpenGL_4_3, 107 | "opengl4.5" => Self::OpenGL_4_5, 108 | "webgpu0" => Self::WebGPU_0, 109 | _ => return Err(SpirvResult::InvalidValue), 110 | }) 111 | } 112 | } 113 | 114 | impl fmt::Display for TargetEnv { 115 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 116 | f.write_str(match self { 117 | Self::Vulkan_1_1_Spirv_1_4 => "vulkan1.1spv1.4", 118 | Self::Vulkan_1_0 => "vulkan1.0", 119 | Self::Vulkan_1_1 => "vulkan1.1", 120 | Self::Vulkan_1_2 => "vulkan1.2", 121 | Self::Universal_1_0 => "spv1.0", 122 | Self::Universal_1_1 => "spv1.1", 123 | Self::Universal_1_2 => "spv1.2", 124 | Self::Universal_1_3 => "spv1.3", 125 | Self::Universal_1_4 => "spv1.4", 126 | Self::Universal_1_5 => "spv1.5", 127 | Self::OpenCLEmbedded_1_2 => "opencl1.2embedded", 128 | Self::OpenCL_1_2 => "opencl1.2", 129 | Self::OpenCLEmbedded_2_0 => "opencl2.0embedded", 130 | Self::OpenCL_2_0 => "opencl2.0", 131 | Self::OpenCLEmbedded_2_1 => "opencl2.1embedded", 132 | Self::OpenCL_2_1 => "opencl2.1", 133 | Self::OpenCLEmbedded_2_2 => "opencl2.2embedded", 134 | Self::OpenCL_2_2 => "opencl2.2", 135 | Self::OpenGL_4_0 => "opengl4.0", 136 | Self::OpenGL_4_1 => "opengl4.1", 137 | Self::OpenGL_4_2 => "opengl4.2", 138 | Self::OpenGL_4_3 => "opengl4.3", 139 | Self::OpenGL_4_5 => "opengl4.5", 140 | Self::WebGPU_0 => "webgpu0", 141 | }) 142 | } 143 | } 144 | 145 | #[derive(Copy, Clone, Debug, PartialEq)] 146 | #[repr(i32)] // SPV_FORCE_32_BIT_ENUM 147 | pub enum SpirvResult { 148 | Success = 0, 149 | Unsupported = 1, 150 | EndOfStream = 2, 151 | Warning = 3, 152 | FailedMatch = 4, 153 | /// Success, but signals early termination. 154 | RequestedTermination = 5, 155 | InternalError = -1, 156 | OutOfMemory = -2, 157 | InvalidPointer = -3, 158 | InvalidBinary = -4, 159 | InvalidText = -5, 160 | InvalidTable = -6, 161 | InvalidValue = -7, 162 | InvalidDiagnostic = -8, 163 | InvalidLookup = -9, 164 | InvalidId = -10, 165 | InvalidCfg = -11, 166 | InvalidLayout = -12, 167 | InvalidCapability = -13, 168 | /// Indicates data rules validation failure. 169 | InvalidData = -14, 170 | MissingExtension = -15, 171 | /// Indicates wrong SPIR-V version 172 | WrongVersion = -16, 173 | } 174 | 175 | impl fmt::Display for SpirvResult { 176 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 177 | #[allow(clippy::enum_glob_use)] 178 | use SpirvResult::*; 179 | 180 | match self { 181 | Success => f.write_str("success"), 182 | Unsupported => f.write_str("unsupported"), 183 | EndOfStream => f.write_str("end of stream"), 184 | Warning => f.write_str("warning"), 185 | FailedMatch => f.write_str("failed match"), 186 | RequestedTermination => f.write_str("requested termination"), 187 | InternalError => f.write_str("internal error"), 188 | OutOfMemory => f.write_str("out of memory"), 189 | InvalidPointer => f.write_str("invalid pointer"), 190 | InvalidBinary => f.write_str("invalid binary"), 191 | InvalidText => f.write_str("invalid text"), 192 | InvalidTable => f.write_str("invalid table"), 193 | InvalidValue => f.write_str("invalid value"), 194 | InvalidDiagnostic => f.write_str("invalid diagnostic"), 195 | InvalidLookup => f.write_str("invalid lookup"), 196 | InvalidId => f.write_str("invalid id"), 197 | InvalidCfg => f.write_str("invalid cfg"), 198 | InvalidLayout => f.write_str("invalid layout"), 199 | InvalidCapability => f.write_str("invalid capability"), 200 | InvalidData => f.write_str("invalid data"), 201 | MissingExtension => f.write_str("missing extension"), 202 | WrongVersion => f.write_str("wrong SPIR-V version"), 203 | } 204 | } 205 | } 206 | 207 | impl std::error::Error for SpirvResult {} 208 | 209 | #[repr(C)] 210 | pub struct Binary { 211 | pub code: *const u32, 212 | pub size: usize, 213 | } 214 | 215 | #[repr(C)] 216 | pub struct ToolContext { 217 | _unused: [u8; 0], 218 | } 219 | 220 | extern "C" { 221 | /// Creates a context object for most of the SPIRV-Tools API. 222 | /// Returns null if env is invalid. 223 | /// 224 | /// See specific API calls for how the target environment is interpeted 225 | /// (particularly assembly and validation). 226 | #[link_name = "spvContextCreate"] 227 | pub fn context_create(env: TargetEnv) -> *mut ToolContext; 228 | /// Destroys the given context object. 229 | #[link_name = "spvContextDestroy"] 230 | pub fn context_destroy(opt: *mut ToolContext); 231 | 232 | /// Frees a binary stream from memory. This is a no-op if binary is a null 233 | /// pointer. 234 | #[link_name = "spvBinaryDestroy"] 235 | pub fn binary_destroy(binary: *mut Binary); 236 | } 237 | -------------------------------------------------------------------------------- /spirv-tools-sys/build.rs: -------------------------------------------------------------------------------- 1 | use cc::Build; 2 | use std::path::Path; 3 | 4 | fn add_includes(builder: &mut Build, root: &str, includes: &[&str]) { 5 | let root = Path::new(root); 6 | 7 | for inc in includes { 8 | builder.include(root.join(inc)); 9 | } 10 | } 11 | 12 | fn add_sources(builder: &mut Build, root: &str, files: &[&str]) { 13 | let root = Path::new(root); 14 | builder.files(files.iter().map(|src| { 15 | let mut p = root.join(src); 16 | p.set_extension("cpp"); 17 | p 18 | })); 19 | } 20 | 21 | fn shared(build: &mut Build) { 22 | add_sources( 23 | build, 24 | "spirv-tools/source", 25 | &[ 26 | "util/bit_vector", 27 | "util/parse_number", 28 | "util/string_utils", 29 | "assembly_grammar", 30 | "binary", 31 | "diagnostic", 32 | "disassemble", 33 | "enum_string_mapping", 34 | "ext_inst", 35 | "extensions", 36 | "libspirv", 37 | "name_mapper", 38 | "opcode", 39 | "operand", 40 | "parsed_operand", 41 | "print", 42 | "software_version", 43 | "spirv_endian", 44 | "spirv_fuzzer_options", 45 | "spirv_optimizer_options", 46 | "spirv_reducer_options", 47 | "spirv_target_env", 48 | "spirv_validator_options", 49 | "table", 50 | "text", 51 | "text_handler", 52 | ], 53 | ); 54 | } 55 | 56 | fn opt(build: &mut Build) { 57 | build.file("src/c/opt.cpp"); 58 | 59 | add_sources( 60 | build, 61 | "spirv-tools/source/opt", 62 | &[ 63 | "aggressive_dead_code_elim_pass", 64 | "analyze_live_input_pass", 65 | "amd_ext_to_khr", 66 | "basic_block", 67 | "block_merge_pass", 68 | "block_merge_util", 69 | "build_module", 70 | "ccp_pass", 71 | "cfg", 72 | "cfg_cleanup_pass", 73 | "code_sink", 74 | "combine_access_chains", 75 | "compact_ids_pass", 76 | "composite", 77 | "const_folding_rules", 78 | "constants", 79 | "convert_to_half_pass", 80 | "convert_to_sampled_image_pass", 81 | "copy_prop_arrays", 82 | "dead_branch_elim_pass", 83 | "dead_insert_elim_pass", 84 | "dead_variable_elimination", 85 | "debug_info_manager", 86 | "decoration_manager", 87 | "def_use_manager", 88 | "desc_sroa", 89 | "desc_sroa_util", 90 | "dominator_analysis", 91 | "dominator_tree", 92 | "eliminate_dead_constant_pass", 93 | "eliminate_dead_functions_pass", 94 | "eliminate_dead_functions_util", 95 | "eliminate_dead_io_components_pass", 96 | "eliminate_dead_members_pass", 97 | "eliminate_dead_output_stores_pass", 98 | "feature_manager", 99 | "fix_func_call_arguments", 100 | "fix_storage_class", 101 | "flatten_decoration_pass", 102 | "fold", 103 | "fold_spec_constant_op_and_composite_pass", 104 | "folding_rules", 105 | "freeze_spec_constant_value_pass", 106 | "function", 107 | "graphics_robust_access_pass", 108 | "if_conversion", 109 | "inline_exhaustive_pass", 110 | "inline_opaque_pass", 111 | "inline_pass", 112 | "inst_bindless_check_pass", 113 | "inst_buff_addr_check_pass", 114 | "inst_debug_printf_pass", 115 | "instruction", 116 | "instruction_list", 117 | "instrument_pass", 118 | "interface_var_sroa", 119 | "interp_fixup_pass", 120 | "invocation_interlock_placement_pass", 121 | "ir_context", 122 | "ir_loader", 123 | "licm_pass", 124 | "liveness", 125 | "local_access_chain_convert_pass", 126 | "local_redundancy_elimination", 127 | "local_single_block_elim_pass", 128 | "local_single_store_elim_pass", 129 | "loop_dependence", 130 | "loop_dependence_helpers", 131 | "loop_descriptor", 132 | "loop_fission", 133 | "loop_fusion", 134 | "loop_fusion_pass", 135 | "loop_peeling", 136 | "loop_unroller", 137 | "loop_unswitch_pass", 138 | "loop_utils", 139 | "mem_pass", 140 | "merge_return_pass", 141 | "module", 142 | "optimizer", 143 | "pass", 144 | "pass_manager", 145 | "pch_source_opt", 146 | "private_to_local_pass", 147 | "propagator", 148 | "reduce_load_size", 149 | "redundancy_elimination", 150 | "register_pressure", 151 | "relax_float_ops_pass", 152 | "remove_dontinline_pass", 153 | "remove_duplicates_pass", 154 | "remove_unused_interface_variables_pass", 155 | "replace_desc_array_access_using_var_index", 156 | "replace_invalid_opc", 157 | "scalar_analysis", 158 | "scalar_analysis_simplification", 159 | "scalar_replacement_pass", 160 | "set_spec_constant_default_value_pass", 161 | "simplification_pass", 162 | "spread_volatile_semantics", 163 | "ssa_rewrite_pass", 164 | "strength_reduction_pass", 165 | "strip_debug_info_pass", 166 | "strip_nonsemantic_info_pass", 167 | "struct_cfg_analysis", 168 | "switch_descriptorset_pass", 169 | "trim_capabilities_pass", 170 | "type_manager", 171 | "types", 172 | "unify_const_pass", 173 | "upgrade_memory_model", 174 | "value_number_table", 175 | "vector_dce", 176 | "workaround1209", 177 | "wrap_opkill", 178 | ], 179 | ); 180 | } 181 | 182 | fn val(build: &mut Build) { 183 | add_sources( 184 | build, 185 | "spirv-tools/source/val", 186 | &[ 187 | "validate", 188 | "validate_adjacency", 189 | "validate_annotation", 190 | "validate_arithmetics", 191 | "validate_atomics", 192 | "validate_barriers", 193 | "validate_bitwise", 194 | "validate_builtins", 195 | "validate_capability", 196 | "validate_cfg", 197 | "validate_composites", 198 | "validate_constants", 199 | "validate_conversion", 200 | "validate_debug", 201 | "validate_decorations", 202 | "validate_derivatives", 203 | "validate_extensions", 204 | "validate_execution_limitations", 205 | "validate_function", 206 | "validate_id", 207 | "validate_image", 208 | "validate_interfaces", 209 | "validate_instruction", 210 | "validate_layout", 211 | "validate_literals", 212 | "validate_logicals", 213 | "validate_memory", 214 | "validate_memory_semantics", 215 | "validate_mesh_shading", 216 | "validate_misc", 217 | "validate_mode_setting", 218 | "validate_non_uniform", 219 | "validate_primitives", 220 | "validate_ray_query", 221 | "validate_ray_tracing", 222 | "validate_ray_tracing_reorder", 223 | "validate_scopes", 224 | "validate_small_type_uses", 225 | "validate_type", 226 | "basic_block", 227 | "construct", 228 | "function", 229 | "instruction", 230 | "validation_state", 231 | ], 232 | ); 233 | } 234 | 235 | fn main() { 236 | let use_installed = std::env::var("CARGO_FEATURE_USE_INSTALLED_TOOLS").is_ok(); 237 | let use_compiled = std::env::var("CARGO_FEATURE_USE_COMPILED_TOOLS").is_ok(); 238 | 239 | if !use_compiled && !use_installed { 240 | panic!("Enable at least one of `use-compiled-tools` or `use-installed-tools` features"); 241 | } 242 | 243 | if use_installed && !use_compiled { 244 | println!("cargo:warning=use-installed-tools feature on, skipping compilation of C++ code"); 245 | return; 246 | } 247 | 248 | let mut build = Build::new(); 249 | 250 | add_includes(&mut build, "spirv-tools", &["", "include"]); 251 | add_includes(&mut build, "generated", &[""]); 252 | add_includes( 253 | &mut build, 254 | "spirv-headers", 255 | &["include", "include/spirv/unified1"], 256 | ); 257 | 258 | shared(&mut build); 259 | val(&mut build); 260 | opt(&mut build); 261 | 262 | build.define("SPIRV_CHECK_CONTEXT", None); 263 | 264 | let target_def = match std::env::var("CARGO_CFG_TARGET_OS") 265 | .expect("CARGO_CFG_TARGET_OS not set") 266 | .as_str() 267 | { 268 | "linux" => "SPIRV_LINUX", 269 | "windows" => "SPIRV_WINDOWS", 270 | "macos" => "SPIRV_MAC", 271 | android if android.starts_with("android") => "SPIRV_ANDROID", 272 | "freebsd" => "SPIRV_FREEBSD", 273 | other => panic!("unsupported target os '{other}'"), 274 | }; 275 | 276 | build.define(target_def, None); 277 | 278 | let compiler = build.get_compiler(); 279 | 280 | if compiler.is_like_gnu() { 281 | build 282 | .flag("-Wall") 283 | .flag("-Wextra") 284 | .flag("-Wnon-virtual-dtor") 285 | .flag("-Wno-missing-field-initializers") 286 | .flag("-Werror") 287 | .flag("-std=c++17") 288 | .flag("-fno-exceptions") 289 | .flag("-fno-rtti") 290 | .flag("-Wno-long-long") 291 | .flag("-Wshadow") 292 | .flag("-Wundef") 293 | .flag("-Wconversion") 294 | .flag("-Wno-sign-conversion") 295 | .flag("-Wno-deprecated-declarations"); // suppress warnings about sprintf 296 | } else if compiler.is_like_clang() { 297 | build 298 | .flag("-Wextra-semi") 299 | .flag("-Wall") 300 | .flag("-Wextra") 301 | .flag("-Wnon-virtual-dtor") 302 | .flag("-Wno-missing-field-initializers") 303 | .flag("-Wno-self-assign") 304 | .flag("-Werror") 305 | .flag("-std=c++17") 306 | .flag("-fno-exceptions") 307 | .flag("-fno-rtti") 308 | .flag("-Wno-long-long") 309 | .flag("-Wshadow") 310 | .flag("-Wundef") 311 | .flag("-Wconversion") 312 | .flag("-Wno-sign-conversion") 313 | .flag("-Wno-deprecated-declarations") // suppress warnings about sprintf 314 | .flag("-ftemplate-depth=1024"); 315 | } else if compiler.is_like_msvc() { 316 | build.flag("/std:c++17"); 317 | } 318 | 319 | build.cpp(true); 320 | build.compile("spirv-tools"); 321 | 322 | println!("cargo:rerun-if-changed=spirv-tools"); 323 | println!("cargo:rerun-if-changed=spirv-headers"); 324 | } 325 | -------------------------------------------------------------------------------- /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. 202 | --------------------------------------------------------------------------------