diff --git a/.cargo/config.in b/.cargo/config.in index 5f2c950d1c89..0845a2ebb456 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -52,6 +52,11 @@ git = "https://github.com/hsivonen/packed_simd" replace-with = "vendored-sources" rev = "3541e3818fdc7c2a24f87e3459151a4ce955a67a" +[source."https://github.com/gfx-rs/naga"] +git = "https://github.com/gfx-rs/naga" +replace-with = "vendored-sources" +rev = "bce6358eb1026c13d2f1c6d365af37afe8869a86" + [source."https://github.com/djg/cubeb-pulse-rs"] git = "https://github.com/djg/cubeb-pulse-rs" replace-with = "vendored-sources" diff --git a/Cargo.lock b/Cargo.lock index ca5ddc05f804..d6f2a9445ed4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3051,6 +3051,18 @@ version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664" +[[package]] +name = "naga" +version = "0.1.0" +source = "git+https://github.com/gfx-rs/naga?rev=bce6358eb1026c13d2f1c6d365af37afe8869a86#bce6358eb1026c13d2f1c6d365af37afe8869a86" +dependencies = [ + "bitflags", + "fxhash", + "log", + "num-traits", + "spirv_headers", +] + [[package]] name = "neqo-common" version = "0.4.3" @@ -4456,6 +4468,16 @@ dependencies = [ "spirv-cross-internal", ] +[[package]] +name = "spirv_headers" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f1418983d16481227ffa3ab3cf44ef92eebc9a76c092fbcd4c51a64ff032622" +dependencies = [ + "bitflags", + "num-traits", +] + [[package]] name = "sql-support" version = "0.1.0" @@ -5543,11 +5565,13 @@ dependencies = [ "gfx-hal", "gfx-memory", "log", + "naga", "parking_lot", "peek-poke 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ron", "serde", "smallvec", + "spirv_headers", "vec_map", "wgpu-types", ] diff --git a/gfx/wgpu/Cargo.lock b/gfx/wgpu/Cargo.lock index f918a30e7526..2cc4eda88a08 100644 --- a/gfx/wgpu/Cargo.lock +++ b/gfx/wgpu/Cargo.lock @@ -744,6 +744,18 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "naga" +version = "0.1.0" +source = "git+https://github.com/gfx-rs/naga?rev=bce6358eb1026c13d2f1c6d365af37afe8869a86#bce6358eb1026c13d2f1c6d365af37afe8869a86" +dependencies = [ + "bitflags", + "fxhash", + "log", + "num-traits", + "spirv_headers", +] + [[package]] name = "net2" version = "0.2.33" @@ -1133,6 +1145,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "spirv_headers" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f1418983d16481227ffa3ab3cf44ef92eebc9a76c092fbcd4c51a64ff032622" +dependencies = [ + "bitflags", + "num-traits", +] + [[package]] name = "stb_truetype" version = "0.3.1" @@ -1376,12 +1398,14 @@ dependencies = [ "gfx-memory", "log", "loom", + "naga", "parking_lot", "peek-poke", "raw-window-handle", "ron", "serde", "smallvec", + "spirv_headers", "vec_map", "wgpu-types", ] diff --git a/gfx/wgpu/wgpu-core/Cargo.toml b/gfx/wgpu/wgpu-core/Cargo.toml index bafe5fd85ae3..5a8cd3261ff8 100644 --- a/gfx/wgpu/wgpu-core/Cargo.toml +++ b/gfx/wgpu/wgpu-core/Cargo.toml @@ -38,8 +38,13 @@ raw-window-handle = { version = "0.3", optional = true } ron = { version = "0.5", optional = true } serde = { version = "1.0", features = ["serde_derive"], optional = true } smallvec = "1" +spirv_headers = { version = "1.4.2" } vec_map = "0.8.1" +[dependencies.naga] +git = "https://github.com/gfx-rs/naga" +rev = "bce6358eb1026c13d2f1c6d365af37afe8869a86" + [dependencies.wgt] path = "../wgpu-types" package = "wgpu-types" diff --git a/gfx/wgpu/wgpu-core/src/device/mod.rs b/gfx/wgpu/wgpu-core/src/device/mod.rs index 4d66cd228fd2..eda82baf10f5 100644 --- a/gfx/wgpu/wgpu-core/src/device/mod.rs +++ b/gfx/wgpu/wgpu-core/src/device/mod.rs @@ -30,6 +30,8 @@ use std::{ sync::atomic::Ordering, }; +use spirv_headers::ExecutionModel; + mod life; #[cfg(any(feature = "trace", feature = "replay"))] pub mod trace; @@ -1511,12 +1513,26 @@ impl Global { let spv = unsafe { slice::from_raw_parts(desc.code.bytes, desc.code.length) }; let raw = unsafe { device.raw.create_shader_module(spv).unwrap() }; + + let module = { + // Parse the given shader code and store its representation. + let spv_iter = spv.into_iter().cloned(); + let mut parser = naga::front::spirv::Parser::new(spv_iter); + parser + .parse() + .map_err(|err| { + log::warn!("Failed to parse shader SPIR-V code: {:?}", err); + log::warn!("Shader module will not be validated"); + }) + .ok() + }; let shader = pipeline::ShaderModule { raw, device_id: Stored { value: device_id, ref_count: device.life_guard.add_ref(), }, + module, }; let id = hub @@ -2014,23 +2030,55 @@ impl Global { } }; - let vertex = hal::pso::EntryPoint:: { - entry: unsafe { ffi::CStr::from_ptr(desc.vertex_stage.entry_point) } - .to_str() - .to_owned() - .unwrap(), // TODO - module: &shader_module_guard[desc.vertex_stage.module].raw, - specialization: hal::pso::Specialization::EMPTY, - }; - let fragment = - unsafe { desc.fragment_stage.as_ref() }.map(|stage| hal::pso::EntryPoint:: { - entry: unsafe { ffi::CStr::from_ptr(stage.entry_point) } + let vertex = { + let entry_point_name = + unsafe { ffi::CStr::from_ptr(desc.vertex_stage.entry_point) } .to_str() .to_owned() - .unwrap(), // TODO - module: &shader_module_guard[stage.module].raw, + .unwrap(); + + let shader_module = &shader_module_guard[desc.vertex_stage.module]; + + if let Some(ref module) = shader_module.module { + if let Err(e) = + validate_shader(module, entry_point_name, ExecutionModel::Vertex) + { + log::error!("Failed validating vertex shader module: {:?}", e); + } + } + + hal::pso::EntryPoint:: { + entry: entry_point_name, // TODO + module: &shader_module.raw, specialization: hal::pso::Specialization::EMPTY, - }); + } + }; + + let fragment = { + let fragment_stage = unsafe { desc.fragment_stage.as_ref() }; + fragment_stage.map(|stage| { + let entry_point_name = unsafe { ffi::CStr::from_ptr(stage.entry_point) } + .to_str() + .to_owned() + .unwrap(); + + let shader_module = &shader_module_guard[stage.module]; + + if let Some(ref module) = shader_module.module { + if let Err(e) = + validate_shader(module, entry_point_name, ExecutionModel::Fragment) + { + log::error!("Failed validating fragment shader module: {:?}", e); + } + } + + hal::pso::EntryPoint:: { + entry: entry_point_name, // TODO + module: &shader_module.raw, + specialization: hal::pso::Specialization::EMPTY, + } + }) + }; let shaders = hal::pso::GraphicsShaderSet { vertex, @@ -2195,12 +2243,23 @@ impl Global { let pipeline_stage = &desc.compute_stage; let (shader_module_guard, _) = hub.shader_modules.read(&mut token); + let entry_point_name = unsafe { ffi::CStr::from_ptr(pipeline_stage.entry_point) } + .to_str() + .to_owned() + .unwrap(); + + let shader_module = &shader_module_guard[pipeline_stage.module]; + + if let Some(ref module) = shader_module.module { + if let Err(e) = validate_shader(module, entry_point_name, ExecutionModel::GLCompute) + { + log::error!("Failed validating compute shader module: {:?}", e); + } + } + let shader = hal::pso::EntryPoint:: { - entry: unsafe { ffi::CStr::from_ptr(pipeline_stage.entry_point) } - .to_str() - .to_owned() - .unwrap(), // TODO - module: &shader_module_guard[pipeline_stage.module].raw, + entry: entry_point_name, // TODO + module: &shader_module.raw, specialization: hal::pso::Specialization::EMPTY, }; @@ -2575,3 +2634,27 @@ impl Global { buffer.map_state = resource::BufferMapState::Idle; } } + +/// Errors produced when validating the shader modules of a pipeline. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum ShaderValidationError { + /// Unable to find an entry point matching the specified execution model. + MissingEntryPoint(ExecutionModel), +} + +fn validate_shader( + module: &naga::Module, + entry_point_name: &str, + execution_model: ExecutionModel, +) -> Result<(), ShaderValidationError> { + // Since a shader module can have multiple entry points with the same name, + // we need to look for one with the right execution model. + let entry_point = module.entry_points.iter().find(|entry_point| { + entry_point.name == entry_point_name && entry_point.exec_model == execution_model + }); + + match entry_point { + Some(_) => Ok(()), + None => Err(ShaderValidationError::MissingEntryPoint(execution_model)), + } +} diff --git a/gfx/wgpu/wgpu-core/src/pipeline.rs b/gfx/wgpu/wgpu-core/src/pipeline.rs index 95340529c89d..0d3749998bca 100644 --- a/gfx/wgpu/wgpu-core/src/pipeline.rs +++ b/gfx/wgpu/wgpu-core/src/pipeline.rs @@ -40,6 +40,7 @@ pub struct ShaderModuleDescriptor { pub struct ShaderModule { pub(crate) raw: B::ShaderModule, pub(crate) device_id: Stored, + pub(crate) module: Option, } #[repr(C)] diff --git a/third_party/rust/naga/.cargo-checksum.json b/third_party/rust/naga/.cargo-checksum.json new file mode 100644 index 000000000000..f84548a4aaee --- /dev/null +++ b/third_party/rust/naga/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".monocodus":"2ed558753daedcd63659a41c82bcd4971f3dffd61c3bbbecbf6aaba433f00c1c",".travis.yml":"d91d0d75087934c2d0503a8c04439fea459a19182021bb0b699644d442f5b6fc","Cargo.toml":"fd51368f651a341628248c0aaafeb5d4d62eea359986dd7ba0e8a368dcacdf94","LICENSE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","Makefile":"51b23cb293d2409397342e53a8f610dfe6da10e8ece06df614fd6e6d88f6eabd","README.md":"747c69b3edb6fa813975a892922d3f99591667c3aa7da5b6d956e7876bb644f4","examples/convert.rs":"561fffdb3a5b145fb3fb873f59f310310ad0c377450da450a6b86a3bfce9238b","src/arena.rs":"a34c363da8fa308dc70d768e09b6acca22c2d73da0d6151b57122913260dbd37","src/back/mod.rs":"0950e0e938f906292b9eab10313421f2179a943aa2956511a0e2968b41663971","src/back/msl.rs":"65512e81bb33b5ce48ed75c71dee4cf3f48e67884c2b6c0a76d21d4e9bcd1c32","src/front/mod.rs":"2320b45153d52992d7104bd3b60499b589c517c6c69f87990e1c91b69bfb4db0","src/front/spirv.rs":"65e82a007bcd461ed07e975474bb4154c029a12d3aada7bb493751b7feeda2ae","src/front/wgsl.rs":"65fe687124a052359dcec5fbc95111a0bc0ef72e8e96d8c3f38fbe70120e4f60","src/lib.rs":"332ab628226bf602794c8470017ac7a3760fba30cbfd93f6dc617d86867764b5","src/proc/interface.rs":"9d43ee5785ea78e833c4b1ba707608b1c3f726b56d4f4a84fdf9195d022fab02","src/proc/mod.rs":"9bf971cb7e476a4b191a970093306e2a412ad1d6bb961cb690083960277a4684","src/proc/typifier.rs":"d9a99f066077f0650d421d96bbd601d222f659c242d2232bd0ef8af74e01d66f","test-data/boids.ron":"f6adc2d25fbb87694d6c4b38d248935402d93576db59236acb4836884ec80945","test-data/boids.wgsl":"a9616a05d35ecca002be0ec3e07ef092b95fda750a2f8d80b38195146edd0a0a","test-data/quad.wgsl":"9b159d06c543d676c2d055c19029d53b7f72ab66e7592d45b4fdd9ed34377e21","tests/convert.rs":"5407ad831e20ab637340119433ca1605568838668581fc90ee2d546818a24101"},"package":null} \ No newline at end of file diff --git a/third_party/rust/naga/.monocodus b/third_party/rust/naga/.monocodus new file mode 100644 index 000000000000..59d8a4711920 --- /dev/null +++ b/third_party/rust/naga/.monocodus @@ -0,0 +1,7 @@ +version: 1.0.0 + +rust: + formatter: + name: rustfmt + ignore_paths: + - ".*" diff --git a/third_party/rust/naga/.travis.yml b/third_party/rust/naga/.travis.yml new file mode 100644 index 000000000000..22761ba7ee19 --- /dev/null +++ b/third_party/rust/naga/.travis.yml @@ -0,0 +1 @@ +language: rust diff --git a/third_party/rust/naga/Cargo.toml b/third_party/rust/naga/Cargo.toml new file mode 100644 index 000000000000..fb5a16443925 --- /dev/null +++ b/third_party/rust/naga/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "naga" +version = "0.1.0" +authors = ["Dzmitry Malyshau "] +edition = "2018" +description = "Shader translation infrastructure" +homepage = "https://github.com/gfx-rs/naga" +repository = "https://github.com/gfx-rs/naga" +keywords = ["shader", "SPIR-V"] +license = "MPL-2.0" + +[dependencies] +bitflags = "1" +fxhash = "0.2" +log = "0.4" +num-traits = "0.2" +spirv = { package = "spirv_headers", version = "1" } + +[dev-dependencies] +env_logger = "0.6" +ron = "0.5" +serde = { version = "1", features = ["serde_derive"] } diff --git a/third_party/rust/naga/LICENSE b/third_party/rust/naga/LICENSE new file mode 100644 index 000000000000..261eeb9e9f8b --- /dev/null +++ b/third_party/rust/naga/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/rust/naga/Makefile b/third_party/rust/naga/Makefile new file mode 100644 index 000000000000..89a899515e7e --- /dev/null +++ b/third_party/rust/naga/Makefile @@ -0,0 +1,16 @@ +.PHONY: all clean +.SECONDARY: boids.metal quad.metal + +all: + +clean: + rm *.metal *.air *.metallib + +%.metal: test-data/%.wgsl $(wildcard src/*.rs src/**/*.rs examples/*.rs) + cargo run --example convert -- $< $@ + +%.air: %.metal + xcrun -sdk macosx metal -c $< -mmacosx-version-min=10.11 + +%.metallib: %.air + xcrun -sdk macosx metallib $< -o $@ diff --git a/third_party/rust/naga/README.md b/third_party/rust/naga/README.md new file mode 100644 index 000000000000..cd547c5d80dc --- /dev/null +++ b/third_party/rust/naga/README.md @@ -0,0 +1,29 @@ +# Naga + +[![Matrix](https://img.shields.io/badge/Matrix-%23naga%3Amatrix.org-blueviolet.svg)](https://matrix.to/#/#naga:matrix.org) +[![Crates.io](https://img.shields.io/crates/v/naga.svg?label=naga)](https://crates.io/crates/naga) +[![Docs.rs](https://docs.rs/naga/badge.svg)](https://docs.rs/naga) +[![Build Status](https://travis-ci.org/gfx-rs/naga.svg?branch=master)](https://travis-ci.org/gfx-rs/naga) + +This is an experimental shader translation library for the needs of gfx-rs project and WebGPU. It's meant to provide a safe and performant way of converting to and from SPIR-V. + +## Supported end-points + +Front-end | Status | Notes | +--------------- | ------------------ | ----- | +SPIR-V (binary) | :construction: | | +WGSL (Tint) | :construction: | | +GLSL (Vulkan) | | | +Rust | | | + +Back-end | Status | Notes | +--------------- | ------------------ | ----- | +SPIR-V (binary) | | | +WGSL | | | +Metal | :construction: | | +HLSL | | | +GLSL | | | +AIR | | | +DXIR | | | +DXIL | | | +DXBC | | | diff --git a/third_party/rust/naga/examples/convert.rs b/third_party/rust/naga/examples/convert.rs new file mode 100644 index 000000000000..c03e1d8fd1f4 --- /dev/null +++ b/third_party/rust/naga/examples/convert.rs @@ -0,0 +1,78 @@ +use serde::{Serialize, Deserialize}; +use std::{env, fs}; + +#[derive(Hash, PartialEq, Eq, Serialize, Deserialize)] +struct BindSource { + set: u32, + binding: u32, +} + +#[derive(Serialize, Deserialize)] +struct BindTarget { + buffer: Option, + texture: Option, + sampler: Option, + mutable: bool, +} + +#[derive(Default, Serialize, Deserialize)] +struct Parameters { + metal_bindings: naga::FastHashMap, +} + +fn main() { + env_logger::init(); + + let args = env::args().collect::>(); + + let module = if args.len() <= 1 { + println!("Call with "); + return + } else if args[1].ends_with(".spv") { + let input = fs::read(&args[1]).unwrap(); + naga::front::spirv::parse_u8_slice(&input).unwrap() + } else if args[1].ends_with(".wgsl") { + let input = fs::read_to_string(&args[1]).unwrap(); + naga::front::wgsl::parse_str(&input).unwrap() + } else { + panic!("Unknown input: {:?}", args[1]); + }; + + if args.len() <= 2 { + println!("{:#?}", module); + return; + } + + let param_path = std::path::PathBuf::from(&args[1]) + .with_extension("ron"); + let params = match fs::read_to_string(param_path) { + Ok(string) => ron::de::from_str(&string).unwrap(), + Err(_) => Parameters::default(), + }; + + if args[2].ends_with(".metal") { + use naga::back::msl; + let mut binding_map = msl::BindingMap::default(); + for (key, value) in params.metal_bindings { + binding_map.insert( + msl::BindSource { + set: key.set, + binding: key.binding, + }, + msl::BindTarget { + buffer: value.buffer, + texture: value.texture, + sampler: value.sampler, + mutable: value.mutable, + }, + ); + } + let options = msl::Options { + binding_map: &binding_map, + }; + let msl = msl::write_string(&module, options).unwrap(); + fs::write(&args[2], msl).unwrap(); + } else { + panic!("Unknown output: {:?}", args[2]); + } +} diff --git a/third_party/rust/naga/src/arena.rs b/third_party/rust/naga/src/arena.rs new file mode 100644 index 000000000000..c790ec553f65 --- /dev/null +++ b/third_party/rust/naga/src/arena.rs @@ -0,0 +1,168 @@ +use std::{fmt, hash, marker::PhantomData, num::NonZeroU32}; + +/// An unique index in the arena array that a handle points to. +/// +/// This type is independent of `spirv::Word`. `spirv::Word` is used in data +/// representation. It holds a SPIR-V and refers to that instruction. In +/// structured representation, we use Handle to refer to an SPIR-V instruction. +/// `Index` is an implementation detail to `Handle`. +type Index = NonZeroU32; + +/// A strongly typed reference to a SPIR-V element. +pub struct Handle { + index: Index, + marker: PhantomData, +} + +impl Clone for Handle { + fn clone(&self) -> Self { + Handle { + index: self.index, + marker: self.marker, + } + } +} +impl Copy for Handle {} +impl PartialEq for Handle { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +} +impl Eq for Handle {} +impl fmt::Debug for Handle { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Handle({})", self.index) + } +} +impl hash::Hash for Handle { + fn hash(&self, hasher: &mut H) { + self.index.hash(hasher) + } +} + +impl Handle { + #[cfg(test)] + pub const DUMMY: Self = Handle { + index: unsafe { NonZeroU32::new_unchecked(!0) }, + marker: PhantomData, + }; + + pub(crate) fn new(index: Index) -> Self { + Handle { + index, + marker: PhantomData, + } + } + + /// Returns the zero-based index of this handle. + pub fn index(self) -> usize { + let index = self.index.get() - 1; + index as usize + } +} + +/// An arena holding some kind of component (e.g., type, constant, +/// instruction, etc.) that can be referenced. +#[derive(Debug)] +pub struct Arena { + /// Values of this arena. + data: Vec, +} + +impl Default for Arena { + fn default() -> Self { + Self::new() + } +} + +impl Arena { + pub fn new() -> Self { + Arena { data: Vec::new() } + } + + pub fn len(&self) -> usize { + self.data.len() + } + + pub fn iter(&self) -> impl Iterator, &T)> { + self.data.iter().enumerate().map(|(i, v)| { + let position = i + 1; + let index = unsafe { Index::new_unchecked(position as u32) }; + (Handle::new(index), v) + }) + } + + /// Adds a new value to the arena, returning a typed handle. + /// + /// The value is not linked to any SPIR-V module. + pub fn append(&mut self, value: T) -> Handle { + let position = self.data.len() + 1; + let index = unsafe { Index::new_unchecked(position as u32) }; + self.data.push(value); + Handle::new(index) + } + + /// Adds a value with a check for uniqueness: returns a handle pointing to + /// an existing element if its value matches the given one, or adds a new + /// element otherwise. + pub fn fetch_or_append(&mut self, value: T) -> Handle + where + T: PartialEq, + { + if let Some(index) = self.data.iter().position(|d| d == &value) { + let index = unsafe { Index::new_unchecked((index + 1) as u32) }; + Handle::new(index) + } else { + self.append(value) + } + } +} + +impl std::ops::Index> for Arena { + type Output = T; + fn index(&self, handle: Handle) -> &T { + let index = handle.index.get() - 1; + &self.data[index as usize] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn append_non_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.append(0); + let t2 = arena.append(0); + assert!(t1 != t2); + assert!(arena[t1] == arena[t2]); + } + + #[test] + fn append_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.append(0); + let t2 = arena.append(1); + assert!(t1 != t2); + assert!(arena[t1] != arena[t2]); + } + + #[test] + fn fetch_or_append_non_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.fetch_or_append(0); + let t2 = arena.fetch_or_append(0); + assert!(t1 == t2); + assert!(arena[t1] == arena[t2]) + } + + #[test] + fn fetch_or_append_unique() { + let mut arena: Arena = Arena::new(); + let t1 = arena.fetch_or_append(0); + let t2 = arena.fetch_or_append(1); + assert!(t1 != t2); + assert!(arena[t1] != arena[t2]); + } +} diff --git a/third_party/rust/naga/src/back/mod.rs b/third_party/rust/naga/src/back/mod.rs new file mode 100644 index 000000000000..f4f1fce17b5e --- /dev/null +++ b/third_party/rust/naga/src/back/mod.rs @@ -0,0 +1 @@ +pub mod msl; \ No newline at end of file diff --git a/third_party/rust/naga/src/back/msl.rs b/third_party/rust/naga/src/back/msl.rs new file mode 100644 index 000000000000..89beb6e6808f --- /dev/null +++ b/third_party/rust/naga/src/back/msl.rs @@ -0,0 +1,976 @@ +/*! Metal Shading Language (MSL) backend + +## Binding model + +Metal's bindings are flat per resource. Since there isn't an obvious mapping +from SPIR-V's descriptor sets, we require a separate mapping provided in the options. +This mapping may have one or more resource end points for each descriptor set + index +pair. + +## Outputs + +In Metal, built-in shader outputs can not be nested into structures within +the output struct. If there is a structure in the outputs, and it contains any built-ins, +we move them up to the root output structure that we define ourselves. +!*/ + +use std::{ + fmt::{ + Display, Error as FmtError, Formatter, Write, + }, +}; + +use crate::{ + arena::Handle, + FastHashMap, +}; + +/// Expect all the global variables to have a pointer type, +/// like in SPIR-V. +const GLOBAL_POINTERS: bool = false; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct BindTarget { + pub buffer: Option, + pub texture: Option, + pub sampler: Option, + pub mutable: bool, +} + +#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +pub struct BindSource { + pub set: spirv::Word, + pub binding: spirv::Word, +} + +pub type BindingMap = FastHashMap; + +enum ResolvedBinding { + BuiltIn(spirv::BuiltIn), + Attribute(spirv::Word), + Color(spirv::Word), + User { prefix: &'static str, index: spirv::Word }, + Resource(BindTarget), +} + +struct Level(usize); +impl Level { + fn next(&self) -> Self { + Level(self.0 + 1) + } +} +impl Display for Level { + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), FmtError> { + (0 .. self.0).map(|_| formatter.write_str("\t")).collect() + } +} + +#[derive(Debug)] +pub enum Error { + Format(FmtError), + UnsupportedExecutionModel(spirv::ExecutionModel), + UnexpectedLocation, + MixedExecutionModels(crate::Handle), + MissingBinding(crate::Handle), + MissingBindTarget(BindSource), + InvalidImageFlags(crate::ImageFlags), + MutabilityViolation(crate::Handle), + BadName(String), +} + +impl From for Error { + fn from(e: FmtError) -> Self { + Error::Format(e) + } +} + +#[derive(Clone, Copy, Debug)] +enum LocationMode { + VertexInput, + FragmentOutput, + Intermediate, + Uniform, +} + +#[derive(Debug, Clone, Copy)] +pub struct Options<'a> { + pub binding_map: &'a BindingMap, +} + +impl Options<'_> { + fn resolve_binding(&self, binding: &crate::Binding, mode: LocationMode) -> Result { + match *binding { + crate::Binding::BuiltIn(built_in) => Ok(ResolvedBinding::BuiltIn(built_in)), + crate::Binding::Location(index) => match mode { + LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(index)), + LocationMode::FragmentOutput => Ok(ResolvedBinding::Color(index)), + LocationMode::Intermediate => Ok(ResolvedBinding::User { + prefix: "loc", + index, + }), + LocationMode::Uniform => Err(Error::UnexpectedLocation), + }, + crate::Binding::Descriptor { set, binding } => { + let source = BindSource { set, binding }; + self.binding_map + .get(&source) + .cloned() + .map(ResolvedBinding::Resource) + .ok_or(Error::MissingBindTarget(source)) + + } + } + } +} + + +trait Indexed { + const CLASS: &'static str; + const PREFIX: bool = false; + fn id(&self) -> usize; +} + +impl Indexed for crate::Handle { + const CLASS: &'static str = "Type"; + fn id(&self) -> usize { self.index() } +} +impl Indexed for crate::Handle { + const CLASS: &'static str = "global"; + fn id(&self) -> usize { self.index() } +} +impl Indexed for crate::Handle { + const CLASS: &'static str = "local"; + fn id(&self) -> usize { self.index() } +} +impl Indexed for crate::Handle { + const CLASS: &'static str = "function"; + fn id(&self) -> usize { self.index() } +} + +struct MemberIndex(usize); +impl Indexed for MemberIndex { + const CLASS: &'static str = "field"; + fn id(&self) -> usize { self.0 } +} +struct ParameterIndex(usize); +impl Indexed for ParameterIndex { + const CLASS: &'static str = "param"; + fn id(&self) -> usize { self.0 } +} +struct InputStructIndex(crate::Handle); +impl Indexed for InputStructIndex { + const CLASS: &'static str = "Input"; + const PREFIX: bool = true; + fn id(&self) -> usize { self.0.index() } +} +struct OutputStructIndex(crate::Handle); +impl Indexed for OutputStructIndex { + const CLASS: &'static str = "Output"; + const PREFIX: bool = true; + fn id(&self) -> usize { self.0.index() } +} + +enum NameSource<'a> { + Custom { name: &'a str, prefix: bool }, + Index(usize), +} + +const RESERVED_NAMES: &[&str] = &[ + "main", +]; + +struct Name<'a> { + class: &'static str, + source: NameSource<'a>, +} +impl Display for Name<'_> { + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), FmtError> { + match self.source { + NameSource::Custom { name, prefix: false } if RESERVED_NAMES.contains(&name) => { + write!(formatter, "{}_", name) + } + NameSource::Custom { name, prefix: false } => formatter.write_str(name), + NameSource::Custom { name, prefix: true } => { + let (head, tail) = name.split_at(1); + write!(formatter, "{}{}{}", self.class, head.to_uppercase(), tail) + } + NameSource::Index(index) => write!(formatter, "{}{}", self.class, index), + } + } +} +impl From for Name<'_> { + fn from(index: I) -> Self { + Name { + class: I::CLASS, + source: NameSource::Index(index.id()), + } + } +} + +trait AsName { + fn or_index(&self, index: I) -> Name; +} +impl AsName for Option { + fn or_index(&self, index: I) -> Name { + Name { + class: I::CLASS, + source: match *self { + Some(ref name) if !name.is_empty() => NameSource::Custom { name, prefix: I::PREFIX }, + _ => NameSource::Index(index.id()), + }, + } + } +} + +struct TypedGlobalVariable<'a> { + module: &'a crate::Module, + handle: crate::Handle, + usage: crate::GlobalUse, +} +impl Display for TypedGlobalVariable<'_> { + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), FmtError> { + let var = &self.module.global_variables[self.handle]; + let name = var.name.or_index(self.handle); + let (space_qualifier, reference) = match var.class { + spirv::StorageClass::Uniform | + spirv::StorageClass::UniformConstant | + spirv::StorageClass::StorageBuffer => { + let space = if self.usage.contains(crate::GlobalUse::STORE) { + "device " + } else { + "constant " + }; + (space, "&") + } + _ => ("", "") + }; + if GLOBAL_POINTERS { + let ty = &self.module.types[var.ty]; + match ty.inner { + crate::TypeInner::Pointer { base, class } => { + let ty_handle = match class { + spirv::StorageClass::Input | + spirv::StorageClass::Output | + spirv::StorageClass::Uniform | + spirv::StorageClass::UniformConstant => base, + _ => var.ty + }; + let ty_name = self.module.types[ty_handle].name.or_index(ty_handle); + write!(formatter, "{} {}", ty_name, name) + } + _ => panic!("Unexpected global type {:?} = {:?}", var.ty, ty), + } + } else { + let ty_name = self.module.types[var.ty].name.or_index(var.ty); + write!(formatter, "{}{}{} {}", space_qualifier, ty_name, reference, name) + } + } +} + +impl Display for ResolvedBinding { + fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), FmtError> { + match *self { + ResolvedBinding::BuiltIn(built_in) => { + let name = match built_in { + spirv::BuiltIn::ClipDistance => "clip_distance", + spirv::BuiltIn::GlobalInvocationId => "thread_position_in_grid", + spirv::BuiltIn::PointSize => "point_size", + spirv::BuiltIn::Position => "position", + _ => panic!("Built in {:?} is not implemented", built_in), + }; + formatter.write_str(name) + } + ResolvedBinding::Attribute(index) => { + write!(formatter, "attribute({})", index) + } + ResolvedBinding::Color(index) => { + write!(formatter, "color({})", index) + } + ResolvedBinding::User { prefix, index } => { + write!(formatter, "user({}{})", prefix, index) + } + ResolvedBinding::Resource(ref target) => { + if let Some(id) = target.buffer { + write!(formatter, "buffer({})", id) + } else if let Some(id) = target.texture { + write!(formatter, "texture({})", id) + } else if let Some(id) = target.sampler { + write!(formatter, "sampler({})", id) + } else { + unimplemented!() + } + } + } + } +} + +pub struct Writer { + out: W, +} + +fn scalar_kind_string(kind: crate::ScalarKind) -> &'static str { + match kind { + crate::ScalarKind::Float => "float", + crate::ScalarKind::Sint => "int", + crate::ScalarKind::Uint => "uint", + crate::ScalarKind::Bool => "bool", + } +} + +fn vector_size_string(size: crate::VectorSize) -> &'static str { + match size { + crate::VectorSize::Bi => "2", + crate::VectorSize::Tri => "3", + crate::VectorSize::Quad => "4", + } +} + +const OUTPUT_STRUCT_NAME: &str = "output"; +const LOCATION_INPUT_STRUCT_NAME: &str = "input"; +const COMPONENTS: &[char] = &['x', 'y', 'z', 'w']; + +fn separate(is_last: bool) -> &'static str { + if is_last { "" } else { "," } +} + +#[derive(Debug)] +enum MaybeOwned<'a, T: 'a> { + Borrowed(&'a T), + Owned(T), +} + +impl MaybeOwned<'_, T> { + fn borrow(&self) -> &T { + match *self { + MaybeOwned::Borrowed(inner) => inner, + MaybeOwned::Owned(ref inner) => inner, + } + } +} + +impl crate::Module { + fn borrow_type(&self, handle: Handle) -> MaybeOwned { + MaybeOwned::Borrowed(&self.types[handle].inner) + } +} + +impl Writer { + fn put_expression<'a>( + &mut self, + expr_handle: Handle, + function: &crate::Function, + module: &'a crate::Module, + ) -> Result, Error> { + let expression = &function.expressions[expr_handle]; + log::trace!("expression {:?} = {:?}", expr_handle, expression); + match *expression { + crate::Expression::Access { base, index } => { + match *self.put_expression(base, function, module)?.borrow() { + crate::TypeInner::Array { base, .. } => { + //TODO: add size check + self.out.write_str("[")?; + self.put_expression(index, function, module)?; + self.out.write_str("]")?; + Ok(module.borrow_type(base)) + } + ref other => panic!("Unexpected indexing of {:?}", other), + } + } + crate::Expression::AccessIndex { base, index } => { + match *self.put_expression(base, function, module)?.borrow() { + crate::TypeInner::Struct { ref members } => { + let member = &members[index as usize]; + let name = member.name.or_index(MemberIndex(index as usize)); + write!(self.out, ".{}", name)?; + Ok(module.borrow_type(member.ty)) + } + crate::TypeInner::Matrix { rows, kind, width, .. } => { + write!(self.out, ".{}", COMPONENTS[index as usize])?; + Ok(MaybeOwned::Owned(crate::TypeInner::Vector { size: rows, kind, width })) + } + crate::TypeInner::Vector { kind, width, .. } => { + write!(self.out, ".{}", COMPONENTS[index as usize])?; + Ok(MaybeOwned::Owned(crate::TypeInner::Scalar { kind, width })) + } + crate::TypeInner::Array { base, size } => { + if let crate::ArraySize::Static(length) = size { + assert!(index < length); + } + write!(self.out, "[{}]", index)?; + Ok(module.borrow_type(base)) + } + ref other => panic!("Unexpected indexing of {:?}", other), + } + } + crate::Expression::Constant(handle) => { + self.put_constant(handle, module) + } + crate::Expression::Compose { ty, ref components } => { + let inner = &module.types[ty].inner; + match *inner { + crate::TypeInner::Vector { size, kind, .. } => { + write!(self.out, "{}{}(", scalar_kind_string(kind), vector_size_string(size))?; + for (i, &handle) in components.iter().enumerate() { + if i != 0 { + write!(self.out, ",")?; + } + self.put_expression(handle, function, module)?; + } + write!(self.out, ")")?; + } + _ => panic!("Unsupported compose {:?}", ty), + } + Ok(MaybeOwned::Borrowed(inner)) + } + crate::Expression::GlobalVariable(handle) => { + let var = &module.global_variables[handle]; + let inner = &module.types[var.ty].inner; + match var.class { + spirv::StorageClass::Output => { + if GLOBAL_POINTERS { + if let crate::TypeInner::Pointer { base, .. } = *inner { + let base_inner = &module.types[base].inner; + if let crate::TypeInner::Struct { .. } = *base_inner { + return Ok(MaybeOwned::Borrowed(base_inner)); + } + } + } else { + if let crate::TypeInner::Struct { .. } = *inner { + return Ok(MaybeOwned::Borrowed(inner)); + } + } + write!(self.out, "{}.", OUTPUT_STRUCT_NAME)?; + } + spirv::StorageClass::Input => { + if let Some(crate::Binding::Location(_)) = var.binding { + write!(self.out, "{}.", LOCATION_INPUT_STRUCT_NAME)?; + } + } + _ => {} + } + let name = var.name.or_index(handle); + write!(self.out, "{}", name)?; + Ok(MaybeOwned::Borrowed(inner)) + } + crate::Expression::LocalVariable(handle) => { + let var = &function.local_variables[handle]; + let inner = &module.types[var.ty].inner; + let name = var.name.or_index(handle); + write!(self.out, "{}", name)?; + Ok(MaybeOwned::Borrowed(inner)) + } + crate::Expression::Load { pointer } => { + //write!(self.out, "*")?; + match *self.put_expression(pointer, function, module)?.borrow() { + crate::TypeInner::Pointer { base, .. } => { + Ok(module.borrow_type(base)) + } + ref other => panic!("Unexpected load pointer {:?}", other), + } + } + crate::Expression::Unary { op, expr } => { + let op_str = match op { + crate::UnaryOperator::Negate => "-", + crate::UnaryOperator::Not => "!", + }; + write!(self.out, "{}", op_str)?; + self.put_expression(expr, function, module) + } + crate::Expression::Binary { op, left, right } => { + let op_str = match op { + crate::BinaryOperator::Add => "+", + crate::BinaryOperator::Subtract => "-", + crate::BinaryOperator::Multiply => "*", + crate::BinaryOperator::Divide => "/", + crate::BinaryOperator::Modulo => "%", + crate::BinaryOperator::Equal => "==", + crate::BinaryOperator::NotEqual => "!=", + crate::BinaryOperator::Less => "<", + crate::BinaryOperator::LessEqual => "<=", + crate::BinaryOperator::Greater => "==", + crate::BinaryOperator::GreaterEqual => ">=", + _ => panic!("Unsupported binary op {:?}", op), + }; + //write!(self.out, "(")?; + let ty_left = self.put_expression(left, function, module)?; + write!(self.out, " {} ", op_str)?; + let ty_right = self.put_expression(right, function, module)?; + //write!(self.out, ")")?; + + Ok(if op_str.len() == 1 { + match (ty_left.borrow(), ty_right.borrow()) { + (&crate::TypeInner::Scalar { kind, width }, &crate::TypeInner::Scalar { .. }) => + MaybeOwned::Owned(crate::TypeInner::Scalar { kind, width }), + (&crate::TypeInner::Scalar { .. }, &crate::TypeInner::Vector { size, kind, width }) | + (&crate::TypeInner::Vector { size, kind, width }, &crate::TypeInner::Scalar { .. }) | + (&crate::TypeInner::Vector { size, kind, width }, &crate::TypeInner::Vector { .. }) => + MaybeOwned::Owned(crate::TypeInner::Vector { size, kind, width }), + other => panic!("Unable to infer {:?} for {:?}", op, other), + } + } else { + MaybeOwned::Owned(crate::TypeInner::Scalar { kind: crate::ScalarKind::Bool, width: 1 }) + }) + } + crate::Expression::ImageSample { image, sampler, coordinate } => { + let ty_image = self.put_expression(image, function, module)?; + write!(self.out, ".sample(")?; + self.put_expression(sampler, function, module)?; + write!(self.out, ", ")?; + self.put_expression(coordinate, function, module)?; + write!(self.out, ")")?; + match *ty_image.borrow() { + crate::TypeInner::Image { base, .. } => Ok(module.borrow_type(base)), + ref other => panic!("Unexpected image type {:?}", other), + } + } + crate::Expression::Call { ref name, ref arguments } => { + match name.as_str() { + "cos" | + "normalize" | + "sin" => { + write!(self.out, "{}(", name)?; + let result = self.put_expression(arguments[0], function, module)?; + write!(self.out, ")")?; + Ok(result) + } + "fclamp" => { + write!(self.out, "clamp(")?; + let result = self.put_expression(arguments[0], function, module)?; + write!(self.out, ", ")?; + self.put_expression(arguments[1], function, module)?; + write!(self.out, ", ")?; + self.put_expression(arguments[2], function, module)?; + write!(self.out, ")")?; + Ok(result) + } + "atan2" => { + write!(self.out, "{}(", name)?; + let result = self.put_expression(arguments[0], function, module)?; + write!(self.out, ", ")?; + self.put_expression(arguments[1], function, module)?; + write!(self.out, ")")?; + Ok(result) + } + "distance" => { + write!(self.out, "distance(")?; + let result = match *self.put_expression(arguments[0], function, module)?.borrow() { + crate::TypeInner::Vector { kind, width, .. } => crate::TypeInner::Scalar { kind, width }, + ref other => panic!("Unexpected distance argument {:?}", other), + }; + write!(self.out, ", ")?; + self.put_expression(arguments[1], function, module)?; + write!(self.out, ")")?; + Ok(MaybeOwned::Owned(result)) + } + "length" => { + write!(self.out, "length(")?; + let result = match *self.put_expression(arguments[0], function, module)?.borrow() { + crate::TypeInner::Vector { kind, width, .. } => crate::TypeInner::Scalar { kind, width }, + ref other => panic!("Unexpected distance argument {:?}", other), + }; + write!(self.out, ")")?; + Ok(MaybeOwned::Owned(result)) + } + + _ => panic!("Unsupported call to '{}'", name), + } + } + ref other => panic!("Unsupported {:?}", other), + } + } + + fn put_constant<'a>( + &mut self, + handle: Handle, + module: &'a crate::Module, + ) -> Result, Error> { + let constant = &module.constants[handle]; + let ty = &module.types[constant.ty]; + + match constant.inner { + crate::ConstantInner::Sint(value) => { + write!(self.out, "{}", value)?; + } + crate::ConstantInner::Uint(value) => { + write!(self.out, "{}", value)?; + } + crate::ConstantInner::Float(value) => { + write!(self.out, "{}", value)?; + if value.fract() == 0.0 { + self.out.write_str(".0")?; + } + } + crate::ConstantInner::Bool(value) => { + write!(self.out, "{}", value)?; + } + crate::ConstantInner::Composite(ref constituents) => { + let ty_name = ty.name.or_index(constant.ty); + write!(self.out, "{}(", ty_name)?; + for (i, handle) in constituents.iter().enumerate() { + if i != 0 { + write!(self.out, ", ")?; + } + self.put_constant(*handle, module)?; + } + write!(self.out, ")")?; + } + } + + Ok(MaybeOwned::Borrowed(&ty.inner)) + } + + fn put_statement<'a>( + &mut self, + level: Level, + statement: &crate::Statement, + function: &crate::Function, + has_output: bool, + module: &'a crate::Module, + ) -> Result<(), Error> { + log::trace!("statement[{}] {:?}", level.0, statement); + match *statement { + crate::Statement::Empty => {} + crate::Statement::If { condition, ref accept, ref reject } => { + write!(self.out, "{}if (", level)?; + self.put_expression(condition, function, module)?; + writeln!(self.out, ") {{")?; + for s in accept { + self.put_statement(level.next(), s, function, has_output, module)?; + } + if !reject.is_empty() { + writeln!(self.out, "{}}} else {{", level)?; + for s in reject { + self.put_statement(level.next(), s, function, has_output, module)?; + } + } + writeln!(self.out, "{}}}", level)?; + } + crate::Statement::Loop { ref body, ref continuing } => { + writeln!(self.out, "{}while(true) {{", level)?; + for s in body { + self.put_statement(level.next(), s, function, has_output, module)?; + } + if !continuing.is_empty() { + //TODO + } + writeln!(self.out, "{}}}", level)?; + } + crate::Statement::Store { pointer, value } => { + //write!(self.out, "\t*")?; + write!(self.out, "{}", level)?; + self.put_expression(pointer, function, module)?; + write!(self.out, " = ")?; + self.put_expression(value, function, module)?; + writeln!(self.out, ";")?; + } + crate::Statement::Break => { + writeln!(self.out, "{}break;", level)?; + } + crate::Statement::Continue => { + writeln!(self.out, "{}continue;", level)?; + } + crate::Statement::Return { value } => { + write!(self.out, "{}return ", level)?; + match value { + None if has_output => self.out.write_str(OUTPUT_STRUCT_NAME)?, + None => {} + Some(expr_handle) if has_output => { + panic!("Unable to return value {:?} from an entry point!", expr_handle) + } + Some(expr_handle) => { + self.put_expression(expr_handle, function, module)?; + } + } + writeln!(self.out, ";")?; + } + _ => panic!("Unsupported {:?}", statement), + }; + Ok(()) + } + + pub fn write(&mut self, module: &crate::Module, options: Options) -> Result<(), Error> { + writeln!(self.out, "#include ")?; + writeln!(self.out, "#include ")?; + writeln!(self.out, "using namespace metal;")?; + + writeln!(self.out)?; + self.write_type_defs(module, options)?; + + writeln!(self.out)?; + self.write_functions(module, options)?; + + Ok(()) + } + + fn write_type_defs(&mut self, module: &crate::Module, options: Options) -> Result<(), Error> { + for (handle, ty) in module.types.iter() { + let name = ty.name.or_index(handle); + match ty.inner { + crate::TypeInner::Scalar { kind, .. } => { + write!(self.out, "typedef {} {}", scalar_kind_string(kind), name)?; + }, + crate::TypeInner::Vector { size, kind, .. } => { + write!(self.out, "typedef {}{} {}", scalar_kind_string(kind), vector_size_string(size), name)?; + }, + crate::TypeInner::Matrix { columns, rows, kind, .. } => { + write!(self.out, "typedef {}{}x{} {}", scalar_kind_string(kind), vector_size_string(columns), vector_size_string(rows), name)?; + } + crate::TypeInner::Pointer { base, class } => { + let base_name = module.types[base].name.or_index(base); + let class_name = match class { + spirv::StorageClass::Input | + spirv::StorageClass::Output => continue, + spirv::StorageClass::Uniform | + spirv::StorageClass::UniformConstant => "constant", + other => { + log::warn!("Unexpected pointer class {:?}", other); + "" + } + }; + write!(self.out, "typedef {} {} *{}", class_name, base_name, name)?; + } + crate::TypeInner::Array { base, size } => { + let base_name = module.types[base].name.or_index(base); + let resolved_size = match size { + crate::ArraySize::Static(length) => length, + crate::ArraySize::Dynamic => 1, + }; + write!(self.out, "typedef {} {}[{}]", base_name, name, resolved_size)?; + } + crate::TypeInner::Struct { ref members } => { + writeln!(self.out, "struct {} {{", name)?; + for (index, member) in members.iter().enumerate() { + let name = member.name.or_index(MemberIndex(index)); + let base_name = module.types[member.ty].name.or_index(member.ty); + write!(self.out, "\t{} {}", base_name, name)?; + if let Some(ref binding) = member.binding { + let resolved = options.resolve_binding(binding, LocationMode::Intermediate)?; + write!(self.out, " [[{}]]", resolved)?; + } + writeln!(self.out, ";")?; + } + write!(self.out, "}}")?; + } + crate::TypeInner::Image { base, dim, flags } => { + let base_name = module.types[base].name.or_index(base); + let dim = match dim { + spirv::Dim::Dim1D => "1d", + spirv::Dim::Dim2D => "2d", + spirv::Dim::Dim3D => "3d", + spirv::Dim::DimCube => "Cube", + _ => panic!("Unsupported dim {:?}", dim), + }; + let access = if flags.contains(crate::ImageFlags::SAMPLED) { + if flags.intersects(crate::ImageFlags::CAN_STORE) { + return Err(Error::InvalidImageFlags(flags)); + } + "sample" + } else if flags.contains(crate::ImageFlags::CAN_LOAD | crate::ImageFlags::CAN_STORE) { + "read_write" + } else if flags.contains(crate::ImageFlags::CAN_STORE) { + "write" + } else if flags.contains(crate::ImageFlags::CAN_LOAD) { + "read" + } else { + return Err(Error::InvalidImageFlags(flags)); + }; + write!(self.out, "typedef texture{}<{}, access::{}> {}", dim, base_name, access, name)?; + } + crate::TypeInner::Sampler => { + write!(self.out, "typedef sampler {}", name)?; + } + } + writeln!(self.out, ";")?; + } + Ok(()) + } + + fn write_functions(&mut self, module: &crate::Module, options: Options) -> Result<(), Error> { + for (fun_handle, fun) in module.functions.iter() { + let fun_name = fun.name.or_index(fun_handle); + // find the entry point(s) and inputs/outputs + let mut exec_model = None; + let mut last_used_global = None; + for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) { + match var.class { + spirv::StorageClass::Input => { + if let Some(crate::Binding::Location(_)) = var.binding { + continue + } + } + spirv::StorageClass::Output => continue, + _ => {} + } + if !usage.is_empty() { + last_used_global = Some(handle); + } + } + for ep in module.entry_points.iter() { + if ep.function == fun_handle { + if exec_model.is_some() { + if exec_model != Some(ep.exec_model) { + return Err(Error::MixedExecutionModels(fun_handle)); + } + } else { + exec_model = Some(ep.exec_model); + } + } + } + let output_name = fun.name.or_index(OutputStructIndex(fun_handle)); + + // make dedicated input/output structs + if let Some(em) = exec_model { + assert_eq!(fun.return_type, None); + let (em_str, in_mode, out_mode) = match em { + spirv::ExecutionModel::Vertex => ("vertex", LocationMode::VertexInput, LocationMode::Intermediate), + spirv::ExecutionModel::Fragment => ("fragment", LocationMode::Intermediate, LocationMode::FragmentOutput), + spirv::ExecutionModel::GLCompute => ("kernel", LocationMode::Uniform, LocationMode::Uniform), + _ => return Err(Error::UnsupportedExecutionModel(em)), + }; + let location_input_name = fun.name.or_index(InputStructIndex(fun_handle)); + + if em != spirv::ExecutionModel::GLCompute { + writeln!(self.out, "struct {} {{", location_input_name)?; + for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) { + if var.class != spirv::StorageClass::Input || !usage.contains(crate::GlobalUse::LOAD) { + continue + } + // if it's a struct, lift all the built-in contents up to the root + let mut ty_handle = var.ty; + if GLOBAL_POINTERS { + if let crate::TypeInner::Pointer { base, .. } = module.types[var.ty].inner { + ty_handle = base; + } + } + if let crate::TypeInner::Struct { ref members } = module.types[ty_handle].inner { + for (index, member) in members.iter().enumerate() { + if let Some(ref binding@crate::Binding::Location(_)) = member.binding { + let name = member.name.or_index(MemberIndex(index)); + let ty_name = module.types[member.ty].name.or_index(member.ty); + let resolved = options.resolve_binding(binding, in_mode)?; + writeln!(self.out, "\t{} {} [[{}]];", ty_name, name, resolved)?; + } + } + } else { + if let Some(ref binding@crate::Binding::Location(_)) = var.binding { + let tyvar = TypedGlobalVariable { module, handle, usage: crate::GlobalUse::empty() }; + let resolved = options.resolve_binding(binding, in_mode)?; + writeln!(self.out, "\t{} [[{}]];", tyvar, resolved)?; + } + } + } + writeln!(self.out, "}};")?; + writeln!(self.out, "struct {} {{", output_name)?; + for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) { + if var.class != spirv::StorageClass::Output || !usage.contains(crate::GlobalUse::STORE) { + continue + } + // if it's a struct, lift all the built-in contents up to the root + let mut ty_handle = var.ty; + if GLOBAL_POINTERS { + if let crate::TypeInner::Pointer { base, .. } = module.types[var.ty].inner { + ty_handle = base; + } + } + if let crate::TypeInner::Struct { ref members } = module.types[ty_handle].inner { + for (index, member) in members.iter().enumerate() { + let name = member.name.or_index(MemberIndex(index)); + let ty_name = module.types[member.ty].name.or_index(member.ty); + let binding = member.binding + .as_ref() + .ok_or(Error::MissingBinding(handle))?; + let resolved = options.resolve_binding(binding, out_mode)?; + writeln!(self.out, "\t{} {} [[{}]];", ty_name, name, resolved)?; + } + } else { + let tyvar = TypedGlobalVariable { module, handle, usage: crate::GlobalUse::empty() }; + write!(self.out, "\t{}", tyvar)?; + if let Some(ref binding) = var.binding { + let resolved = options.resolve_binding(binding, out_mode)?; + write!(self.out, " [[{}]]", resolved)?; + } + writeln!(self.out, ";")?; + } + } + writeln!(self.out, "}};")?; + writeln!(self.out, "{} {} {}(", em_str, output_name, fun_name)?; + let separator = separate(last_used_global.is_none()); + writeln!(self.out, "\t{} {} [[stage_in]]{}", + location_input_name, LOCATION_INPUT_STRUCT_NAME, separator)?; + } else { + writeln!(self.out, "{} void {}(", em_str, fun_name)?; + } + + for ((handle, var), &usage) in module.global_variables.iter().zip(&fun.global_usage) { + if usage.is_empty() || var.class == spirv::StorageClass::Output { + continue + } + if var.class == spirv::StorageClass::Input { + if let Some(crate::Binding::Location(_)) = var.binding { + // location inputs are put into a separate struct + continue + } + } + let loc_mode = match (em, var.class) { + (spirv::ExecutionModel::Vertex, spirv::StorageClass::Input) => LocationMode::VertexInput, + (spirv::ExecutionModel::Vertex, spirv::StorageClass::Output) | + (spirv::ExecutionModel::Fragment, spirv::StorageClass::Input) => LocationMode::Intermediate, + (spirv::ExecutionModel::Fragment, spirv::StorageClass::Output) => LocationMode::FragmentOutput, + _ => LocationMode::Uniform, + }; + let resolved = options.resolve_binding(var.binding.as_ref().unwrap(), loc_mode)?; + let tyvar = TypedGlobalVariable { module, handle, usage }; + let separator = separate(last_used_global == Some(handle)); + writeln!(self.out, "\t{} [[{}]]{}", tyvar, resolved, separator)?; + } + } else { + let result_type_name = match fun.return_type { + Some(type_id) => module.types[type_id].name.or_index(type_id), + None => Name { + class: "", + source: NameSource::Custom { name: "void", prefix: false }, + }, + }; + writeln!(self.out, "{} {}(", result_type_name, fun_name)?; + for (index, &ty) in fun.parameter_types.iter().enumerate() { + let name = Name::from(ParameterIndex(index)); + let member_type_name = module.types[ty].name.or_index(ty); + let separator = separate(index + 1 == fun.parameter_types.len() && last_used_global.is_none()); + writeln!(self.out, "\t{} {}{}", member_type_name, name, separator)?; + } + } + writeln!(self.out, ") {{")?; + + // write down function body + let has_output = match exec_model { + Some(spirv::ExecutionModel::Vertex) | + Some(spirv::ExecutionModel::Fragment) => { + writeln!(self.out, "\t{} {};", output_name, OUTPUT_STRUCT_NAME)?; + true + } + _ => false + }; + for (local_handle, local) in fun.local_variables.iter() { + let ty_name = module.types[local.ty].name.or_index(local.ty); + write!(self.out, "\t{} {}", ty_name, local.name.or_index(local_handle))?; + if let Some(value) = local.init { + write!(self.out, " = ")?; + self.put_expression(value, fun, module)?; + } + writeln!(self.out, ";")?; + } + for statement in fun.body.iter() { + self.put_statement(Level(1), statement, fun, has_output, module)?; + } + writeln!(self.out, "}}")?; + } + + Ok(()) + } +} + +pub fn write_string(module: &crate::Module, options: Options) -> Result { + let mut w = Writer { out: String::new() }; + w.write(module, options)?; + Ok(w.out) +} diff --git a/third_party/rust/naga/src/front/mod.rs b/third_party/rust/naga/src/front/mod.rs new file mode 100644 index 000000000000..36c1b701e39f --- /dev/null +++ b/third_party/rust/naga/src/front/mod.rs @@ -0,0 +1,26 @@ +pub mod spirv; +pub mod wgsl; + +use crate::arena::Arena; + +pub const GENERATOR: u32 = 0; + +impl crate::Module { + fn from_header(header: crate::Header) -> Self { + crate::Module { + header, + types: Arena::new(), + constants: Arena::new(), + global_variables: Arena::new(), + functions: Arena::new(), + entry_points: Vec::new(), + } + } + + fn generate_empty() -> Self { + Self::from_header(crate::Header { + version: (1, 0, 0), + generator: GENERATOR, + }) + } +} diff --git a/third_party/rust/naga/src/front/spirv.rs b/third_party/rust/naga/src/front/spirv.rs new file mode 100644 index 000000000000..3afcb39bf3e6 --- /dev/null +++ b/third_party/rust/naga/src/front/spirv.rs @@ -0,0 +1,1515 @@ +/*! SPIR-V frontend + +## ID lookups + +Our IR links to everything with `Handle`, while SPIR-V uses IDs. +In order to keep track of the associations, the parser has many lookup tables. +There map `spirv::Word` into a specific IR handle, plus potentially a bit of +extra info, such as the related SPIR-V type ID. +TODO: would be nice to find ways that avoid looking up as much + +!*/ + +use crate::{ + arena::{Arena, Handle}, + FastHashMap, FastHashSet, +}; + +use num_traits::cast::FromPrimitive; +use std::convert::TryInto; + +pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[ + spirv::Capability::Shader, +]; +pub const SUPPORTED_EXTENSIONS: &[&str] = &[ +]; +pub const SUPPORTED_EXT_SETS: &[&str] = &[ + "GLSL.std.450", +]; + +#[derive(Debug)] +pub enum Error { + InvalidHeader, + InvalidWordCount, + UnknownInstruction(u16), + UnknownCapability(u32), + UnsupportedInstruction(ModuleState, spirv::Op), + UnsupportedCapability(spirv::Capability), + UnsupportedExtension(String), + UnsupportedExtSet(String), + UnsupportedType(Handle), + UnsupportedExecutionModel(u32), + UnsupportedStorageClass(u32), + UnsupportedFunctionControl(u32), + UnsupportedDim(u32), + InvalidParameter(spirv::Op), + InvalidOperandCount(spirv::Op, u16), + InvalidOperand, + InvalidDecoration(spirv::Word), + InvalidId(spirv::Word), + InvalidTypeWidth(spirv::Word), + InvalidSign(spirv::Word), + InvalidInnerType(spirv::Word), + InvalidVectorSize(spirv::Word), + InvalidVariableClass(spirv::StorageClass), + InvalidAccessType(spirv::Word), + InvalidAccessIndex(Handle), + InvalidLoadType(spirv::Word), + InvalidStoreType(spirv::Word), + InvalidBinding(spirv::Word), + WrongFunctionResultType(spirv::Word), + WrongFunctionParameterType(spirv::Word), + BadString, + IncompleteData, +} + +struct Instruction { + op: spirv::Op, + wc: u16, +} + +impl Instruction { + fn expect(&self, count: u16) -> Result<(), Error> { + if self.wc == count { + Ok(()) + } else { + Err(Error::InvalidOperandCount(self.op, self.wc)) + } + } + + fn expect_at_least(&self, count: u16) -> Result<(), Error> { + if self.wc >= count { + Ok(()) + } else { + Err(Error::InvalidOperandCount(self.op, self.wc)) + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub enum ModuleState { + Empty, + Capability, + Extension, + ExtInstImport, + MemoryModel, + EntryPoint, + ExecutionMode, + Source, + Name, + ModuleProcessed, + Annotation, + Type, + Function, +} + +trait LookupHelper { + type Target; + fn lookup(&self, key: spirv::Word) -> Result<&Self::Target, Error>; +} + +impl LookupHelper for FastHashMap { + type Target = T; + fn lookup(&self, key: spirv::Word) -> Result<&T, Error> { + self.get(&key).ok_or(Error::InvalidId(key)) + } +} + +fn map_vector_size(word: spirv::Word) -> Result { + match word { + 2 => Ok(crate::VectorSize::Bi), + 3 => Ok(crate::VectorSize::Tri), + 4 => Ok(crate::VectorSize::Quad), + _ => Err(Error::InvalidVectorSize(word)), + } +} + +fn map_storage_class(word: spirv::Word) -> Result { + spirv::StorageClass::from_u32(word).ok_or(Error::UnsupportedStorageClass(word)) +} + +type MemberIndex = u32; + +#[derive(Debug, Default)] +struct Decoration { + name: Option, + built_in: Option, + location: Option, + desc_set: Option, + desc_index: Option, +} + +impl Decoration { + fn get_binding(&self) -> Option { + //TODO: validate this better + match *self { + Decoration { + built_in: Some(built_in), + location: None, + desc_set: None, + desc_index: None, + .. + } => Some(crate::Binding::BuiltIn(built_in)), + Decoration { + built_in: None, + location: Some(loc), + desc_set: None, + desc_index: None, + .. + } => Some(crate::Binding::Location(loc)), + Decoration { + built_in: None, + location: None, + desc_set: Some(set), + desc_index: Some(binding), + .. + } => Some(crate::Binding::Descriptor { set, binding }), + _ => None, + } + } +} + +#[derive(Debug)] +struct LookupFunctionType { + parameter_type_ids: Vec, + return_type_id: spirv::Word, +} + +#[derive(Debug)] +struct EntryPoint { + exec_model: spirv::ExecutionModel, + name: String, + function_id: spirv::Word, + variable_ids: Vec, +} + +#[derive(Debug)] +struct LookupType { + handle: Handle, + base_id: Option, +} + +#[derive(Debug)] +struct LookupConstant { + handle: Handle, + type_id: spirv::Word, +} + +#[derive(Debug)] +struct LookupVariable { + handle: Handle, + type_id: spirv::Word, +} + +#[derive(Clone, Debug)] +struct LookupExpression { + handle: Handle, + type_id: spirv::Word, +} + +#[derive(Clone, Debug)] +struct LookupSampledImage { + image: Handle, + sampler: Handle, +} + +pub struct Parser { + data: I, + state: ModuleState, + temp_bytes: Vec, + future_decor: FastHashMap, + future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>, + lookup_member_type_id: FastHashMap<(spirv::Word, MemberIndex), spirv::Word>, + lookup_type: FastHashMap, + lookup_void_type: FastHashSet, + lookup_constant: FastHashMap, + lookup_variable: FastHashMap, + lookup_expression: FastHashMap, + lookup_sampled_image: FastHashMap, + lookup_function_type: FastHashMap, + lookup_function: FastHashMap>, +} + +impl> Parser { + pub fn new(data: I) -> Self { + Parser { + data, + state: ModuleState::Empty, + temp_bytes: Vec::new(), + future_decor: FastHashMap::default(), + future_member_decor: FastHashMap::default(), + lookup_member_type_id: FastHashMap::default(), + lookup_type: FastHashMap::default(), + lookup_void_type: FastHashSet::default(), + lookup_constant: FastHashMap::default(), + lookup_variable: FastHashMap::default(), + lookup_expression: FastHashMap::default(), + lookup_sampled_image: FastHashMap::default(), + lookup_function_type: FastHashMap::default(), + lookup_function: FastHashMap::default(), + } + } + + fn next(&mut self) -> Result { + self.data.next().ok_or(Error::IncompleteData) + } + + fn next_inst(&mut self) -> Result { + let word = self.next()?; + let (wc, opcode) = ((word >> 16) as u16, (word & 0xffff) as u16); + if wc == 0 { + return Err(Error::InvalidWordCount); + } + let op = spirv::Op::from_u16(opcode).ok_or(Error::UnknownInstruction(opcode))?; + + Ok(Instruction { op, wc }) + } + + fn next_string(&mut self, mut count: u16) -> Result<(String, u16), Error>{ + self.temp_bytes.clear(); + loop { + if count == 0 { + return Err(Error::BadString); + } + count -= 1; + let chars = self.next()?.to_le_bytes(); + let pos = chars.iter().position(|&c| c == 0).unwrap_or(4); + self.temp_bytes.extend_from_slice(&chars[.. pos]); + if pos < 4 { + break + } + } + std::str::from_utf8(&self.temp_bytes) + .map(|s| (s.to_owned(), count)) + .map_err(|_| Error::BadString) + } + + fn next_decoration( + &mut self, + inst: Instruction, + base_words: u16, + dec: &mut Decoration, + ) -> Result<(), Error> { + let raw = self.next()?; + let dec_typed = spirv::Decoration::from_u32(raw).ok_or(Error::InvalidDecoration(raw))?; + log::trace!("\t\t{:?}", dec_typed); + match dec_typed { + spirv::Decoration::BuiltIn => { + inst.expect(base_words + 2)?; + let raw = self.next()?; + let built_in = spirv::BuiltIn::from_u32(raw); + if built_in.is_none() { + log::warn!("Unknown built in {:?}", raw); + } + dec.built_in = built_in; + } + spirv::Decoration::Location => { + inst.expect(base_words + 2)?; + dec.location = Some(self.next()?); + } + spirv::Decoration::DescriptorSet => { + inst.expect(base_words + 2)?; + dec.desc_set = Some(self.next()?); + } + spirv::Decoration::Binding => { + inst.expect(base_words + 2)?; + dec.desc_index = Some(self.next()?); + } + other => { + log::warn!("Unknown decoration {:?}", other); + for _ in base_words + 1 .. inst.wc { + let _var = self.next()?; + } + } + } + Ok(()) + } + + fn next_block( + &mut self, + fun: &mut crate::Function, + type_arena: &Arena, + const_arena: &Arena, + ) -> Result<(), Error> { + loop { + use spirv::Op; + let inst = self.next_inst()?; + log::debug!("\t\t{:?} [{}]", inst.op, inst.wc); + match inst.op { + Op::AccessChain => { + struct AccessExpression { + base_handle: Handle, + type_id: spirv::Word, + } + inst.expect_at_least(4)?; + let result_type_id = self.next()?; + let result_id = self.next()?; + let base_id = self.next()?; + log::trace!("\t\t\tlooking up expr {:?}", base_id); + let mut acex = { + let expr = self.lookup_expression.lookup(base_id)?; + let ptr_type = self.lookup_type.lookup(expr.type_id)?; + AccessExpression { + base_handle: expr.handle, + type_id: ptr_type.base_id.unwrap(), + } + }; + for _ in 4 .. inst.wc { + let access_id = self.next()?; + log::trace!("\t\t\tlooking up expr {:?}", access_id); + let index_expr = self.lookup_expression.lookup(access_id)?.clone(); + let index_type_handle = self.lookup_type.lookup(index_expr.type_id)?.handle; + match type_arena[index_type_handle].inner { + crate::TypeInner::Scalar { kind: crate::ScalarKind::Uint, .. } | + crate::TypeInner::Scalar { kind: crate::ScalarKind::Sint, .. } => (), + _ => return Err(Error::UnsupportedType(index_type_handle)), + } + log::trace!("\t\t\tlooking up type {:?}", acex.type_id); + let type_lookup = self.lookup_type.lookup(acex.type_id)?; + acex = match type_arena[type_lookup.handle].inner { + crate::TypeInner::Struct { .. } => { + let index = match fun.expressions[index_expr.handle] { + crate::Expression::Constant(const_handle) => { + match const_arena[const_handle].inner { + crate::ConstantInner::Uint(v) => v as u32, + crate::ConstantInner::Sint(v) => v as u32, + _ => return Err(Error::InvalidAccessIndex(index_expr.handle)), + } + } + _ => return Err(Error::InvalidAccessIndex(index_expr.handle)) + }; + AccessExpression { + base_handle: fun.expressions.append(crate::Expression::AccessIndex { + base: acex.base_handle, + index, + }), + type_id: *self.lookup_member_type_id + .get(&(acex.type_id, index)) + .ok_or(Error::InvalidAccessType(acex.type_id))?, + } + } + crate::TypeInner::Array { .. } | + crate::TypeInner::Vector { .. } | + crate::TypeInner::Matrix { .. } => { + AccessExpression { + base_handle: fun.expressions.append(crate::Expression::Access { + base: acex.base_handle, + index: index_expr.handle, + }), + type_id: type_lookup.base_id + .ok_or(Error::InvalidAccessType(acex.type_id))?, + } + } + _ => return Err(Error::UnsupportedType(type_lookup.handle)), + }; + } + + self.lookup_expression.insert(result_id, LookupExpression { + handle: acex.base_handle, + type_id: result_type_id, + }); + } + Op::CompositeExtract => { + inst.expect_at_least(4)?; + let result_type_id = self.next()?; + let result_id = self.next()?; + let base_id = self.next()?; + log::trace!("\t\t\tlooking up expr {:?}", base_id); + let mut lexp = { + let expr = self.lookup_expression.lookup(base_id)?; + LookupExpression { + handle: expr.handle, + type_id: expr.type_id, + } + }; + for _ in 4 .. inst.wc { + let index = self.next()?; + log::trace!("\t\t\tlooking up type {:?}", lexp.type_id); + let type_lookup = self.lookup_type.lookup(lexp.type_id)?; + let type_id = match type_arena[type_lookup.handle].inner { + crate::TypeInner::Struct { .. } => { + *self.lookup_member_type_id + .get(&(lexp.type_id, index)) + .ok_or(Error::InvalidAccessType(lexp.type_id))? + } + crate::TypeInner::Array { .. } | + crate::TypeInner::Vector { .. } | + crate::TypeInner::Matrix { .. } => { + type_lookup.base_id + .ok_or(Error::InvalidAccessType(lexp.type_id))? + } + _ => return Err(Error::UnsupportedType(type_lookup.handle)), + }; + lexp = LookupExpression { + handle: fun.expressions.append(crate::Expression::AccessIndex { + base: lexp.handle, + index, + }), + type_id, + }; + } + + self.lookup_expression.insert(result_id, LookupExpression { + handle: lexp.handle, + type_id: result_type_id, + }); + } + Op::CompositeConstruct => { + inst.expect_at_least(3)?; + let result_type_id = self.next()?; + let id = self.next()?; + let mut components = Vec::with_capacity(inst.wc as usize - 2); + for _ in 3 .. inst.wc { + let comp_id = self.next()?; + log::trace!("\t\t\tlooking up expr {:?}", comp_id); + let lexp = self.lookup_expression.lookup(comp_id)?; + components.push(lexp.handle); + } + let expr = crate::Expression::Compose { + ty: self.lookup_type.lookup(result_type_id)?.handle, + components, + }; + self.lookup_expression.insert(id, LookupExpression { + handle: fun.expressions.append(expr), + type_id: result_type_id, + }); + } + Op::Load => { + inst.expect_at_least(4)?; + let result_type_id = self.next()?; + let result_id = self.next()?; + let pointer_id = self.next()?; + if inst.wc != 4 { + inst.expect(5)?; + let _memory_access = self.next()?; + } + let base_expr = self.lookup_expression.lookup(pointer_id)?; + let base_type = self.lookup_type.lookup(base_expr.type_id)?; + if base_type.base_id != Some(result_type_id) { + return Err(Error::InvalidLoadType(result_type_id)); + } + match type_arena[base_type.handle].inner { + crate::TypeInner::Pointer { .. } => (), + _ => return Err(Error::UnsupportedType(base_type.handle)), + } + let expr = crate::Expression::Load { + pointer: base_expr.handle, + }; + self.lookup_expression.insert(result_id, LookupExpression { + handle: fun.expressions.append(expr), + type_id: result_type_id, + }); + } + Op::Store => { + inst.expect_at_least(3)?; + let pointer_id = self.next()?; + let value_id = self.next()?; + if inst.wc != 3 { + inst.expect(4)?; + let _memory_access = self.next()?; + } + let base_expr = self.lookup_expression.lookup(pointer_id)?; + let base_type = self.lookup_type.lookup(base_expr.type_id)?; + match type_arena[base_type.handle].inner { + crate::TypeInner::Pointer { .. } => (), + _ => return Err(Error::UnsupportedType(base_type.handle)), + }; + let value_expr = self.lookup_expression.lookup(value_id)?; + if base_type.base_id != Some(value_expr.type_id) { + return Err(Error::InvalidStoreType(value_expr.type_id)); + } + fun.body.push(crate::Statement::Store { + pointer: base_expr.handle, + value: value_expr.handle, + }) + } + Op::Return => { + inst.expect(1)?; + fun.body.push(crate::Statement::Return { value: None }); + break + } + Op::VectorTimesScalar => { + inst.expect(5)?; + let result_type_id = self.next()?; + let result_type_loookup = self.lookup_type.lookup(result_type_id)?; + let (res_size, res_width) = match type_arena[result_type_loookup.handle].inner { + crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } => (size, width), + _ => return Err(Error::UnsupportedType(result_type_loookup.handle)), + }; + let result_id = self.next()?; + let vector_id = self.next()?; + let scalar_id = self.next()?; + let vector_lexp = self.lookup_expression.lookup(vector_id)?; + let vector_type_lookup = self.lookup_type.lookup(vector_lexp.type_id)?; + match type_arena[vector_type_lookup.handle].inner { + crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } if size == res_size && width == res_width => (), + _ => return Err(Error::UnsupportedType(vector_type_lookup.handle)), + }; + let scalar_lexp = self.lookup_expression.lookup(scalar_id)?.clone(); + let scalar_type_lookup = self.lookup_type.lookup(scalar_lexp.type_id)?; + match type_arena[scalar_type_lookup.handle].inner { + crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, width } if width == res_width => (), + _ => return Err(Error::UnsupportedType(scalar_type_lookup.handle)), + }; + let expr = crate::Expression::Binary { + op: crate::BinaryOperator::Multiply, + left: vector_lexp.handle, + right: scalar_lexp.handle, + }; + self.lookup_expression.insert(result_id, LookupExpression { + handle: fun.expressions.append(expr), + type_id: result_type_id, + }); + } + Op::MatrixTimesVector => { + inst.expect(5)?; + let result_type_id = self.next()?; + let result_type_loookup = self.lookup_type.lookup(result_type_id)?; + let (res_size, res_width) = match type_arena[result_type_loookup.handle].inner { + crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } => (size, width), + _ => return Err(Error::UnsupportedType(result_type_loookup.handle)), + }; + let result_id = self.next()?; + let matrix_id = self.next()?; + let vector_id = self.next()?; + let matrix_lexp = self.lookup_expression.lookup(matrix_id)?; + let matrix_type_lookup = self.lookup_type.lookup(matrix_lexp.type_id)?; + let columns = match type_arena[matrix_type_lookup.handle].inner { + crate::TypeInner::Matrix { columns, rows, kind: crate::ScalarKind::Float, width } if rows == res_size && width == res_width => columns, + _ => return Err(Error::UnsupportedType(matrix_type_lookup.handle)), + }; + let vector_lexp = self.lookup_expression.lookup(vector_id)?.clone(); + let vector_type_lookup = self.lookup_type.lookup(vector_lexp.type_id)?; + match type_arena[vector_type_lookup.handle].inner { + crate::TypeInner::Vector { size, kind: crate::ScalarKind::Float, width } if size == columns && width == res_width => (), + _ => return Err(Error::UnsupportedType(vector_type_lookup.handle)), + }; + let expr = crate::Expression::Binary { + op: crate::BinaryOperator::Multiply, + left: matrix_lexp.handle, + right: vector_lexp.handle, + }; + self.lookup_expression.insert(result_id, LookupExpression { + handle: fun.expressions.append(expr), + type_id: result_type_id, + }); + } + Op::SampledImage => { + inst.expect(5)?; + let _result_type_id = self.next()?; + let result_id = self.next()?; + let image_id = self.next()?; + let sampler_id = self.next()?; + let image_lexp = self.lookup_expression.lookup(image_id)?; + let sampler_lexp = self.lookup_expression.lookup(sampler_id)?; + //TODO: compare the result type + self.lookup_sampled_image.insert(result_id, LookupSampledImage { + image: image_lexp.handle, + sampler: sampler_lexp.handle, + }); + } + Op::ImageSampleImplicitLod => { + inst.expect_at_least(5)?; + let result_type_id = self.next()?; + let result_id = self.next()?; + let sampled_image_id = self.next()?; + let coordinate_id = self.next()?; + let si_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?; + let coord_lexp = self.lookup_expression.lookup(coordinate_id)?; + let coord_type_lookup = self.lookup_type.lookup(coord_lexp.type_id)?; + match type_arena[coord_type_lookup.handle].inner { + crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, .. } | + crate::TypeInner::Vector { kind: crate::ScalarKind::Float, .. } => (), + _ => return Err(Error::UnsupportedType(coord_type_lookup.handle)), + } + //TODO: compare the result type + let expr = crate::Expression::ImageSample { + image: si_lexp.image, + sampler: si_lexp.sampler, + coordinate: coord_lexp.handle, + }; + self.lookup_expression.insert(result_id, LookupExpression { + handle: fun.expressions.append(expr), + type_id: result_type_id, + }); + } + _ => return Err(Error::UnsupportedInstruction(self.state, inst.op)), + } + } + Ok(()) + } + + fn make_expression_storage(&mut self) -> Arena { + let mut expressions = Arena::new(); + assert!(self.lookup_expression.is_empty()); + // register global variables + for (&id, var) in self.lookup_variable.iter() { + self.lookup_expression.insert(id, LookupExpression { + type_id: var.type_id, + handle: expressions.append(crate::Expression::GlobalVariable(var.handle)), + }); + } + // register constants + for (&id, con) in self.lookup_constant.iter() { + self.lookup_expression.insert(id, LookupExpression { + type_id: con.type_id, + handle: expressions.append(crate::Expression::Constant(con.handle)), + }); + } + // done + expressions + } + + fn switch(&mut self, state: ModuleState, op: spirv::Op) -> Result<(), Error> { + if state < self.state { + Err(Error::UnsupportedInstruction(self.state, op)) + } else { + self.state = state; + Ok(()) + } + } + + pub fn parse(&mut self) -> Result { + let mut module = crate::Module::from_header({ + if self.next()? != spirv::MAGIC_NUMBER { + return Err(Error::InvalidHeader); + } + let version_raw = self.next()?.to_le_bytes(); + let generator = self.next()?; + let _bound = self.next()?; + let _schema = self.next()?; + crate::Header { + version: (version_raw[2], version_raw[1], version_raw[0]), + generator, + } + }); + let mut entry_points = Vec::new(); + + while let Ok(inst) = self.next_inst() { + use spirv::Op; + log::debug!("\t{:?} [{}]", inst.op, inst.wc); + match inst.op { + Op::Capability => self.parse_capability(inst), + Op::Extension => self.parse_extension(inst), + Op::ExtInstImport => self.parse_ext_inst_import(inst), + Op::MemoryModel => self.parse_memory_model(inst), + Op::EntryPoint => self.parse_entry_point(inst, &mut entry_points), + Op::ExecutionMode => self.parse_execution_mode(inst), + Op::Source => self.parse_source(inst), + Op::SourceExtension => self.parse_source_extension(inst), + Op::Name => self.parse_name(inst), + Op::MemberName => self.parse_member_name(inst), + Op::Decorate => self.parse_decorate(inst), + Op::MemberDecorate => self.parse_member_decorate(inst), + Op::TypeVoid => self.parse_type_void(inst), + Op::TypeInt => self.parse_type_int(inst, &mut module), + Op::TypeFloat => self.parse_type_float(inst, &mut module), + Op::TypeVector => self.parse_type_vector(inst, &mut module), + Op::TypeMatrix => self.parse_type_matrix(inst, &mut module), + Op::TypeFunction => self.parse_type_function(inst), + Op::TypePointer => self.parse_type_pointer(inst, &mut module), + Op::TypeArray => self.parse_type_array(inst, &mut module), + Op::TypeRuntimeArray => self.parse_type_runtime_array(inst, &mut module), + Op::TypeStruct => self.parse_type_struct(inst, &mut module), + Op::TypeImage => self.parse_type_image(inst, &mut module), + Op::TypeSampledImage => self.parse_type_sampled_image(inst), + Op::TypeSampler => self.parse_type_sampler(inst, &mut module), + Op::Constant | Op::SpecConstant => self.parse_constant(inst, &mut module), + Op::ConstantComposite => self.parse_composite_constant(inst, &mut module), + Op::Variable => self.parse_variable(inst, &mut module), + Op::Function => self.parse_function(inst, &mut module), + _ => Err(Error::UnsupportedInstruction(self.state, inst.op)), //TODO + }?; + } + + if !self.future_decor.is_empty() { + log::warn!("Unused item decorations: {:?}", self.future_decor); + self.future_decor.clear(); + } + if !self.future_member_decor.is_empty() { + log::warn!("Unused member decorations: {:?}", self.future_member_decor); + self.future_member_decor.clear(); + } + + module.entry_points.reserve(entry_points.len()); + for raw in entry_points { + module.entry_points.push(crate::EntryPoint { + exec_model: raw.exec_model, + name: raw.name, + function: *self.lookup_function.lookup(raw.function_id)?, + }); + } + + Ok(module) + } + + fn parse_capability(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Capability, inst.op)?; + inst.expect(2)?; + let capability = self.next()?; + let cap = + spirv::Capability::from_u32(capability).ok_or(Error::UnknownCapability(capability))?; + if !SUPPORTED_CAPABILITIES.contains(&cap) { + return Err(Error::UnsupportedCapability(cap)); + } + Ok(()) + } + + fn parse_extension(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Extension, inst.op)?; + inst.expect_at_least(2)?; + let (name, left) = self.next_string(inst.wc - 1)?; + if left != 0 { + return Err(Error::InvalidOperand); + } + if !SUPPORTED_EXTENSIONS.contains(&name.as_str()) { + return Err(Error::UnsupportedExtension(name.to_owned())); + } + Ok(()) + } + + fn parse_ext_inst_import(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Extension, inst.op)?; + inst.expect_at_least(3)?; + let _result = self.next()?; + let (name, left) = self.next_string(inst.wc - 2)?; + if left != 0 { + return Err(Error::InvalidOperand); + } + if !SUPPORTED_EXT_SETS.contains(&name.as_str()) { + return Err(Error::UnsupportedExtSet(name.to_owned())); + } + Ok(()) + } + + fn parse_memory_model(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::MemoryModel, inst.op)?; + inst.expect(3)?; + let _addressing_model = self.next()?; + let _memory_model = self.next()?; + Ok(()) + } + + fn parse_entry_point( + &mut self, + inst: Instruction, + entry_points: &mut Vec, + ) -> Result<(), Error> { + self.switch(ModuleState::EntryPoint, inst.op)?; + inst.expect_at_least(4)?; + let exec_model = self.next()?; + let exec_model = spirv::ExecutionModel::from_u32(exec_model) + .ok_or(Error::UnsupportedExecutionModel(exec_model))?; + let function_id = self.next()?; + let (name, left) = self.next_string(inst.wc - 3)?; + let ep = EntryPoint { + exec_model, + name: name.to_owned(), + function_id, + variable_ids: self.data + .by_ref() + .take(left as usize) + .collect(), + }; + entry_points.push(ep); + Ok(()) + } + + fn parse_execution_mode(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::ExecutionMode, inst.op)?; + inst.expect_at_least(3)?; + let _ep_id = self.next()?; + let _mode = self.next()?; + for _ in 3..inst.wc { + let _ = self.next()?; //TODO + } + Ok(()) + } + + fn parse_source(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Source, inst.op)?; + for _ in 1 .. inst.wc { + let _ = self.next()?; + } + Ok(()) + } + + fn parse_source_extension(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Source, inst.op)?; + inst.expect_at_least(2)?; + let (_name, _) = self.next_string(inst.wc - 1)?; + Ok(()) + } + + fn parse_name(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Name, inst.op)?; + inst.expect_at_least(3)?; + let id = self.next()?; + let (name, left) = self.next_string(inst.wc - 2)?; + if left != 0 { + return Err(Error::InvalidOperand); + } + self.future_decor + .entry(id) + .or_default() + .name = Some(name.to_owned()); + Ok(()) + } + + fn parse_member_name(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Name, inst.op)?; + inst.expect_at_least(4)?; + let id = self.next()?; + let member = self.next()?; + let (name, left) = self.next_string(inst.wc - 3)?; + if left != 0 { + return Err(Error::InvalidOperand); + } + self.future_member_decor + .entry((id, member)) + .or_default() + .name = Some(name.to_owned()); + Ok(()) + } + + fn parse_decorate(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Annotation, inst.op)?; + inst.expect_at_least(3)?; + let id = self.next()?; + let mut dec = self.future_decor + .remove(&id) + .unwrap_or_default(); + self.next_decoration(inst, 2, &mut dec)?; + self.future_decor.insert(id, dec); + Ok(()) + } + + fn parse_member_decorate(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Annotation, inst.op)?; + inst.expect_at_least(4)?; + let id = self.next()?; + let member = self.next()?; + let mut dec = self.future_member_decor + .remove(&(id, member)) + .unwrap_or_default(); + self.next_decoration(inst, 3, &mut dec)?; + self.future_member_decor.insert((id, member), dec); + Ok(()) + } + + fn parse_type_void(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(2)?; + let id = self.next()?; + self.lookup_void_type.insert(id); + Ok(()) + } + + fn parse_type_int( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(4)?; + let id = self.next()?; + let width = self.next()?; + let sign = self.next()?; + let inner = crate::TypeInner::Scalar { + kind: match sign { + 0 => crate::ScalarKind::Uint, + 1 => crate::ScalarKind::Sint, + _ => return Err(Error::InvalidSign(sign)), + }, + width: width + .try_into() + .map_err(|_| Error::InvalidTypeWidth(width))?, + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor + .remove(&id) + .and_then(|dec| dec.name), + inner, + }), + base_id: None, + }); + Ok(()) + } + + fn parse_type_float( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(3)?; + let id = self.next()?; + let width = self.next()?; + let inner = crate::TypeInner::Scalar { + kind: crate::ScalarKind::Float, + width: width + .try_into() + .map_err(|_| Error::InvalidTypeWidth(width))?, + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor + .remove(&id) + .and_then(|dec| dec.name), + inner, + }), + base_id: None, + }); + Ok(()) + } + + fn parse_type_vector( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(4)?; + let id = self.next()?; + let type_id = self.next()?; + let type_lookup = self.lookup_type.lookup(type_id)?; + let (kind, width) = match module.types[type_lookup.handle].inner { + crate::TypeInner::Scalar { kind, width } => (kind, width), + _ => return Err(Error::InvalidInnerType(type_id)), + }; + let component_count = self.next()?; + let inner = crate::TypeInner::Vector { + size: map_vector_size(component_count)?, + kind, + width, + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor + .remove(&id) + .and_then(|dec| dec.name), + inner, + }), + base_id: Some(type_id), + }); + Ok(()) + } + + fn parse_type_matrix( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(4)?; + let id = self.next()?; + let vector_type_id = self.next()?; + let num_columns = self.next()?; + let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?; + let inner = match module.types[vector_type_lookup.handle].inner { + crate::TypeInner::Vector { size, kind, width } => crate::TypeInner::Matrix { + columns: map_vector_size(num_columns)?, + rows: size, + kind, + width, + }, + _ => return Err(Error::InvalidInnerType(vector_type_id)), + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor + .remove(&id) + .and_then(|dec| dec.name), + inner, + }), + base_id: Some(vector_type_id), + }); + Ok(()) + } + + fn parse_type_function(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect_at_least(3)?; + let id = self.next()?; + let return_type_id = self.next()?; + let parameter_type_ids = self.data + .by_ref() + .take(inst.wc as usize - 3) + .collect(); + self.lookup_function_type.insert(id, LookupFunctionType { + parameter_type_ids, + return_type_id, + }); + Ok(()) + } + + fn parse_type_pointer( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(4)?; + let id = self.next()?; + let storage = self.next()?; + let type_id = self.next()?; + let inner = crate::TypeInner::Pointer { + base: self.lookup_type.lookup(type_id)?.handle, + class: map_storage_class(storage)?, + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor + .remove(&id) + .and_then(|dec| dec.name), + inner, + }), + base_id: Some(type_id), + }); + Ok(()) + } + + fn parse_type_array( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(4)?; + let id = self.next()?; + let type_id = self.next()?; + let length = self.next()?; + let inner = crate::TypeInner::Array { + base: self.lookup_type.lookup(type_id)?.handle, + size: crate::ArraySize::Static(length), + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor + .remove(&id) + .and_then(|dec| dec.name), + inner, + }), + base_id: Some(type_id), + }); + Ok(()) + } + + fn parse_type_runtime_array( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(4)?; + let id = self.next()?; + let type_id = self.next()?; + let inner = crate::TypeInner::Array { + base: self.lookup_type.lookup(type_id)?.handle, + size: crate::ArraySize::Dynamic, + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor.remove(&id).and_then(|dec| dec.name), + inner, + }), + base_id: Some(type_id), + }); + Ok(()) + } + + fn parse_type_struct( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect_at_least(2)?; + let id = self.next()?; + let mut members = Vec::with_capacity(inst.wc as usize - 2); + for i in 0 .. u32::from(inst.wc) - 2 { + let type_id = self.next()?; + let ty = self.lookup_type.lookup(type_id)?.handle; + self.lookup_member_type_id.insert((id, i), type_id); + let decor = self.future_member_decor + .remove(&(id, i)) + .unwrap_or_default(); + let binding = decor.get_binding(); + members.push(crate::StructMember { + name: decor.name, + binding, + ty, + }); + } + let inner = crate::TypeInner::Struct { + members + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: self.future_decor.remove(&id).and_then(|dec| dec.name), + inner, + }), + base_id: None, + }); + Ok(()) + } + + fn parse_type_image( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect_at_least(9)?; + + let id = self.next()?; + let sample_type_id = self.next()?; + let dim = self.next()?; + let mut flags = crate::ImageFlags::empty(); + let _is_depth = self.next()?; + if self.next()? != 0 { + flags |= crate::ImageFlags::ARRAYED; + } + if self.next()? != 0 { + flags |= crate::ImageFlags::MULTISAMPLED; + } + let is_sampled = self.next()?; + if is_sampled != 0 { + flags |= crate::ImageFlags::SAMPLED; + } + let _format = self.next()?; + if inst.wc > 9 { + inst.expect(10)?; + let access = self.next()?; + if access == 0 || access == 2 { + flags |= crate::ImageFlags::CAN_LOAD; + } + if access == 1 || access == 2 { + flags |= crate::ImageFlags::CAN_STORE; + } + }; + + let decor = self.future_decor + .remove(&id) + .unwrap_or_default(); + + let inner = crate::TypeInner::Image { + base: self.lookup_type.lookup(sample_type_id)?.handle, + dim: spirv::Dim::from_u32(dim).ok_or(Error::UnsupportedDim(dim))?, + flags, + }; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: decor.name, + inner, + }), + base_id: Some(sample_type_id), + }); + Ok(()) + } + + fn parse_type_sampled_image(&mut self, inst: Instruction) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(3)?; + let id = self.next()?; + let image_id = self.next()?; + self.lookup_type.insert(id, LookupType { + handle: self.lookup_type.lookup(image_id)?.handle, + base_id: Some(image_id), + }); + Ok(()) + } + + fn parse_type_sampler( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect(2)?; + let id = self.next()?; + let decor = self.future_decor + .remove(&id) + .unwrap_or_default(); + let inner = crate::TypeInner::Sampler; + self.lookup_type.insert(id, LookupType { + handle: module.types.append(crate::Type { + name: decor.name, + inner, + }), + base_id: None, + }); + Ok(()) + } + + fn parse_constant( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect_at_least(3)?; + let type_id = self.next()?; + let id = self.next()?; + let type_lookup = self.lookup_type.lookup(type_id)?; + let ty = type_lookup.handle; + let inner = match module.types[type_lookup.handle].inner { + crate::TypeInner::Scalar { kind: crate::ScalarKind::Uint, width } => { + let low = self.next()?; + let high = if width > 32 { + inst.expect(4)?; + self.next()? + } else { + 0 + }; + crate::ConstantInner::Uint((u64::from(high) << 32) | u64::from(low)) + } + crate::TypeInner::Scalar { kind: crate::ScalarKind::Sint, width } => { + let low = self.next()?; + let high = if width < 32 { + return Err(Error::InvalidTypeWidth(u32::from(width))); + } else if width > 32 { + inst.expect(4)?; + self.next()? + } else { + !0 + }; + crate::ConstantInner::Sint(((u64::from(high) << 32) | u64::from(low)) as i64) + } + crate::TypeInner::Scalar { kind: crate::ScalarKind::Float, width } => { + let low = self.next()?; + let extended = match width { + 32 => f64::from(f32::from_bits(low)), + 64 => { + inst.expect(4)?; + let high = self.next()?; + f64::from_bits((u64::from(high) << 32) | u64::from(low)) + } + _ => return Err(Error::InvalidTypeWidth(u32::from(width))), + }; + crate::ConstantInner::Float(extended) + } + _ => return Err(Error::UnsupportedType(type_lookup.handle)) + }; + self.lookup_constant.insert(id, LookupConstant { + handle: module.constants.append(crate::Constant { + name: self.future_decor + .remove(&id) + .and_then(|dec| dec.name), + specialization: None, //TODO + inner, + ty, + }), + type_id, + }); + Ok(()) + } + + fn parse_composite_constant( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect_at_least(3)?; + let type_id = self.next()?; + let type_lookup = self.lookup_type.lookup(type_id)?; + let ty = type_lookup.handle; + + let id = self.next()?; + + let constituents_count = inst.wc - 3; + let mut constituents = Vec::with_capacity(constituents_count as usize); + for _ in 0..constituents_count { + let constituent_id = self.next()?; + let constant = self.lookup_constant.lookup(constituent_id)?; + constituents.push(constant.handle); + } + + self.lookup_constant.insert(id, LookupConstant { + handle: module.constants.append(crate::Constant { + name: self.future_decor + .remove(&id) + .and_then(|dec|dec.name), + specialization: None, + inner: crate::ConstantInner::Composite(constituents), + ty + }), + type_id + }); + + Ok(()) + } + + fn parse_variable( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Type, inst.op)?; + inst.expect_at_least(4)?; + let type_id = self.next()?; + let id = self.next()?; + let storage = self.next()?; + if inst.wc != 4 { + inst.expect(5)?; + let _init = self.next()?; //TODO + } + let lookup_type = self.lookup_type.lookup(type_id)?; + let dec = self.future_decor + .remove(&id) + .ok_or(Error::InvalidBinding(id))?; + let binding = match module.types[lookup_type.handle].inner { + crate::TypeInner::Pointer { base, class: spirv::StorageClass::Input } | + crate::TypeInner::Pointer { base, class: spirv::StorageClass::Output } => { + match module.types[base].inner { + crate::TypeInner::Struct { ref members } => { + // we don't expect binding decoration on I/O structs, + // but we do expect them on all of the members + for member in members { + if member.binding.is_none() { + log::warn!("Struct {:?} member {:?} doesn't have a binding", base, member); + return Err(Error::InvalidBinding(id)); + } + } + None + } + _ => { + Some(dec + .get_binding() + .ok_or(Error::InvalidBinding(id))? + ) + } + } + } + _ => { + Some(dec + .get_binding() + .ok_or(Error::InvalidBinding(id))? + ) + } + }; + let var = crate::GlobalVariable { + name: dec.name, + class: map_storage_class(storage)?, + binding, + ty: lookup_type.handle, + }; + self.lookup_variable.insert(id, LookupVariable { + handle: module.global_variables.append(var), + type_id, + }); + Ok(()) + } + + fn parse_function( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + self.switch(ModuleState::Function, inst.op)?; + inst.expect(5)?; + let result_type = self.next()?; + let fun_id = self.next()?; + let fun_control = self.next()?; + let fun_type = self.next()?; + let mut fun = { + let ft = self.lookup_function_type.lookup(fun_type)?; + if ft.return_type_id != result_type { + return Err(Error::WrongFunctionResultType(result_type)) + } + crate::Function { + name: self.future_decor + .remove(&fun_id) + .and_then(|dec| dec.name), + control: spirv::FunctionControl::from_bits(fun_control) + .ok_or(Error::UnsupportedFunctionControl(fun_control))?, + parameter_types: Vec::with_capacity(ft.parameter_type_ids.len()), + return_type: if self.lookup_void_type.contains(&result_type) { + None + } else { + Some(self.lookup_type.lookup(result_type)?.handle) + }, + global_usage: Vec::new(), + local_variables: Arena::new(), + expressions: self.make_expression_storage(), + body: Vec::new(), + } + }; + // read parameters + for i in 0..fun.parameter_types.capacity() { + match self.next_inst()? { + Instruction { op: spirv::Op::FunctionParameter, wc: 3 } => { + let type_id = self.next()?; + let _id = self.next()?; + //Note: we redo the lookup in order to work around `self` borrowing + if type_id != self.lookup_function_type + .lookup(fun_type)? + .parameter_type_ids[i] + { + return Err(Error::WrongFunctionParameterType(type_id)) + } + let ty = self.lookup_type.lookup(type_id)?.handle; + fun.parameter_types.push(ty); + } + Instruction { op, .. } => return Err(Error::InvalidParameter(op)), + } + } + // read body + loop { + let fun_inst = self.next_inst()?; + log::debug!("\t\t{:?}", fun_inst.op); + match fun_inst.op { + spirv::Op::Label => { + fun_inst.expect(2)?; + let _id = self.next()?; + self.next_block(&mut fun, &module.types, &module.constants)?; + } + spirv::Op::FunctionEnd => { + fun_inst.expect(1)?; + break + } + _ => return Err(Error::UnsupportedInstruction(self.state, fun_inst.op)) + } + } + // done + fun.global_usage = crate::GlobalUse::scan(&fun.expressions, &fun.body, &module.global_variables); + let handle = module.functions.append(fun); + self.lookup_function.insert(fun_id, handle); + self.lookup_expression.clear(); + self.lookup_sampled_image.clear(); + Ok(()) + } +} + +pub fn parse_u8_slice(data: &[u8]) -> Result { + if data.len() % 4 != 0 { + return Err(Error::IncompleteData); + } + + let words = data + .chunks(4) + .map(|c| u32::from_le_bytes(c.try_into().unwrap())); + Parser::new(words).parse() +} + +#[cfg(test)] +mod test { + #[test] + fn parse() { + let bin = vec![ + // Magic number. Version number: 1.0. + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, + // Generator number: 0. Bound: 0. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Reserved word: 0. + 0x00, 0x00, 0x00, 0x00, + // OpMemoryModel. Logical. + 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + // GLSL450. + 0x01, 0x00, 0x00, 0x00, + ]; + let _ = super::parse_u8_slice(&bin).unwrap(); + } +} diff --git a/third_party/rust/naga/src/front/wgsl.rs b/third_party/rust/naga/src/front/wgsl.rs new file mode 100644 index 000000000000..2ae50f9be844 --- /dev/null +++ b/third_party/rust/naga/src/front/wgsl.rs @@ -0,0 +1,1402 @@ +use crate::{ + arena::{Arena, Handle}, + proc::{Typifier, ResolveError}, + FastHashMap, +}; + + +#[derive(Debug, PartialEq)] +pub enum Token<'a> { + Separator(char), + DoubleColon, + Paren(char), + DoubleParen(char), + Number(&'a str), + String(&'a str), + Word(&'a str), + Operation(char), + LogicalOperation(char), + ShiftOperation(char), + ArithmeticShiftOperation(char), + Arrow, + Unknown(char), + UnterminatedString, + End, +} + +mod lex { + use super::Token; + + fn _consume_str<'a>(input: &'a str, what: &str) -> Option<&'a str> { + if input.starts_with(what) { + Some(&input[what.len() ..]) + } else { + None + } + } + + fn consume_any(input: &str, what: impl Fn(char) -> bool) -> (&str, &str) { + let pos = input.find(|c| !what(c)).unwrap_or_else(|| input.len()); + input.split_at(pos) + } + + pub fn consume_token(mut input: &str) -> (Token<'_>, &str) { + input = input.trim_start(); + let mut chars = input.chars(); + let cur = match chars.next() { + Some(c) => c, + None => return (Token::End, input), + }; + match cur { + ':' => { + input = chars.as_str(); + if chars.next() == Some(':') { + (Token::DoubleColon, chars.as_str()) + } else { + (Token::Separator(cur), input) + } + } + ';' | ',' | '.' => { + (Token::Separator(cur), chars.as_str()) + } + '(' | ')' | '{' | '}' => { + (Token::Paren(cur), chars.as_str()) + } + '<' | '>' => { + input = chars.as_str(); + let next = chars.next(); + if next == Some('=') { + (Token::LogicalOperation(cur), chars.as_str()) + } else if next == Some(cur) { + input = chars.as_str(); + if chars.next() == Some(cur) { + (Token::ArithmeticShiftOperation(cur), chars.as_str()) + } else { + (Token::ShiftOperation(cur), input) + } + } else { + (Token::Paren(cur), input) + } + } + '[' | ']' => { + input = chars.as_str(); + if chars.next() == Some(cur) { + (Token::DoubleParen(cur), chars.as_str()) + } else { + (Token::Paren(cur), input) + } + } + '0' ..= '9' => { + let (number, rest) = consume_any(input, |c| (c>='0' && c<='9' || c=='.')); + (Token::Number(number), rest) + } + 'a'..='z' | 'A'..='Z' | '_' => { + let (word, rest) = consume_any(input, |c| c.is_alphanumeric() || c=='_'); + (Token::Word(word), rest) + } + '"' => { + let base = chars.as_str(); + let len = match chars.position(|c| c == '"') { + Some(pos) => pos, + None => return (Token::UnterminatedString, chars.as_str()) + }; + (Token::String(&base[..len]), chars.as_str()) + } + '-' => { + input = chars.as_str(); + if chars.next() == Some('>') { + (Token::Arrow, chars.as_str()) + } else { + (Token::Operation(cur), input) + } + } + '+' | '*' | '/' | '%' | '^' => { + (Token::Operation(cur), chars.as_str()) + } + '!' => { + if chars.next() == Some('=') { + (Token::LogicalOperation(cur), chars.as_str()) + } else { + (Token::Operation(cur), input) + } + } + '=' | '&' | '|' => { + input = chars.as_str(); + if chars.next() == Some(cur) { + (Token::LogicalOperation(cur), chars.as_str()) + } else { + (Token::Operation(cur), input) + } + } + '#' => { + match chars.position(|c| c == '\n' || c == '\r') { + Some(_) => consume_token(chars.as_str()), + None => (Token::End, chars.as_str()) + } + } + _ => (Token::Unknown(cur), chars.as_str()) + } + } +} + +#[derive(Debug)] +pub enum Error<'a> { + Unexpected(Token<'a>), + BadInteger(&'a str, std::num::ParseIntError), + BadFloat(&'a str, std::num::ParseFloatError), + BadAccessor(&'a str), + InvalidResolve(ResolveError), + UnknownImport(&'a str), + UnknownStorageClass(&'a str), + UnknownDecoration(&'a str), + UnknownBuiltin(&'a str), + UnknownPipelineStage(&'a str), + UnknownIdent(&'a str), + UnknownType(&'a str), + UnknownFunction(&'a str), + MutabilityViolation(&'a str), + Other, +} + +#[derive(Clone)] +struct Lexer<'a> { + input: &'a str, +} + +impl<'a> Lexer<'a> { + fn new(input: &'a str) -> Self { + Lexer { input } + } + + #[must_use] + fn next(&mut self) -> Token<'a> { + let (token, rest) = lex::consume_token(self.input); + self.input = rest; + token + } + + #[must_use] + fn peek(&mut self) -> Token<'a> { + self.clone().next() + } + + fn expect(&mut self, expected: Token<'a>) -> Result<(), Error<'a>> { + let token = self.next(); + if token == expected { + Ok(()) + } else { + Err(Error::Unexpected(token)) + } + } + + fn skip(&mut self, what: Token<'a>) -> bool { + let (token, rest) = lex::consume_token(self.input); + if token == what { + self.input = rest; + true + } else { + false + } + } + + fn next_ident(&mut self) -> Result<&'a str, Error<'a>> { + match self.next() { + Token::Word(word) => Ok(word), + other => Err(Error::Unexpected(other)), + } + } + + fn _next_float_literal(&mut self) -> Result> { + match self.next() { + Token::Number(word) => word.parse().map_err(|err| Error::BadFloat(word, err)), + other => Err(Error::Unexpected(other)), + } + } + + fn next_uint_literal(&mut self) -> Result> { + match self.next() { + Token::Number(word) => word.parse().map_err(|err| Error::BadInteger(word, err)), + other => Err(Error::Unexpected(other)), + } + } + + fn _next_sint_literal(&mut self) -> Result> { + match self.next() { + Token::Number(word) => word.parse().map_err(|err| Error::BadInteger(word, err)), + other => Err(Error::Unexpected(other)), + } + } + + fn next_scalar_generic(&mut self) -> Result<(crate::ScalarKind, u8), Error<'a>> { + self.expect(Token::Paren('<'))?; + let pair = match self.next() { + Token::Word("f32") => (crate::ScalarKind::Float, 32), + Token::Word("i32") => (crate::ScalarKind::Sint, 32), + Token::Word("u32") => (crate::ScalarKind::Uint, 32), + other => return Err(Error::Unexpected(other)), + }; + self.expect(Token::Paren('>'))?; + Ok(pair) + } +} + +trait StringValueLookup<'a> { + type Value; + fn lookup(&self, key: &'a str) -> Result>; +} +impl<'a> StringValueLookup<'a> for FastHashMap<&'a str, Handle> { + type Value = Handle; + fn lookup(&self, key: &'a str) -> Result> { + self.get(key) + .cloned() + .ok_or(Error::UnknownIdent(key)) + } +} + +struct StatementContext<'input, 'temp, 'out> { + lookup_ident: &'temp mut FastHashMap<&'input str, Handle>, + typifier: &'temp mut Typifier, + variables: &'out mut Arena, + expressions: &'out mut Arena, + types: &'out mut Arena, + constants: &'out mut Arena, + global_vars: &'out Arena, +} + +impl<'a> StatementContext<'a, '_, '_> { + fn reborrow(&mut self) -> StatementContext<'a, '_, '_> { + StatementContext { + lookup_ident: self.lookup_ident, + typifier: self.typifier, + variables: self.variables, + expressions: self.expressions, + types: self.types, + constants: self.constants, + global_vars: self.global_vars, + } + } + + fn as_expression(&mut self) -> ExpressionContext<'a, '_, '_> { + ExpressionContext { + lookup_ident: self.lookup_ident, + typifier: self.typifier, + expressions: self.expressions, + types: self.types, + constants: self.constants, + global_vars: self.global_vars, + local_vars: self.variables, + } + } +} + +struct ExpressionContext<'input, 'temp, 'out> { + lookup_ident: &'temp FastHashMap<&'input str, Handle>, + typifier: &'temp mut Typifier, + expressions: &'out mut Arena, + types: &'out mut Arena, + constants: &'out mut Arena, + global_vars: &'out Arena, + local_vars: &'out Arena, +} + +impl<'a> ExpressionContext<'a, '_, '_> { + fn reborrow(&mut self) -> ExpressionContext<'a, '_, '_> { + ExpressionContext { + lookup_ident: self.lookup_ident, + typifier: self.typifier, + expressions: self.expressions, + types: self.types, + constants: self.constants, + global_vars: self.global_vars, + local_vars: self.local_vars, + } + } + + fn resolve_type(&mut self, handle: Handle) -> Result, Error<'a>> { + self.typifier + .resolve(handle, self.expressions, self.types, self.constants, self.global_vars, self.local_vars) + .map_err(Error::InvalidResolve) + } + + fn parse_binary_op( + &mut self, + lexer: &mut Lexer<'a>, + classifier: impl Fn(Token<'a>) -> Option, + mut parser: impl FnMut(&mut Lexer<'a>, ExpressionContext<'a, '_, '_>) -> Result, Error<'a>>, + ) -> Result, Error<'a>> { + let mut left = parser(lexer, self.reborrow())?; + while let Some(op) = classifier(lexer.peek()) { + let _ = lexer.next(); + let expression = crate::Expression::Binary { + op, + left, + right: parser(lexer, self.reborrow())?, + }; + left = self.expressions.append(expression); + } + Ok(left) + } +} + + +#[derive(Clone, Debug, PartialEq)] +pub enum Scope { + Decoration, + ImportDecl, + VariableDecl, + TypeDecl, + FunctionDecl, + Block, + Statement, + ConstantExpr, + PrimaryExpr, + SingularExpr, + GeneralExpr, +} + +#[derive(Debug)] +pub struct ParseError<'a> { + pub error: Error<'a>, + pub scopes: Vec, + pub pos: (usize, usize), +} + +pub struct Parser { + scopes: Vec, + lookup_type: FastHashMap>, + std_namespace: Option, +} + +impl Parser { + pub fn new() -> Self { + Parser { + scopes: Vec::new(), + lookup_type: FastHashMap::default(), + std_namespace: None, + } + } + + fn get_storage_class(word: &str) -> Result> { + match word { + "in" => Ok(spirv::StorageClass::Input), + "out" => Ok(spirv::StorageClass::Output), + "uniform" => Ok(spirv::StorageClass::Uniform), + "storage_buffer" => Ok(spirv::StorageClass::StorageBuffer), + _ => Err(Error::UnknownStorageClass(word)), + } + } + + fn get_built_in(word: &str) -> Result> { + match word { + "position" => Ok(spirv::BuiltIn::Position), + "vertex_idx" => Ok(spirv::BuiltIn::VertexId), + "global_invocation_id" => Ok(spirv::BuiltIn::GlobalInvocationId), + _ => Err(Error::UnknownBuiltin(word)), + } + } + + fn get_execution_model(word: &str) -> Result> { + match word { + "vertex" => Ok(spirv::ExecutionModel::Vertex), + "fragment" => Ok(spirv::ExecutionModel::Fragment), + "compute" => Ok(spirv::ExecutionModel::GLCompute), + _ => Err(Error::UnknownPipelineStage(word)), + } + } + + fn get_constant_inner(word: &str) -> Result<(crate::ConstantInner, crate::ScalarKind), Error<'_>> { + if word.contains('.') { + word + .parse() + .map(|f|(crate::ConstantInner::Float(f), crate::ScalarKind::Float)) + .map_err(|err| Error::BadFloat(word, err)) + } else { + word + .parse() + .map(|i|(crate::ConstantInner::Sint(i), crate::ScalarKind::Sint)) + .map_err(|err| Error::BadInteger(word, err)) + } + } + + fn parse_const_expression<'a>( + &mut self, + lexer: &mut Lexer<'a>, + type_arena: &mut Arena, + const_arena: &mut Arena, + ) -> Result> { + self.scopes.push(Scope::ConstantExpr); + let inner = match lexer.peek() { + Token::Word("true") => { + let _ = lexer.next(); + crate::ConstantInner::Bool(true) + } + Token::Word("false") => { + let _ = lexer.next(); + crate::ConstantInner::Bool(false) + } + Token::Number(word) => { + let _ = lexer.next(); + let (inner, _) = Self::get_constant_inner(word)?; + inner + } + _ => { + let _ty = self.parse_type_decl(lexer, type_arena); + lexer.expect(Token::Paren('('))?; + while !lexer.skip(Token::Paren(')')) { + let _ = self.parse_const_expression(lexer, type_arena, const_arena)?; + } + unimplemented!() + } + }; + self.scopes.pop(); + Ok(inner) + } + + fn parse_primary_expression<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut ctx: ExpressionContext<'a, '_, '_>, + ) -> Result, Error<'a>> { + self.scopes.push(Scope::PrimaryExpr); + let backup = lexer.clone(); + let expression = match lexer.next() { + Token::Paren('(') => { + let expr = self.parse_general_expression(lexer, ctx)?; + lexer.expect(Token::Paren(')'))?; + self.scopes.pop(); + return Ok(expr); + } + Token::Word("true") => { + let handle = ctx.constants.fetch_or_append(crate::Constant { + name: None, + specialization: None, + inner: crate::ConstantInner::Bool(true), + ty: Typifier::deduce_type_handle( + crate::TypeInner::Scalar { + kind: crate::ScalarKind::Bool, + width: 1, + }, + ctx.types, + ) + }); + crate::Expression::Constant(handle) + } + Token::Word("false") => { + let handle = ctx.constants.fetch_or_append(crate::Constant { + name: None, + specialization: None, + inner: crate::ConstantInner::Bool(false), + ty: Typifier::deduce_type_handle( + crate::TypeInner::Scalar { + kind: crate::ScalarKind::Bool, + width: 1, + }, + ctx.types, + ) + }); + crate::Expression::Constant(handle) + } + Token::Number(word) => { + let (inner, kind) = Self::get_constant_inner(word)?; + let handle = ctx.constants.fetch_or_append(crate::Constant { + name: None, + specialization: None, + inner, + ty: Typifier::deduce_type_handle( + crate::TypeInner::Scalar { kind, width: 32 }, + ctx.types, + ) + }); + crate::Expression::Constant(handle) + } + Token::Word(word) => { + if let Some(handle) = ctx.lookup_ident.get(word) { + self.scopes.pop(); + return Ok(*handle); + } + if self.std_namespace.as_ref().map(|s| s.as_str()) == Some(word) { + lexer.expect(Token::DoubleColon)?; + let name = lexer.next_ident()?; + let mut arguments = Vec::new(); + lexer.expect(Token::Paren('('))?; + while !lexer.skip(Token::Paren(')')) { + if !arguments.is_empty() { + lexer.expect(Token::Separator(','))?; + } + let arg = self.parse_general_expression(lexer, ctx.reborrow())?; + arguments.push(arg); + } + crate::Expression::Call { + name: name.to_owned(), + arguments, + } + } else { + *lexer = backup; + let ty = self.parse_type_decl(lexer, ctx.types)?; + lexer.expect(Token::Paren('('))?; + let mut components = Vec::new(); + while !lexer.skip(Token::Paren(')')) { + if !components.is_empty() { + lexer.expect(Token::Separator(','))?; + } + let sub_expr = self.parse_general_expression(lexer, ctx.reborrow())?; + components.push(sub_expr); + } + crate::Expression::Compose { ty, components } + } + } + other => return Err(Error::Unexpected(other)), + }; + self.scopes.pop(); + Ok(ctx.expressions.append(expression)) + } + + fn parse_postfix<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut ctx: ExpressionContext<'a, '_, '_>, + mut handle: Handle, + ) -> Result, Error<'a>> { + loop { + match lexer.peek() { + Token::Separator('.') => { + let _ = lexer.next(); + let name = lexer.next_ident()?; + let type_handle = ctx.resolve_type(handle)?; + let base_type = &ctx.types[type_handle]; + let expression = match base_type.inner { + crate::TypeInner::Struct { ref members } => { + let index = members + .iter() + .position(|m| m.name.as_ref().map(|s| s.as_str()) == Some(name)) + .ok_or(Error::BadAccessor(name))? as u32; + crate::Expression::AccessIndex { + base: handle, + index, + } + } + crate::TypeInner::Vector { size, kind, width } | + crate::TypeInner::Matrix { columns: size, kind, width, .. } => { + const MEMBERS: [char; 4] = ['x', 'y', 'z', 'w']; + if name.len() > 1 { + let mut components = Vec::with_capacity(name.len()); + for ch in name.chars() { + let expr = crate::Expression::AccessIndex { + base: handle, + index: MEMBERS[.. size as usize] + .iter() + .position(|&m| m == ch) + .ok_or(Error::BadAccessor(name))? as u32, + }; + components.push(ctx.expressions.append(expr)); + } + let size = match name.len() { + 2 => crate::VectorSize::Bi, + 3 => crate::VectorSize::Tri, + 4 => crate::VectorSize::Quad, + _ => return Err(Error::BadAccessor(name)), + }; + let inner = if let crate::TypeInner::Matrix { rows, .. } = base_type.inner { + crate::TypeInner::Matrix { columns: size, rows, kind, width } + } else { + crate::TypeInner::Vector { size, kind, width } + }; + crate::Expression::Compose { + ty: Typifier::deduce_type_handle(inner, ctx.types), + components, + } + } else { + let ch = name.chars().next().unwrap(); + let index = MEMBERS[.. size as usize] + .iter() + .position(|&m| m == ch) + .ok_or(Error::BadAccessor(name))? as u32; + crate::Expression::AccessIndex { + base: handle, + index, + } + } + } + _ => return Err(Error::BadAccessor(name)), + }; + handle = ctx.expressions.append(expression); + } + Token::Paren('[') => { + let _ = lexer.next(); + let index = self.parse_general_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Paren(']'))?; + let expr = crate::Expression::Access { + base: handle, + index, + }; + handle = ctx.expressions.append(expr); + } + _ => return Ok(handle), + } + } + } + + fn parse_singular_expression<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut ctx: ExpressionContext<'a, '_, '_>, + ) -> Result, Error<'a>> { + fn get_intrinsic(word: &str) -> Option { + match word { + "any" => Some(crate::IntrinsicFunction::Any), + "all" => Some(crate::IntrinsicFunction::All), + "is_nan" => Some(crate::IntrinsicFunction::IsNan), + "is_inf" => Some(crate::IntrinsicFunction::IsInf), + "is_normal" => Some(crate::IntrinsicFunction::IsNormal), + _ => None, + } + } + fn get_derivative(word: &str) -> Option { + match word { + "dpdx" => Some(crate::DerivativeAxis::X), + "dpdy" => Some(crate::DerivativeAxis::Y), + "dwidth" => Some(crate::DerivativeAxis::Width), + _ => None, + } + } + + self.scopes.push(Scope::SingularExpr); + let backup = lexer.clone(); + let expression = match lexer.next() { + Token::Operation('-') => { + Some(crate::Expression::Unary { + op: crate::UnaryOperator::Negate, + expr: self.parse_singular_expression(lexer, ctx.reborrow())?, + }) + } + Token::Operation('!') => { + Some(crate::Expression::Unary { + op: crate::UnaryOperator::Not, + expr: self.parse_singular_expression(lexer, ctx.reborrow())?, + }) + } + Token::Word(word) => { + if let Some(fun) = get_intrinsic(word) { + lexer.expect(Token::Paren('('))?; + let argument = self.parse_primary_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Paren(')'))?; + Some(crate::Expression::Intrinsic { + fun, + argument, + }) + } else if let Some(axis) = get_derivative(word) { + lexer.expect(Token::Paren('('))?; + let expr = self.parse_primary_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Paren(')'))?; + Some(crate::Expression::Derivative { + axis, + expr, + }) + } else if word == "dot" { + lexer.expect(Token::Paren('('))?; + let a = self.parse_primary_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Separator(','))?; + let b = self.parse_primary_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Paren(')'))?; + Some(crate::Expression::DotProduct(a, b)) + } else if word == "outer_product" { + lexer.expect(Token::Paren('('))?; + let a = self.parse_primary_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Separator(','))?; + let b = self.parse_primary_expression(lexer, ctx.reborrow())?; + lexer.expect(Token::Paren(')'))?; + Some(crate::Expression::CrossProduct(a, b)) + } else { + None + } + } + _ => None, + }; + + let handle = match expression { + Some(expr) => ctx.expressions.append(expr), + None => { + *lexer = backup; + let handle = self.parse_primary_expression(lexer, ctx.reborrow())?; + self.parse_postfix(lexer, ctx, handle)? + } + }; + self.scopes.pop(); + Ok(handle) + } + + fn parse_equality_expression<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut context: ExpressionContext<'a, '_, '_>, + ) -> Result, Error<'a>> { + // equality_expression + context.parse_binary_op( + lexer, + |token| match token { + Token::LogicalOperation('=') => Some(crate::BinaryOperator::Equal), + Token::LogicalOperation('!') => Some(crate::BinaryOperator::NotEqual), + _ => None + }, + // relational_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::Paren('<') => Some(crate::BinaryOperator::Less), + Token::Paren('>') => Some(crate::BinaryOperator::Greater), + Token::LogicalOperation('<') => Some(crate::BinaryOperator::LessEqual), + Token::LogicalOperation('>') => Some(crate::BinaryOperator::GreaterEqual), + _ => None, + }, + // shift_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::ShiftOperation('<') => Some(crate::BinaryOperator::ShiftLeftLogical), + Token::ShiftOperation('>') => Some(crate::BinaryOperator::ShiftRightLogical), + Token::ArithmeticShiftOperation('>') => Some(crate::BinaryOperator::ShiftRightArithmetic), + _ => None, + }, + // additive_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::Operation('+') => Some(crate::BinaryOperator::Add), + Token::Operation('-') => Some(crate::BinaryOperator::Subtract), + _ => None, + }, + // multiplicative_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::Operation('*') => Some(crate::BinaryOperator::Multiply), + Token::Operation('/') => Some(crate::BinaryOperator::Divide), + Token::Operation('%') => Some(crate::BinaryOperator::Modulo), + _ => None, + }, + |lexer, context| self.parse_singular_expression(lexer, context), + ), + ), + ), + ), + ) + } + + fn parse_general_expression<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut context: ExpressionContext<'a, '_, '_>, + ) -> Result, Error<'a>> { + self.scopes.push(Scope::GeneralExpr); + // logical_or_expression + let handle = context.parse_binary_op( + lexer, + |token| match token { + Token::LogicalOperation('|') => Some(crate::BinaryOperator::LogicalOr), + _ => None, + }, + // logical_and_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::LogicalOperation('&') => Some(crate::BinaryOperator::LogicalAnd), + _ => None, + }, + // inclusive_or_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::Operation('|') => Some(crate::BinaryOperator::InclusiveOr), + _ => None, + }, + // exclusive_or_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::Operation('^') => Some(crate::BinaryOperator::ExclusiveOr), + _ => None, + }, + // and_expression + |lexer, mut context| context.parse_binary_op( + lexer, + |token| match token { + Token::Operation('&') => Some(crate::BinaryOperator::And), + _ => None, + }, + |lexer, context| self.parse_equality_expression(lexer, context), + ), + ), + ), + ), + )?; + self.scopes.pop(); + Ok(handle) + } + + fn parse_variable_ident_decl<'a>( + &mut self, + lexer: &mut Lexer<'a>, + type_arena: &mut Arena, + ) -> Result<(&'a str, Handle), Error<'a>> { + let name = lexer.next_ident()?; + lexer.expect(Token::Separator(':'))?; + let ty = self.parse_type_decl(lexer, type_arena)?; + Ok((name, ty)) + } + + fn parse_variable_decl<'a>( + &mut self, + lexer: &mut Lexer<'a>, + type_arena: &mut Arena, + const_arena: &mut Arena, + ) -> Result<(&'a str, Option, Handle), Error<'a>> { + self.scopes.push(Scope::VariableDecl); + let mut class = None; + if lexer.skip(Token::Paren('<')) { + let class_str = lexer.next_ident()?; + class = Some(Self::get_storage_class(class_str)?); + lexer.expect(Token::Paren('>'))?; + } + let name = lexer.next_ident()?; + lexer.expect(Token::Separator(':'))?; + let ty = self.parse_type_decl(lexer, type_arena)?; + if lexer.skip(Token::Operation('=')) { + let _inner = self.parse_const_expression(lexer, type_arena, const_arena)?; + //TODO + } + lexer.expect(Token::Separator(';'))?; + self.scopes.pop(); + Ok((name, class, ty)) + } + + fn parse_struct_body<'a>( + &mut self, + lexer: &mut Lexer<'a>, + type_arena: &mut Arena, + ) -> Result, Error<'a>> { + let mut members = Vec::new(); + lexer.expect(Token::Paren('{'))?; + loop { + if lexer.skip(Token::DoubleParen('[')) { + self.scopes.push(Scope::Decoration); + let mut ready = true; + loop { + match lexer.next() { + Token::DoubleParen(']') => { + break; + } + Token::Separator(',') if !ready => { + ready = true; + } + Token::Word("offset") if ready => { + let _offset = lexer.next_uint_literal()?; //TODO + ready = false; + } + other => return Err(Error::Unexpected(other)), + } + } + self.scopes.pop(); + } + let name = match lexer.next() { + Token::Word(word) => word, + Token::Paren('}') => return Ok(members), + other => return Err(Error::Unexpected(other)), + }; + lexer.expect(Token::Separator(':'))?; + let ty = self.parse_type_decl(lexer, type_arena)?; + lexer.expect(Token::Separator(';'))?; + members.push(crate::StructMember { + name: Some(name.to_owned()), + binding: None, + ty, + }); + } + } + + fn parse_type_decl<'a>( + &mut self, + lexer: &mut Lexer<'a>, + type_arena: &mut Arena, + ) -> Result, Error<'a>> { + self.scopes.push(Scope::TypeDecl); + let inner = match lexer.next() { + Token::Word("f32") => { + crate::TypeInner::Scalar { + kind: crate::ScalarKind::Float, + width: 32, + } + } + Token::Word("i32") => { + crate::TypeInner::Scalar { + kind: crate::ScalarKind::Sint, + width: 32, + } + } + Token::Word("u32") => { + crate::TypeInner::Scalar { + kind: crate::ScalarKind::Uint, + width: 32, + } + } + Token::Word("vec2") => { + let (kind, width) = lexer.next_scalar_generic()?; + crate::TypeInner::Vector { + size: crate::VectorSize::Bi, + kind, + width, + } + } + Token::Word("vec3") => { + let (kind, width) = lexer.next_scalar_generic()?; + crate::TypeInner::Vector { + size: crate::VectorSize::Tri, + kind, + width, + } + } + Token::Word("vec4") => { + let (kind, width) = lexer.next_scalar_generic()?; + crate::TypeInner::Vector { + size: crate::VectorSize::Quad, + kind, + width, + } + } + Token::Word("mat2x2") => { + let (kind, width) = lexer.next_scalar_generic()?; + crate::TypeInner::Matrix { + columns: crate::VectorSize::Bi, + rows: crate::VectorSize::Bi, + kind, + width, + } + } + Token::Word("mat3x3") => { + let (kind, width) = lexer.next_scalar_generic()?; + crate::TypeInner::Matrix { + columns: crate::VectorSize::Tri, + rows: crate::VectorSize::Tri, + kind, + width, + } + } + Token::Word("mat4x4") => { + let (kind, width) = lexer.next_scalar_generic()?; + crate::TypeInner::Matrix { + columns: crate::VectorSize::Quad, + rows: crate::VectorSize::Quad, + kind, + width, + } + } + Token::Word("ptr") => { + lexer.expect(Token::Paren('<'))?; + let class = Self::get_storage_class(lexer.next_ident()?)?; + lexer.expect(Token::Separator(','))?; + let base = self.parse_type_decl(lexer, type_arena)?; + lexer.expect(Token::Paren('>'))?; + crate::TypeInner::Pointer { base, class } + } + Token::Word("array") => { + lexer.expect(Token::Paren('<'))?; + let base = self.parse_type_decl(lexer, type_arena)?; + let size = match lexer.next() { + Token::Separator(',') => { + let value = lexer.next_uint_literal()?; + lexer.expect(Token::Paren('>'))?; + crate::ArraySize::Static(value) + } + Token::Separator('>') => crate::ArraySize::Dynamic, + other => return Err(Error::Unexpected(other)), + }; + crate::TypeInner::Array { base, size } + } + Token::Word("struct") => { + let members = self.parse_struct_body(lexer, type_arena)?; + crate::TypeInner::Struct { members } + } + Token::Word(name) => { + self.scopes.pop(); + return self.lookup_type + .get(name) + .cloned() + .ok_or(Error::UnknownType(name)); + } + other => return Err(Error::Unexpected(other)), + }; + self.scopes.pop(); + Ok(Typifier::deduce_type_handle(inner, type_arena)) + } + + fn parse_statement<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut context: StatementContext<'a, '_, '_>, + ) -> Result, Error<'a>> { + match lexer.next() { + Token::Separator(';') => Ok(Some(crate::Statement::Empty)), + Token::Paren('}') => Ok(None), + Token::Word(word) => { + self.scopes.push(Scope::Statement); + let statement = match word { + "var" => { + enum Init { + Empty, + Uniform(Handle), + Variable(Handle), + } + let (name, ty) = self.parse_variable_ident_decl(lexer, context.types)?; + let init = if lexer.skip(Token::Operation('=')) { + let value = self.parse_general_expression(lexer, context.as_expression())?; + if let crate::Expression::Constant(_) = context.expressions[value] { + Init::Uniform(value) + } else { + Init::Variable(value) + } + } else { + Init::Empty + }; + lexer.expect(Token::Separator(';'))?; + let var_id = context.variables.append(crate::LocalVariable { + name: Some(name.to_owned()), + ty, + init: match init { + Init::Uniform(value) => Some(value), + _ => None, + } + }); + let expr_id = context.expressions.append(crate::Expression::LocalVariable(var_id)); + context.lookup_ident.insert(name, expr_id); + match init { + Init::Variable(value) => crate::Statement::Store { pointer: expr_id, value }, + _ => crate::Statement::Empty, + } + } + "return" => { + let value = if lexer.peek() != Token::Separator(';') { + Some(self.parse_general_expression(lexer, context.as_expression())?) + } else { + None + }; + lexer.expect(Token::Separator(';'))?; + crate::Statement::Return { + value + } + } + "if" => { + lexer.expect(Token::Paren('('))?; + let condition = self.parse_general_expression(lexer, context.as_expression())?; + lexer.expect(Token::Paren(')'))?; + let accept = self.parse_block(lexer, context.reborrow())?; + let reject = if lexer.skip(Token::Word("else")) { + self.parse_block(lexer, context.reborrow())? + } else { + Vec::new() + }; + crate::Statement::If { + condition, + accept, + reject, + } + } + "loop" => { + let mut body = Vec::new(); + let mut continuing = Vec::new(); + lexer.expect(Token::Paren('{'))?; + loop { + if lexer.skip(Token::Word("continuing")) { + continuing = self.parse_block(lexer, context.reborrow())?; + lexer.expect(Token::Paren('}'))?; + break; + } + match self.parse_statement(lexer, context.reborrow())? { + Some(s) => body.push(s), + None => break, + } + } + crate::Statement::Loop { + body, + continuing + } + } + "break" => crate::Statement::Break, + "continue" => crate::Statement::Continue, + ident => { + // assignment + let var_expr = context.lookup_ident.lookup(ident)?; + let left = self.parse_postfix(lexer, context.as_expression(), var_expr)?; + lexer.expect(Token::Operation('='))?; + let value = self.parse_general_expression(lexer, context.as_expression())?; + lexer.expect(Token::Separator(';'))?; + crate::Statement::Store { + pointer: left, + value, + } + } + }; + self.scopes.pop(); + Ok(Some(statement)) + } + other => Err(Error::Unexpected(other)), + } + } + + fn parse_block<'a>( + &mut self, + lexer: &mut Lexer<'a>, + mut context: StatementContext<'a, '_, '_>, + ) -> Result, Error<'a>> { + self.scopes.push(Scope::Block); + lexer.expect(Token::Paren('{'))?; + let mut statements = Vec::new(); + while let Some(s) = self.parse_statement(lexer, context.reborrow())? { + statements.push(s); + } + self.scopes.pop(); + Ok(statements) + } + + fn parse_function_decl<'a>( + &mut self, + lexer: &mut Lexer<'a>, + module: &mut crate::Module, + lookup_global_expression: &FastHashMap<&'a str, crate::Expression>, + ) -> Result, Error<'a>> { + self.scopes.push(Scope::FunctionDecl); + // read function name + let mut lookup_ident = FastHashMap::default(); + let fun_name = lexer.next_ident()?; + // populare initial expressions + let mut expressions = Arena::new(); + for (&name, expression) in lookup_global_expression.iter() { + let expr_handle = expressions.append(expression.clone()); + lookup_ident.insert(name, expr_handle); + } + // read parameter list + let mut parameter_types = Vec::new(); + lexer.expect(Token::Paren('('))?; + while !lexer.skip(Token::Paren(')')) { + if !parameter_types.is_empty() { + lexer.expect(Token::Separator(','))?; + } + let (param_name, param_type) = self.parse_variable_ident_decl(lexer, &mut module.types)?; + let param_index = parameter_types.len() as u32; + let expression_token = expressions.append(crate::Expression::FunctionParameter(param_index)); + lookup_ident.insert(param_name, expression_token); + parameter_types.push(param_type); + } + // read return type + lexer.expect(Token::Arrow)?; + let return_type = if lexer.skip(Token::Word("void")) { + None + } else { + Some(self.parse_type_decl(lexer, &mut module.types)?) + }; + // read body + let mut local_variables = Arena::new(); + let mut typifier = Typifier::new(); + let body = self.parse_block(lexer, StatementContext { + lookup_ident: &mut lookup_ident, + typifier: &mut typifier, + variables: &mut local_variables, + expressions: &mut expressions, + types: &mut module.types, + constants: &mut module.constants, + global_vars: &module.global_variables, + })?; + // done + let global_usage = crate::GlobalUse::scan(&expressions, &body, &module.global_variables); + self.scopes.pop(); + + let fun = crate::Function { + name: Some(fun_name.to_owned()), + control: spirv::FunctionControl::empty(), + parameter_types, + return_type, + global_usage, + local_variables, + expressions, + body, + }; + Ok(module.functions.append(fun)) + } + + fn parse_global_decl<'a>( + &mut self, + lexer: &mut Lexer<'a>, + module: &mut crate::Module, + lookup_global_expression: &mut FastHashMap<&'a str, crate::Expression>, + ) -> Result> { + // read decorations + let mut binding = None; + if lexer.skip(Token::DoubleParen('[')) { + let (mut bind_index, mut bind_set) = (None, None); + self.scopes.push(Scope::Decoration); + loop { + match lexer.next_ident()? { + "location" => { + let loc = lexer.next_uint_literal()?; + binding = Some(crate::Binding::Location(loc)); + } + "builtin" => { + let builtin = Self::get_built_in(lexer.next_ident()?)?; + binding = Some(crate::Binding::BuiltIn(builtin)); + } + "binding" => { + bind_index = Some(lexer.next_uint_literal()?); + } + "set" => { + bind_set = Some(lexer.next_uint_literal()?); + } + other => return Err(Error::UnknownDecoration(other)), + } + match lexer.next() { + Token::DoubleParen(']') => { + break; + } + Token::Separator(',') => { + } + other => return Err(Error::Unexpected(other)), + } + } + match (bind_set, bind_index) { + (Some(set), Some(index)) if binding.is_none() => { + binding = Some(crate::Binding::Descriptor { set, binding: index }); + } + _ if binding.is_none() => return Err(Error::Other), + _ => {} + } + self.scopes.pop(); + } + // read items + match lexer.next() { + Token::Separator(';') => {}, + Token::Word("import") => { + self.scopes.push(Scope::ImportDecl); + let path = match lexer.next() { + Token::String(path) => path, + other => return Err(Error::Unexpected(other)), + }; + lexer.expect(Token::Word("as"))?; + let namespace = lexer.next_ident()?; + lexer.expect(Token::Separator(';'))?; + match path { + "GLSL.std.450" => { + self.std_namespace = Some(namespace.to_owned()) + } + _ => return Err(Error::UnknownImport(path)), + } + self.scopes.pop(); + } + Token::Word("type") => { + let name = lexer.next_ident()?; + lexer.expect(Token::Operation('='))?; + let ty = self.parse_type_decl(lexer, &mut module.types)?; + self.lookup_type.insert(name.to_owned(), ty); + lexer.expect(Token::Separator(';'))?; + } + Token::Word("const") => { + let (name, ty) = self.parse_variable_ident_decl(lexer, &mut module.types)?; + lexer.expect(Token::Operation('='))?; + let inner = self.parse_const_expression(lexer, &mut module.types, &mut module.constants)?; + lexer.expect(Token::Separator(';'))?; + let const_handle = module.constants.append(crate::Constant { + name: Some(name.to_owned()), + specialization: None, + inner, + ty, + }); + lookup_global_expression.insert(name, crate::Expression::Constant(const_handle)); + } + Token::Word("var") => { + let (name, class, ty) = self.parse_variable_decl(lexer, &mut module.types, &mut module.constants)?; + let var_handle = module.global_variables.append(crate::GlobalVariable { + name: Some(name.to_owned()), + class: match class { + Some(c) => c, + None => match binding { + Some(crate::Binding::BuiltIn(builtin)) => match builtin { + spirv::BuiltIn::GlobalInvocationId => spirv::StorageClass::Input, + spirv::BuiltIn::Position => spirv::StorageClass::Output, + _ => unimplemented!(), + }, + _ => spirv::StorageClass::Private, + }, + }, + binding: binding.take(), + ty, + }); + lookup_global_expression.insert(name, crate::Expression::GlobalVariable(var_handle)); + } + Token::Word("fn") => { + self.parse_function_decl(lexer, module, &lookup_global_expression)?; + } + Token::Word("entry_point") => { + let exec_model = Self::get_execution_model(lexer.next_ident()?)?; + let export_name = if lexer.skip(Token::Word("as")) { + match lexer.next() { + Token::String(name) => Some(name), + other => return Err(Error::Unexpected(other)) + } + } else { + None + }; + lexer.expect(Token::Operation('='))?; + let fun_ident = lexer.next_ident()?; + lexer.expect(Token::Separator(';'))?; + let (fun_handle, _) = module.functions + .iter() + .find(|(_, fun)| fun.name.as_ref().map(|s| s.as_str()) == Some(fun_ident)) + .ok_or(Error::UnknownFunction(fun_ident))?; + module.entry_points.push(crate::EntryPoint { + exec_model, + name: export_name.unwrap_or(fun_ident).to_owned(), + function: fun_handle, + }); + } + Token::End => return Ok(false), + token => return Err(Error::Unexpected(token)), + } + match binding { + None => Ok(true), + // we had the decoration but no var? + Some(_) => Err(Error::Other), + } + } + + pub fn parse<'a>(&mut self, source: &'a str) -> Result> { + self.scopes.clear(); + self.lookup_type.clear(); + self.std_namespace = None; + + let mut module = crate::Module::generate_empty(); + let mut lexer = Lexer::new(source); + let mut lookup_global_expression = FastHashMap::default(); + loop { + match self.parse_global_decl(&mut lexer, &mut module, &mut lookup_global_expression) { + Err(error) => { + let pos = source.len() - lexer.input.len(); + let (mut rows, mut cols) = (0, 1); + for line in source[..pos].lines() { + rows += 1; + cols = line.len(); + } + return Err(ParseError { + error, + scopes: std::mem::replace(&mut self.scopes, Vec::new()), + pos: (rows, cols), + }); + } + Ok(true) => {} + Ok(false) => { + assert_eq!(self.scopes, Vec::new()); + return Ok(module); + } + } + } + } +} + +pub fn parse_str(source: &str) -> Result { + Parser::new().parse(source) +} diff --git a/third_party/rust/naga/src/lib.rs b/third_party/rust/naga/src/lib.rs new file mode 100644 index 000000000000..8f97346e2d2a --- /dev/null +++ b/third_party/rust/naga/src/lib.rs @@ -0,0 +1,292 @@ +#![allow(clippy::new_without_default)] + +mod arena; +pub mod back; +pub mod front; +pub mod proc; + +use crate::arena::{Arena, Handle}; + +use std::{ + collections::{HashMap, HashSet}, + hash::BuildHasherDefault, +}; + + +pub type FastHashMap = HashMap>; +pub type FastHashSet = HashSet>; + +#[derive(Clone, Debug)] +pub struct Header { + pub version: (u8, u8, u8), + pub generator: u32, +} + +pub type Bytes = u8; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum VectorSize { + Bi = 2, + Tri = 3, + Quad = 4, +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ScalarKind { + Sint, + Uint, + Float, + Bool, +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ArraySize { + Static(spirv::Word), + Dynamic, +} + +#[derive(Debug, PartialEq)] +pub struct StructMember { + pub name: Option, + pub binding: Option, + pub ty: Handle, +} + +bitflags::bitflags! { + pub struct ImageFlags: u32 { + const ARRAYED = 0x1; + const MULTISAMPLED = 0x2; + const SAMPLED = 0x4; + const CAN_LOAD = 0x10; + const CAN_STORE = 0x20; + } +} + +#[derive(Debug)] +pub struct Type { + pub name: Option, + pub inner: TypeInner, +} + +#[derive(Debug, PartialEq)] +pub enum TypeInner { + Scalar { kind: ScalarKind, width: Bytes }, + Vector { size: VectorSize, kind: ScalarKind, width: Bytes }, + Matrix { columns: VectorSize, rows: VectorSize, kind: ScalarKind, width: Bytes }, + Pointer { base: Handle, class: spirv::StorageClass }, + Array { base: Handle, size: ArraySize }, + Struct { members: Vec }, + Image { base: Handle, dim: spirv::Dim, flags: ImageFlags }, + Sampler, +} + +#[derive(Debug, PartialEq)] +pub struct Constant { + pub name: Option, + pub specialization: Option, + pub inner: ConstantInner, + pub ty: Handle, +} + +#[derive(Debug, PartialEq)] +pub enum ConstantInner { + Sint(i64), + Uint(u64), + Float(f64), + Bool(bool), + Composite(Vec>), +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Binding { + BuiltIn(spirv::BuiltIn), + Location(spirv::Word), + Descriptor { set: spirv::Word, binding: spirv::Word }, +} + +bitflags::bitflags! { + pub struct GlobalUse: u8 { + const LOAD = 0x1; + const STORE = 0x2; + } +} + +#[derive(Clone, Debug)] +pub struct GlobalVariable { + pub name: Option, + pub class: spirv::StorageClass, + pub binding: Option, + pub ty: Handle, +} + +#[derive(Clone, Debug)] +pub struct LocalVariable { + pub name: Option, + pub ty: Handle, + pub init: Option>, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum UnaryOperator { + Negate, + Not, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BinaryOperator { + Add, + Subtract, + Multiply, + Divide, + Modulo, + Equal, + NotEqual, + Less, + LessEqual, + Greater, + GreaterEqual, + And, + ExclusiveOr, + InclusiveOr, + LogicalAnd, + LogicalOr, + ShiftLeftLogical, + ShiftRightLogical, + ShiftRightArithmetic, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum IntrinsicFunction { + Any, + All, + IsNan, + IsInf, + IsFinite, + IsNormal, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum DerivativeAxis { + X, + Y, + Width, +} + +#[derive(Clone, Debug)] +pub enum Expression { + Access { + base: Handle, + index: Handle, //int + }, + AccessIndex { + base: Handle, + index: u32, + }, + Constant(Handle), + Compose { + ty: Handle, + components: Vec>, + }, + FunctionParameter(u32), + GlobalVariable(Handle), + LocalVariable(Handle), + Load { + pointer: Handle, + }, + ImageSample { + image: Handle, + sampler: Handle, + coordinate: Handle, + }, + Unary { + op: UnaryOperator, + expr: Handle, + }, + Binary { + op: BinaryOperator, + left: Handle, + right: Handle, + }, + Intrinsic { + fun: IntrinsicFunction, + argument: Handle, + }, + DotProduct(Handle, Handle), + CrossProduct(Handle, Handle), + Derivative { + axis: DerivativeAxis, + //modifier, + expr: Handle, + }, + Call { + name: String, + arguments: Vec>, + }, +} + +pub type Block = Vec; +#[derive(Debug)] +pub struct FallThrough; + +#[derive(Debug)] +pub enum Statement { + Empty, + Block(Block), + If { + condition: Handle, //bool + accept: Block, + reject: Block, + }, + Switch { + selector: Handle, //int + cases: FastHashMap)>, + default: Block, + }, + Loop { + body: Block, + continuing: Block, + }, + //TODO: move terminator variations into a separate enum? + Break, + Continue, + Return { + value: Option>, + }, + Kill, + Store { + pointer: Handle, + value: Handle, + }, +} + +#[derive(Debug)] +pub struct Function { + pub name: Option, + pub control: spirv::FunctionControl, + pub parameter_types: Vec>, + pub return_type: Option>, + pub global_usage: Vec, + pub local_variables: Arena, + pub expressions: Arena, + pub body: Block, +} + +#[derive(Debug)] +pub struct EntryPoint { + pub exec_model: spirv::ExecutionModel, + pub name: String, + pub function: Handle, +} + +#[derive(Debug)] +pub struct Module { + pub header: Header, + pub types: Arena, + pub constants: Arena, + pub global_variables: Arena, + pub functions: Arena, + pub entry_points: Vec, +} diff --git a/third_party/rust/naga/src/proc/interface.rs b/third_party/rust/naga/src/proc/interface.rs new file mode 100644 index 000000000000..9522ac981b36 --- /dev/null +++ b/third_party/rust/naga/src/proc/interface.rs @@ -0,0 +1,139 @@ +use crate::{ + arena::{Arena, Handle}, +}; + +struct Interface<'a> { + expressions: &'a Arena, + uses: Vec, +} + +impl<'a> Interface<'a> { + fn add_inputs(&mut self, handle: Handle) { + use crate::Expression as E; + match self.expressions[handle] { + E::Access { base, index } => { + self.add_inputs(base); + self.add_inputs(index); + } + E::AccessIndex { base, .. } => { + self.add_inputs(base); + } + E::Constant(_) => {} + E::Compose { ref components, .. } => { + for &comp in components { + self.add_inputs(comp); + } + } + E::FunctionParameter(_) => {}, + E::GlobalVariable(handle) => { + self.uses[handle.index()] |= crate::GlobalUse::LOAD; + } + E::LocalVariable(_) => {} + E::Load { pointer } => { + self.add_inputs(pointer); + } + E::ImageSample { image, sampler, coordinate } => { + self.add_inputs(image); + self.add_inputs(sampler); + self.add_inputs(coordinate); + } + E::Unary { expr, .. } => { + self.add_inputs(expr); + } + E::Binary { left, right, .. } => { + self.add_inputs(left); + self.add_inputs(right); + } + E::Intrinsic { argument, .. } => { + self.add_inputs(argument); + } + E::DotProduct(left, right) => { + self.add_inputs(left); + self.add_inputs(right); + } + E::CrossProduct(left, right) => { + self.add_inputs(left); + self.add_inputs(right); + } + E::Derivative { expr, .. } => { + self.add_inputs(expr); + } + E::Call { ref arguments, .. } => { + for &argument in arguments { + self.add_inputs(argument); + } + } + } + } + + fn collect(&mut self, block: &[crate::Statement]) { + for statement in block { + use crate::Statement as S; + match *statement { + S::Empty | + S::Break | + S::Continue | + S::Kill => (), + S::Block(ref b) => { + self.collect(b); + } + S::If { condition, ref accept, ref reject } => { + self.add_inputs(condition); + self.collect(accept); + self.collect(reject); + } + S::Switch { selector, ref cases, ref default } => { + self.add_inputs(selector); + for &(ref case, _) in cases.values() { + self.collect(case); + } + self.collect(default); + } + S::Loop { ref body, ref continuing } => { + self.collect(body); + self.collect(continuing); + } + S::Return { value } => { + if let Some(expr) = value { + self.add_inputs(expr); + } + } + S::Store { pointer, value } => { + let mut left = pointer; + loop { + match self.expressions[left] { + crate::Expression::Access { base, index } => { + self.add_inputs(index); + left = base; + } + crate::Expression::AccessIndex { base, .. } => { + left = base; + } + crate::Expression::GlobalVariable(handle) => { + self.uses[handle.index()] |= crate::GlobalUse::STORE; + break; + } + _ => break, + } + } + self.add_inputs(value); + } + } + } + } +} + +impl crate::GlobalUse { + pub fn scan( + expressions: &Arena, + body: &[crate::Statement], + globals: &Arena, + ) -> Vec { + let mut io = Interface { + expressions, + uses: vec![crate::GlobalUse::empty(); globals.len()], + }; + io.collect(body); + io.uses + } +} diff --git a/third_party/rust/naga/src/proc/mod.rs b/third_party/rust/naga/src/proc/mod.rs new file mode 100644 index 000000000000..cb78f765fd32 --- /dev/null +++ b/third_party/rust/naga/src/proc/mod.rs @@ -0,0 +1,4 @@ +mod interface; +mod typifier; + +pub use typifier::{ResolveError, Typifier}; diff --git a/third_party/rust/naga/src/proc/typifier.rs b/third_party/rust/naga/src/proc/typifier.rs new file mode 100644 index 000000000000..700a6b32f922 --- /dev/null +++ b/third_party/rust/naga/src/proc/typifier.rs @@ -0,0 +1,155 @@ +use crate::arena::{Arena, Handle}; + +pub struct Typifier { + types: Vec>, +} + +#[derive(Debug)] +pub enum ResolveError { + InvalidAccessIndex, +} + +impl Typifier { + pub fn new() -> Self { + Typifier { + types: Vec::new(), + } + } + + pub fn resolve( + &mut self, + expr_handle: Handle, + expressions: &Arena, + types: &mut Arena, + constants: &Arena, + global_vars: &Arena, + local_vars: &Arena, + ) -> Result, ResolveError> { + if self.types.len() <= expr_handle.index() { + for (eh, expr) in expressions.iter().skip(self.types.len()) { + let ty = match *expr { + crate::Expression::Access { base, .. } => { + match types[self.types[base.index()]].inner { + crate::TypeInner::Array { base, .. } => base, + ref other => panic!("Can't access into {:?}", other), + } + } + crate::Expression::AccessIndex { base, index } => { + match types[self.types[base.index()]].inner { + crate::TypeInner::Vector { size, kind, width } => { + if index >= size as u32 { + return Err(ResolveError::InvalidAccessIndex) + } + let inner = crate::TypeInner::Scalar { kind, width }; + Self::deduce_type_handle(inner, types) + } + crate::TypeInner::Matrix { columns, rows, kind, width } => { + if index >= columns as u32 { + return Err(ResolveError::InvalidAccessIndex) + } + let inner = crate::TypeInner::Vector { size: rows, kind, width }; + Self::deduce_type_handle(inner, types) + } + crate::TypeInner::Array { base, .. } => base, + crate::TypeInner::Struct { ref members } => { + members.get(index as usize) + .ok_or(ResolveError::InvalidAccessIndex)? + .ty + } + ref other => panic!("Can't access into {:?}", other), + } + } + crate::Expression::Constant(h) => constants[h].ty, + crate::Expression::Compose { ty, .. } => ty, + crate::Expression::FunctionParameter(_) => unimplemented!(), + crate::Expression::GlobalVariable(h) => global_vars[h].ty, + crate::Expression::LocalVariable(h) => local_vars[h].ty, + crate::Expression::Load { .. } => unimplemented!(), + crate::Expression::ImageSample { .. } => unimplemented!(), + crate::Expression::Unary { expr, .. } => self.types[expr.index()], + crate::Expression::Binary { op, left, right } => { + match op { + crate::BinaryOperator::Add | + crate::BinaryOperator::Subtract | + crate::BinaryOperator::Divide | + crate::BinaryOperator::Modulo => { + self.types[left.index()] + } + crate::BinaryOperator::Multiply => { + let ty_left = self.types[left.index()]; + let ty_right = self.types[right.index()]; + if ty_left == ty_right { + ty_left + } else if let crate::TypeInner::Scalar { .. } = types[ty_right].inner { + ty_left + } else if let crate::TypeInner::Matrix { columns, kind, width, .. } = types[ty_left].inner { + let inner = crate::TypeInner::Vector { size: columns, kind, width}; + Self::deduce_type_handle(inner, types) + } else { + panic!("Incompatible arguments {:?} x {:?}", types[ty_left], types[ty_right]); + } + } + crate::BinaryOperator::Equal | + crate::BinaryOperator::NotEqual | + crate::BinaryOperator::Less | + crate::BinaryOperator::LessEqual | + crate::BinaryOperator::Greater | + crate::BinaryOperator::GreaterEqual | + crate::BinaryOperator::LogicalAnd | + crate::BinaryOperator::LogicalOr => { + self.types[left.index()] + } + crate::BinaryOperator::And | + crate::BinaryOperator::ExclusiveOr | + crate::BinaryOperator::InclusiveOr | + crate::BinaryOperator::ShiftLeftLogical | + crate::BinaryOperator::ShiftRightLogical | + crate::BinaryOperator::ShiftRightArithmetic => { + self.types[left.index()] + } + } + } + crate::Expression::Intrinsic { .. } => unimplemented!(), + crate::Expression::DotProduct(_, _) => unimplemented!(), + crate::Expression::CrossProduct(_, _) => unimplemented!(), + crate::Expression::Derivative { .. } => unimplemented!(), + crate::Expression::Call { ref name, ref arguments } => { + match name.as_str() { + "distance" | "length" => { + let ty_handle = self.types[arguments[0].index()]; + let inner = match types[ty_handle].inner { + crate::TypeInner::Vector { kind, width, .. } => { + crate::TypeInner::Scalar { kind, width } + } + ref other => panic!("Unexpected argument {:?}", other), + }; + Self::deduce_type_handle(inner, types) + } + "normalize" | "fclamp" => self.types[arguments[0].index()], + _ => panic!("Unknown '{}' call", name), + } + } + }; + log::debug!("Resolving {:?} = {:?} : {:?}", eh, expr, ty); + self.types.push(ty); + }; + } + Ok(self.types[expr_handle.index()]) + } + + pub fn deduce_type_handle( + inner: crate::TypeInner, + arena: &mut Arena, + ) -> Handle { + if let Some((token, _)) = arena + .iter() + .find(|(_, ty)| ty.inner == inner) + { + return token; + } + arena.append(crate::Type { + name: None, + inner, + }) + } +} diff --git a/third_party/rust/naga/test-data/boids.ron b/third_party/rust/naga/test-data/boids.ron new file mode 100644 index 000000000000..db17ca341080 --- /dev/null +++ b/third_party/rust/naga/test-data/boids.ron @@ -0,0 +1,7 @@ +( + metal_bindings: { + (set: 0, binding: 0): (buffer: Some(0), texture: None, sampler: None, mutable: false), + (set: 0, binding: 1): (buffer: Some(1), texture: None, sampler: None, mutable: true), + (set: 0, binding: 2): (buffer: Some(2), texture: None, sampler: None, mutable: true), + } +) diff --git a/third_party/rust/naga/test-data/boids.wgsl b/third_party/rust/naga/test-data/boids.wgsl new file mode 100644 index 000000000000..c7dc9a29a16b --- /dev/null +++ b/third_party/rust/naga/test-data/boids.wgsl @@ -0,0 +1,152 @@ +# Copyright 2020 The Tint Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import "GLSL.std.450" as std; + +# vertex shader + +[[location 0]] var a_particlePos : vec2; +[[location 1]] var a_particleVel : vec2; +[[location 2]] var a_pos : vec2; +[[builtin position]] var gl_Position : vec4; + +fn vtx_main() -> void { + var angle : f32 = -std::atan2(a_particleVel.x, a_particleVel.y); + var pos : vec2 = vec2( + (a_pos.x * std::cos(angle)) - (a_pos.y * std::sin(angle)), + (a_pos.x * std::sin(angle)) + (a_pos.y * std::cos(angle))); + gl_Position = vec4(pos + a_particlePos, 0, 1); + return; +} +entry_point vertex as "main" = vtx_main; + +# fragment shader +[[location 0]] var fragColor : vec4; + +fn frag_main() -> void { + fragColor = vec4(1.0, 1.0, 1.0, 1.0); + return; +} +entry_point fragment as "main" = frag_main; + +# compute shader +type Particle = struct { + [[offset 0]] pos : vec2; + [[offset 8]] vel : vec2; +}; + +type SimParams = struct { + [[offset 0]] deltaT : f32; + [[offset 4]] rule1Distance : f32; + [[offset 8]] rule2Distance : f32; + [[offset 12]] rule3Distance : f32; + [[offset 16]] rule1Scale : f32; + [[offset 20]] rule2Scale : f32; + [[offset 24]] rule3Scale : f32; +}; + +type Particles = struct { + [[offset 0]] particles : array; +}; + +[[binding 0, set 0]] var params : SimParams; +[[binding 1, set 0]] var particlesA : Particles; +[[binding 2, set 0]] var particlesB : Particles; + +[[builtin global_invocation_id]] var gl_GlobalInvocationID : vec3; + +# https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp +fn compute_main() -> void { + var index : u32 = gl_GlobalInvocationID.x; + if (index >= 5) { + return; + } + + var vPos : vec2 = particlesA.particles[index].pos; + var vVel : vec2 = particlesA.particles[index].vel; + + var cMass : vec2 = vec2(0, 0); + var cVel : vec2 = vec2(0, 0); + var colVel : vec2 = vec2(0, 0); + var cMassCount : i32 = 0; + var cVelCount : i32 = 0; + + var pos : vec2; + var vel : vec2; + var i : u32 = 0; + loop { + if (i >= 5) { + break; + } + if (i == index) { + continue; + } + + pos = particlesA.particles[i].pos.xy; + vel = particlesA.particles[i].vel.xy; + + if (std::distance(pos, vPos) < params.rule1Distance) { + cMass = cMass + pos; + cMassCount = cMassCount + 1; + } + if (std::distance(pos, vPos) < params.rule2Distance) { + colVel = colVel - (pos - vPos); + } + if (std::distance(pos, vPos) < params.rule3Distance) { + cVel = cVel + vel; + cVelCount = cVelCount + 1; + } + + continuing { + i = i + 1; + } + } + if (cMassCount > 0) { + cMass = (cMass / vec2(cMassCount, cMassCount)) + vPos; + } + if (cVelCount > 0) { + cVel = cVel / vec2(cVelCount, cVelCount); + } + + vVel = vVel + (cMass * params.rule1Scale) + (colVel * params.rule2Scale) + + (cVel * params.rule3Scale); + + # clamp velocity for a more pleasing simulation + vVel = std::normalize(vVel) * std::fclamp(std::length(vVel), 0.0, 0.1); + + # kinematic update + vPos = vPos + (vVel * params.deltaT); + + # Wrap around boundary + if (vPos.x < -1.0) { + vPos.x = 1.0; + } + if (vPos.x > 1.0) { + vPos.x = -1.0; + } + if (vPos.y < -1.0) { + vPos.y = 1.0; + } + if (vPos.y > 1.0) { + vPos.y = -1.0; + } + + # Write back + particlesB.particles[index].pos = vPos; + particlesB.particles[index].vel = vVel; + + return; +} +entry_point compute as "main" = compute_main; + diff --git a/third_party/rust/naga/test-data/quad.wgsl b/third_party/rust/naga/test-data/quad.wgsl new file mode 100644 index 000000000000..2666ea1e747d --- /dev/null +++ b/third_party/rust/naga/test-data/quad.wgsl @@ -0,0 +1,24 @@ +# vertex +const c_scale: f32 = 1.2; +[[location 0]] var a_pos : vec2; +[[location 1]] var a_uv : vec2; +[[location 0]] var v_uv : vec2; +[[builtin position]] var o_position : vec4; + +fn main_vert() -> void { + o_position = vec4(c_scale * a_pos, 0.0, 1.0); + return; +} +entry_point vertex as "main" = main_vert; + +# fragment +[[location 0]] var a_uv : vec2; +#layout(set = 0, binding = 0) uniform texture2D u_texture; +#layout(set = 0, binding = 1) uniform sampler u_sampler; +[[location 0]] var o_color : vec4; + +fn main_frag() -> void { + o_color = vec4(1, 0, 0, 1); #TODO: sample + return; +} +entry_point fragment as "main" = main_frag; diff --git a/third_party/rust/naga/tests/convert.rs b/third_party/rust/naga/tests/convert.rs new file mode 100644 index 000000000000..4150ed824291 --- /dev/null +++ b/third_party/rust/naga/tests/convert.rs @@ -0,0 +1,51 @@ +fn load_wgsl(name: &str) -> naga::Module { + let path = format!("{}/test-data/{}.wgsl", env!("CARGO_MANIFEST_DIR"), name); + let input = std::fs::read_to_string(path).unwrap(); + naga::front::wgsl::parse_str(&input).unwrap() +} + +#[test] +fn convert_quad() { + let module = load_wgsl("quad"); + { + use naga::back::msl; + let mut binding_map = msl::BindingMap::default(); + binding_map.insert( + msl::BindSource { set: 0, binding: 0 }, + msl::BindTarget { buffer: None, texture: Some(1), sampler: None, mutable: false }, + ); + binding_map.insert( + msl::BindSource { set: 0, binding: 1 }, + msl::BindTarget { buffer: None, texture: None, sampler: Some(1), mutable: false }, + ); + let options = msl::Options { + binding_map: &binding_map, + }; + msl::write_string(&module, options).unwrap(); + } +} + +#[test] +fn convert_boids() { + let module = load_wgsl("boids"); + { + use naga::back::msl; + let mut binding_map = msl::BindingMap::default(); + binding_map.insert( + msl::BindSource { set: 0, binding: 0 }, + msl::BindTarget { buffer: Some(0), texture: None, sampler: None, mutable: false }, + ); + binding_map.insert( + msl::BindSource { set: 0, binding: 1 }, + msl::BindTarget { buffer: Some(1), texture: None, sampler: Some(1), mutable: false }, + ); + binding_map.insert( + msl::BindSource { set: 0, binding: 2 }, + msl::BindTarget { buffer: Some(2), texture: None, sampler: Some(1), mutable: false }, + ); + let options = msl::Options { + binding_map: &binding_map, + }; + msl::write_string(&module, options).unwrap(); + } +} diff --git a/third_party/rust/spirv_headers/.cargo-checksum.json b/third_party/rust/spirv_headers/.cargo-checksum.json new file mode 100644 index 000000000000..45122f626343 --- /dev/null +++ b/third_party/rust/spirv_headers/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"a7fb396d7d75f52e15338f5fb389c1d10ef51e4f5bc24c1d6ab834248f2b7efd","README.md":"e6b0558fda2d831b1c291a773fd2baee3c2e835f2d76952de927b9e455bf0fc9","autogen_spirv.rs":"eec69221ce0b44a06aa0dc44dbff1af974f1fd7530fee02e02badd2edaf15071","lib.rs":"968a4b6b083e283b530271cc2cc13d6c69793877647694a15636c0fbecd1bf58"},"package":"3f1418983d16481227ffa3ab3cf44ef92eebc9a76c092fbcd4c51a64ff032622"} \ No newline at end of file diff --git a/third_party/rust/spirv_headers/Cargo.toml b/third_party/rust/spirv_headers/Cargo.toml new file mode 100644 index 000000000000..46ebde9223d7 --- /dev/null +++ b/third_party/rust/spirv_headers/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "spirv_headers" +version = "1.4.2" +authors = ["Lei Zhang "] +description = "Rust definition of SPIR-V structs and enums" +documentation = "https://docs.rs/spirv_headers" +readme = "README.md" +keywords = ["spirv", "definition", "struct", "enum"] +license = "Apache-2.0" +repository = "https://github.com/gfx-rs/rspirv" + +[lib] +path = "lib.rs" +[dependencies.bitflags] +version = "1" + +[dependencies.num-traits] +version = "0.2" diff --git a/third_party/rust/spirv_headers/README.md b/third_party/rust/spirv_headers/README.md new file mode 100644 index 000000000000..e8b7383ac29e --- /dev/null +++ b/third_party/rust/spirv_headers/README.md @@ -0,0 +1,50 @@ +spirv-headers of the rspirv project +=================================== + +[![Crate][img-crate-headers]][crate-headers] +[![Documentation][img-doc-headers]][doc-headers] + +The headers crate for the rspirv project which provides Rust definitions of +SPIR-V structs, enums, and constants. + +Usage +----- + +This project uses associated constants, which became available in the stable channel +since [1.20][rust-1.20]. So to compile with a compiler from the stable channel, +please make sure that the version is >= 1.20. + +First add to your `Cargo.toml`: + +```toml +[dependencies] +rspirv_headers = "1.4" +``` + +Then add to your crate root: + +```rust +extern crate spirv_headers; +``` + +Version +------- + +Note that the major and minor version of this create is tracking the SPIR-V spec, +while the patch number is used for bugfixes for the crate itself. So version +`1.4.2` is tracking SPIR-V 1.4 but not necessarily revision 2. Major client APIs +like Vulkan/OpenCL pin to a specific major and minor version, regardless of the +revision. + +Examples +-------- + +Please see the [documentation][doc-headers] and project's +[README][project-readme] for examples. + +[img-crate-headers]: https://img.shields.io/crates/v/spirv_headers.svg +[img-doc-headers]: https://docs.rs/spirv_headers/badge.svg +[crate-headers]: https://crates.io/crates/spirv_headers +[doc-headers]: https://docs.rs/spirv_headers +[project-readme]: https://github.com/gfx-rs/rspirv/blob/master/README.md +[rust-1.20]: https://blog.rust-lang.org/2017/08/31/Rust-1.20.html diff --git a/third_party/rust/spirv_headers/autogen_spirv.rs b/third_party/rust/spirv_headers/autogen_spirv.rs new file mode 100644 index 000000000000..66820ec33c0e --- /dev/null +++ b/third_party/rust/spirv_headers/autogen_spirv.rs @@ -0,0 +1,3645 @@ +// AUTOMATICALLY GENERATED from the SPIR-V JSON grammar: +// external/spirv.core.grammar.json. +// DO NOT MODIFY! + +pub type Word = u32; +pub const MAGIC_NUMBER: u32 = 0x07230203; +pub const MAJOR_VERSION: u8 = 1u8; +pub const MINOR_VERSION: u8 = 4u8; +pub const REVISION: u8 = 1u8; +bitflags! { # [ doc = "SPIR-V operand kind: [ImageOperands](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_image_operands_a_image_operands)" ] pub struct ImageOperands : u32 { const NONE = 0u32 ; const BIAS = 1u32 ; const LOD = 2u32 ; const GRAD = 4u32 ; const CONST_OFFSET = 8u32 ; const OFFSET = 16u32 ; const CONST_OFFSETS = 32u32 ; const SAMPLE = 64u32 ; const MIN_LOD = 128u32 ; const MAKE_TEXEL_AVAILABLE_KHR = 256u32 ; const MAKE_TEXEL_VISIBLE_KHR = 512u32 ; const NON_PRIVATE_TEXEL_KHR = 1024u32 ; const VOLATILE_TEXEL_KHR = 2048u32 ; const SIGN_EXTEND = 4096u32 ; const ZERO_EXTEND = 8192u32 ; } } +bitflags! { # [ doc = "SPIR-V operand kind: [FPFastMathMode](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_fp_fast_math_mode_a_fp_fast_math_mode)" ] pub struct FPFastMathMode : u32 { const NONE = 0u32 ; const NOT_NAN = 1u32 ; const NOT_INF = 2u32 ; const NSZ = 4u32 ; const ALLOW_RECIP = 8u32 ; const FAST = 16u32 ; } } +bitflags! { # [ doc = "SPIR-V operand kind: [SelectionControl](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_selection_control_a_selection_control)" ] pub struct SelectionControl : u32 { const NONE = 0u32 ; const FLATTEN = 1u32 ; const DONT_FLATTEN = 2u32 ; } } +bitflags! { # [ doc = "SPIR-V operand kind: [LoopControl](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_loop_control_a_loop_control)" ] pub struct LoopControl : u32 { const NONE = 0u32 ; const UNROLL = 1u32 ; const DONT_UNROLL = 2u32 ; const DEPENDENCY_INFINITE = 4u32 ; const DEPENDENCY_LENGTH = 8u32 ; const MIN_ITERATIONS = 16u32 ; const MAX_ITERATIONS = 32u32 ; const ITERATION_MULTIPLE = 64u32 ; const PEEL_COUNT = 128u32 ; const PARTIAL_COUNT = 256u32 ; } } +bitflags! { # [ doc = "SPIR-V operand kind: [FunctionControl](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_function_control_a_function_control)" ] pub struct FunctionControl : u32 { const NONE = 0u32 ; const INLINE = 1u32 ; const DONT_INLINE = 2u32 ; const PURE = 4u32 ; const CONST = 8u32 ; } } +bitflags! { # [ doc = "SPIR-V operand kind: [MemorySemantics](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_memory_semantics_a_memory_semantics)" ] pub struct MemorySemantics : u32 { const RELAXED = 0u32 ; const NONE = 0u32 ; const ACQUIRE = 2u32 ; const RELEASE = 4u32 ; const ACQUIRE_RELEASE = 8u32 ; const SEQUENTIALLY_CONSISTENT = 16u32 ; const UNIFORM_MEMORY = 64u32 ; const SUBGROUP_MEMORY = 128u32 ; const WORKGROUP_MEMORY = 256u32 ; const CROSS_WORKGROUP_MEMORY = 512u32 ; const ATOMIC_COUNTER_MEMORY = 1024u32 ; const IMAGE_MEMORY = 2048u32 ; const OUTPUT_MEMORY_KHR = 4096u32 ; const MAKE_AVAILABLE_KHR = 8192u32 ; const MAKE_VISIBLE_KHR = 16384u32 ; } } +bitflags! { # [ doc = "SPIR-V operand kind: [MemoryAccess](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_memory_access_a_memory_access)" ] pub struct MemoryAccess : u32 { const NONE = 0u32 ; const VOLATILE = 1u32 ; const ALIGNED = 2u32 ; const NONTEMPORAL = 4u32 ; const MAKE_POINTER_AVAILABLE_KHR = 8u32 ; const MAKE_POINTER_VISIBLE_KHR = 16u32 ; const NON_PRIVATE_POINTER_KHR = 32u32 ; } } +bitflags! { # [ doc = "SPIR-V operand kind: [KernelProfilingInfo](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_kernel_profiling_info_a_kernel_profiling_info)" ] pub struct KernelProfilingInfo : u32 { const NONE = 0u32 ; const CMD_EXEC_TIME = 1u32 ; } } +#[doc = "/// SPIR-V operand kind: [SourceLanguage](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_source_language_a_source_language)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SourceLanguage { + Unknown = 0u32, + ESSL = 1u32, + GLSL = 2u32, + OpenCL_C = 3u32, + OpenCL_CPP = 4u32, + HLSL = 5u32, +} +#[allow(non_upper_case_globals)] +impl SourceLanguage { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + SourceLanguage::Unknown + | SourceLanguage::ESSL + | SourceLanguage::GLSL + | SourceLanguage::OpenCL_C + | SourceLanguage::OpenCL_CPP + | SourceLanguage::HLSL => &[], + } + } +} +impl num_traits::FromPrimitive for SourceLanguage { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => SourceLanguage::Unknown, + 1u32 => SourceLanguage::ESSL, + 2u32 => SourceLanguage::GLSL, + 3u32 => SourceLanguage::OpenCL_C, + 4u32 => SourceLanguage::OpenCL_CPP, + 5u32 => SourceLanguage::HLSL, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [ExecutionModel](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_execution_model_a_execution_model)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ExecutionModel { + Vertex = 0u32, + TessellationControl = 1u32, + TessellationEvaluation = 2u32, + Geometry = 3u32, + Fragment = 4u32, + GLCompute = 5u32, + Kernel = 6u32, + TaskNV = 5267u32, + MeshNV = 5268u32, + RayGenerationNV = 5313u32, + IntersectionNV = 5314u32, + AnyHitNV = 5315u32, + ClosestHitNV = 5316u32, + MissNV = 5317u32, + CallableNV = 5318u32, +} +#[allow(non_upper_case_globals)] +impl ExecutionModel { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + ExecutionModel::Geometry => &[Capability::Geometry], + ExecutionModel::Kernel => &[Capability::Kernel], + ExecutionModel::TaskNV | ExecutionModel::MeshNV => &[Capability::MeshShadingNV], + ExecutionModel::RayGenerationNV + | ExecutionModel::IntersectionNV + | ExecutionModel::AnyHitNV + | ExecutionModel::ClosestHitNV + | ExecutionModel::MissNV + | ExecutionModel::CallableNV => &[Capability::RayTracingNV], + ExecutionModel::Vertex | ExecutionModel::Fragment | ExecutionModel::GLCompute => { + &[Capability::Shader] + } + ExecutionModel::TessellationControl | ExecutionModel::TessellationEvaluation => { + &[Capability::Tessellation] + } + } + } +} +impl num_traits::FromPrimitive for ExecutionModel { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => ExecutionModel::Vertex, + 1u32 => ExecutionModel::TessellationControl, + 2u32 => ExecutionModel::TessellationEvaluation, + 3u32 => ExecutionModel::Geometry, + 4u32 => ExecutionModel::Fragment, + 5u32 => ExecutionModel::GLCompute, + 6u32 => ExecutionModel::Kernel, + 5267u32 => ExecutionModel::TaskNV, + 5268u32 => ExecutionModel::MeshNV, + 5313u32 => ExecutionModel::RayGenerationNV, + 5314u32 => ExecutionModel::IntersectionNV, + 5315u32 => ExecutionModel::AnyHitNV, + 5316u32 => ExecutionModel::ClosestHitNV, + 5317u32 => ExecutionModel::MissNV, + 5318u32 => ExecutionModel::CallableNV, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [AddressingModel](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_addressing_model_a_addressing_model)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum AddressingModel { + Logical = 0u32, + Physical32 = 1u32, + Physical64 = 2u32, + PhysicalStorageBuffer64EXT = 5348u32, +} +#[allow(non_upper_case_globals)] +impl AddressingModel { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + AddressingModel::Logical => &[], + AddressingModel::Physical32 | AddressingModel::Physical64 => &[Capability::Addresses], + AddressingModel::PhysicalStorageBuffer64EXT => { + &[Capability::PhysicalStorageBufferAddressesEXT] + } + } + } +} +impl num_traits::FromPrimitive for AddressingModel { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => AddressingModel::Logical, + 1u32 => AddressingModel::Physical32, + 2u32 => AddressingModel::Physical64, + 5348u32 => AddressingModel::PhysicalStorageBuffer64EXT, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [MemoryModel](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_memory_model_a_memory_model)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum MemoryModel { + Simple = 0u32, + GLSL450 = 1u32, + OpenCL = 2u32, + VulkanKHR = 3u32, +} +#[allow(non_upper_case_globals)] +impl MemoryModel { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + MemoryModel::OpenCL => &[Capability::Kernel], + MemoryModel::Simple | MemoryModel::GLSL450 => &[Capability::Shader], + MemoryModel::VulkanKHR => &[Capability::VulkanMemoryModelKHR], + } + } +} +impl num_traits::FromPrimitive for MemoryModel { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => MemoryModel::Simple, + 1u32 => MemoryModel::GLSL450, + 2u32 => MemoryModel::OpenCL, + 3u32 => MemoryModel::VulkanKHR, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [ExecutionMode](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_execution_mode_a_execution_mode)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ExecutionMode { + Invocations = 0u32, + SpacingEqual = 1u32, + SpacingFractionalEven = 2u32, + SpacingFractionalOdd = 3u32, + VertexOrderCw = 4u32, + VertexOrderCcw = 5u32, + PixelCenterInteger = 6u32, + OriginUpperLeft = 7u32, + OriginLowerLeft = 8u32, + EarlyFragmentTests = 9u32, + PointMode = 10u32, + Xfb = 11u32, + DepthReplacing = 12u32, + DepthGreater = 14u32, + DepthLess = 15u32, + DepthUnchanged = 16u32, + LocalSize = 17u32, + LocalSizeHint = 18u32, + InputPoints = 19u32, + InputLines = 20u32, + InputLinesAdjacency = 21u32, + Triangles = 22u32, + InputTrianglesAdjacency = 23u32, + Quads = 24u32, + Isolines = 25u32, + OutputVertices = 26u32, + OutputPoints = 27u32, + OutputLineStrip = 28u32, + OutputTriangleStrip = 29u32, + VecTypeHint = 30u32, + ContractionOff = 31u32, + Initializer = 33u32, + Finalizer = 34u32, + SubgroupSize = 35u32, + SubgroupsPerWorkgroup = 36u32, + SubgroupsPerWorkgroupId = 37u32, + LocalSizeId = 38u32, + LocalSizeHintId = 39u32, + PostDepthCoverage = 4446u32, + DenormPreserve = 4459u32, + DenormFlushToZero = 4460u32, + SignedZeroInfNanPreserve = 4461u32, + RoundingModeRTE = 4462u32, + RoundingModeRTZ = 4463u32, + StencilRefReplacingEXT = 5027u32, + OutputLinesNV = 5269u32, + OutputPrimitivesNV = 5270u32, + DerivativeGroupQuadsNV = 5289u32, + DerivativeGroupLinearNV = 5290u32, + OutputTrianglesNV = 5298u32, +} +#[allow(non_upper_case_globals)] +impl ExecutionMode { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + ExecutionMode::LocalSize | ExecutionMode::LocalSizeId => &[], + ExecutionMode::DerivativeGroupLinearNV => &[Capability::ComputeDerivativeGroupLinearNV], + ExecutionMode::DerivativeGroupQuadsNV => &[Capability::ComputeDerivativeGroupQuadsNV], + ExecutionMode::DenormFlushToZero => &[Capability::DenormFlushToZero], + ExecutionMode::DenormPreserve => &[Capability::DenormPreserve], + ExecutionMode::Invocations + | ExecutionMode::InputPoints + | ExecutionMode::InputLines + | ExecutionMode::InputLinesAdjacency + | ExecutionMode::InputTrianglesAdjacency + | ExecutionMode::OutputLineStrip + | ExecutionMode::OutputTriangleStrip => &[Capability::Geometry], + ExecutionMode::OutputPoints => &[Capability::Geometry, Capability::MeshShadingNV], + ExecutionMode::Triangles => &[Capability::Geometry, Capability::Tessellation], + ExecutionMode::OutputVertices => &[ + Capability::Geometry, + Capability::Tessellation, + Capability::MeshShadingNV, + ], + ExecutionMode::LocalSizeHint + | ExecutionMode::VecTypeHint + | ExecutionMode::ContractionOff + | ExecutionMode::Initializer + | ExecutionMode::Finalizer + | ExecutionMode::LocalSizeHintId => &[Capability::Kernel], + ExecutionMode::OutputLinesNV + | ExecutionMode::OutputPrimitivesNV + | ExecutionMode::OutputTrianglesNV => &[Capability::MeshShadingNV], + ExecutionMode::RoundingModeRTE => &[Capability::RoundingModeRTE], + ExecutionMode::RoundingModeRTZ => &[Capability::RoundingModeRTZ], + ExecutionMode::PostDepthCoverage => &[Capability::SampleMaskPostDepthCoverage], + ExecutionMode::PixelCenterInteger + | ExecutionMode::OriginUpperLeft + | ExecutionMode::OriginLowerLeft + | ExecutionMode::EarlyFragmentTests + | ExecutionMode::DepthReplacing + | ExecutionMode::DepthGreater + | ExecutionMode::DepthLess + | ExecutionMode::DepthUnchanged => &[Capability::Shader], + ExecutionMode::SignedZeroInfNanPreserve => &[Capability::SignedZeroInfNanPreserve], + ExecutionMode::StencilRefReplacingEXT => &[Capability::StencilExportEXT], + ExecutionMode::SubgroupSize + | ExecutionMode::SubgroupsPerWorkgroup + | ExecutionMode::SubgroupsPerWorkgroupId => &[Capability::SubgroupDispatch], + ExecutionMode::SpacingEqual + | ExecutionMode::SpacingFractionalEven + | ExecutionMode::SpacingFractionalOdd + | ExecutionMode::VertexOrderCw + | ExecutionMode::VertexOrderCcw + | ExecutionMode::PointMode + | ExecutionMode::Quads + | ExecutionMode::Isolines => &[Capability::Tessellation], + ExecutionMode::Xfb => &[Capability::TransformFeedback], + } + } +} +impl num_traits::FromPrimitive for ExecutionMode { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => ExecutionMode::Invocations, + 1u32 => ExecutionMode::SpacingEqual, + 2u32 => ExecutionMode::SpacingFractionalEven, + 3u32 => ExecutionMode::SpacingFractionalOdd, + 4u32 => ExecutionMode::VertexOrderCw, + 5u32 => ExecutionMode::VertexOrderCcw, + 6u32 => ExecutionMode::PixelCenterInteger, + 7u32 => ExecutionMode::OriginUpperLeft, + 8u32 => ExecutionMode::OriginLowerLeft, + 9u32 => ExecutionMode::EarlyFragmentTests, + 10u32 => ExecutionMode::PointMode, + 11u32 => ExecutionMode::Xfb, + 12u32 => ExecutionMode::DepthReplacing, + 14u32 => ExecutionMode::DepthGreater, + 15u32 => ExecutionMode::DepthLess, + 16u32 => ExecutionMode::DepthUnchanged, + 17u32 => ExecutionMode::LocalSize, + 18u32 => ExecutionMode::LocalSizeHint, + 19u32 => ExecutionMode::InputPoints, + 20u32 => ExecutionMode::InputLines, + 21u32 => ExecutionMode::InputLinesAdjacency, + 22u32 => ExecutionMode::Triangles, + 23u32 => ExecutionMode::InputTrianglesAdjacency, + 24u32 => ExecutionMode::Quads, + 25u32 => ExecutionMode::Isolines, + 26u32 => ExecutionMode::OutputVertices, + 27u32 => ExecutionMode::OutputPoints, + 28u32 => ExecutionMode::OutputLineStrip, + 29u32 => ExecutionMode::OutputTriangleStrip, + 30u32 => ExecutionMode::VecTypeHint, + 31u32 => ExecutionMode::ContractionOff, + 33u32 => ExecutionMode::Initializer, + 34u32 => ExecutionMode::Finalizer, + 35u32 => ExecutionMode::SubgroupSize, + 36u32 => ExecutionMode::SubgroupsPerWorkgroup, + 37u32 => ExecutionMode::SubgroupsPerWorkgroupId, + 38u32 => ExecutionMode::LocalSizeId, + 39u32 => ExecutionMode::LocalSizeHintId, + 4446u32 => ExecutionMode::PostDepthCoverage, + 4459u32 => ExecutionMode::DenormPreserve, + 4460u32 => ExecutionMode::DenormFlushToZero, + 4461u32 => ExecutionMode::SignedZeroInfNanPreserve, + 4462u32 => ExecutionMode::RoundingModeRTE, + 4463u32 => ExecutionMode::RoundingModeRTZ, + 5027u32 => ExecutionMode::StencilRefReplacingEXT, + 5269u32 => ExecutionMode::OutputLinesNV, + 5270u32 => ExecutionMode::OutputPrimitivesNV, + 5289u32 => ExecutionMode::DerivativeGroupQuadsNV, + 5290u32 => ExecutionMode::DerivativeGroupLinearNV, + 5298u32 => ExecutionMode::OutputTrianglesNV, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [StorageClass](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_storage_class_a_storage_class)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum StorageClass { + UniformConstant = 0u32, + Input = 1u32, + Uniform = 2u32, + Output = 3u32, + Workgroup = 4u32, + CrossWorkgroup = 5u32, + Private = 6u32, + Function = 7u32, + Generic = 8u32, + PushConstant = 9u32, + AtomicCounter = 10u32, + Image = 11u32, + StorageBuffer = 12u32, + CallableDataNV = 5328u32, + IncomingCallableDataNV = 5329u32, + RayPayloadNV = 5338u32, + HitAttributeNV = 5339u32, + IncomingRayPayloadNV = 5342u32, + ShaderRecordBufferNV = 5343u32, + PhysicalStorageBufferEXT = 5349u32, +} +#[allow(non_upper_case_globals)] +impl StorageClass { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + StorageClass::UniformConstant + | StorageClass::Input + | StorageClass::Workgroup + | StorageClass::CrossWorkgroup + | StorageClass::Function + | StorageClass::Image => &[], + StorageClass::AtomicCounter => &[Capability::AtomicStorage], + StorageClass::Generic => &[Capability::GenericPointer], + StorageClass::PhysicalStorageBufferEXT => { + &[Capability::PhysicalStorageBufferAddressesEXT] + } + StorageClass::CallableDataNV + | StorageClass::IncomingCallableDataNV + | StorageClass::RayPayloadNV + | StorageClass::HitAttributeNV + | StorageClass::IncomingRayPayloadNV + | StorageClass::ShaderRecordBufferNV => &[Capability::RayTracingNV], + StorageClass::Uniform + | StorageClass::Output + | StorageClass::Private + | StorageClass::PushConstant + | StorageClass::StorageBuffer => &[Capability::Shader], + } + } +} +impl num_traits::FromPrimitive for StorageClass { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => StorageClass::UniformConstant, + 1u32 => StorageClass::Input, + 2u32 => StorageClass::Uniform, + 3u32 => StorageClass::Output, + 4u32 => StorageClass::Workgroup, + 5u32 => StorageClass::CrossWorkgroup, + 6u32 => StorageClass::Private, + 7u32 => StorageClass::Function, + 8u32 => StorageClass::Generic, + 9u32 => StorageClass::PushConstant, + 10u32 => StorageClass::AtomicCounter, + 11u32 => StorageClass::Image, + 12u32 => StorageClass::StorageBuffer, + 5328u32 => StorageClass::CallableDataNV, + 5329u32 => StorageClass::IncomingCallableDataNV, + 5338u32 => StorageClass::RayPayloadNV, + 5339u32 => StorageClass::HitAttributeNV, + 5342u32 => StorageClass::IncomingRayPayloadNV, + 5343u32 => StorageClass::ShaderRecordBufferNV, + 5349u32 => StorageClass::PhysicalStorageBufferEXT, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [Dim](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_dim_a_dim)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Dim { + Dim1D = 0u32, + Dim2D = 1u32, + Dim3D = 2u32, + DimCube = 3u32, + DimRect = 4u32, + DimBuffer = 5u32, + DimSubpassData = 6u32, +} +#[allow(non_upper_case_globals)] +impl Dim { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + Dim::Dim3D => &[], + Dim::DimSubpassData => &[Capability::InputAttachment], + Dim::Dim1D => &[Capability::Sampled1D, Capability::Image1D], + Dim::DimBuffer => &[Capability::SampledBuffer, Capability::ImageBuffer], + Dim::DimRect => &[Capability::SampledRect, Capability::ImageRect], + Dim::DimCube => &[Capability::Shader, Capability::ImageCubeArray], + Dim::Dim2D => &[ + Capability::Shader, + Capability::Kernel, + Capability::ImageMSArray, + ], + } + } +} +impl num_traits::FromPrimitive for Dim { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => Dim::Dim1D, + 1u32 => Dim::Dim2D, + 2u32 => Dim::Dim3D, + 3u32 => Dim::DimCube, + 4u32 => Dim::DimRect, + 5u32 => Dim::DimBuffer, + 6u32 => Dim::DimSubpassData, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [SamplerAddressingMode](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_sampler_addressing_mode_a_sampler_addressing_mode)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SamplerAddressingMode { + None = 0u32, + ClampToEdge = 1u32, + Clamp = 2u32, + Repeat = 3u32, + RepeatMirrored = 4u32, +} +#[allow(non_upper_case_globals)] +impl SamplerAddressingMode { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + SamplerAddressingMode::None + | SamplerAddressingMode::ClampToEdge + | SamplerAddressingMode::Clamp + | SamplerAddressingMode::Repeat + | SamplerAddressingMode::RepeatMirrored => &[Capability::Kernel], + } + } +} +impl num_traits::FromPrimitive for SamplerAddressingMode { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => SamplerAddressingMode::None, + 1u32 => SamplerAddressingMode::ClampToEdge, + 2u32 => SamplerAddressingMode::Clamp, + 3u32 => SamplerAddressingMode::Repeat, + 4u32 => SamplerAddressingMode::RepeatMirrored, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [SamplerFilterMode](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_sampler_filter_mode_a_sampler_filter_mode)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SamplerFilterMode { + Nearest = 0u32, + Linear = 1u32, +} +#[allow(non_upper_case_globals)] +impl SamplerFilterMode { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + SamplerFilterMode::Nearest | SamplerFilterMode::Linear => &[Capability::Kernel], + } + } +} +impl num_traits::FromPrimitive for SamplerFilterMode { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => SamplerFilterMode::Nearest, + 1u32 => SamplerFilterMode::Linear, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [ImageFormat](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_image_format_a_image_format)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ImageFormat { + Unknown = 0u32, + Rgba32f = 1u32, + Rgba16f = 2u32, + R32f = 3u32, + Rgba8 = 4u32, + Rgba8Snorm = 5u32, + Rg32f = 6u32, + Rg16f = 7u32, + R11fG11fB10f = 8u32, + R16f = 9u32, + Rgba16 = 10u32, + Rgb10A2 = 11u32, + Rg16 = 12u32, + Rg8 = 13u32, + R16 = 14u32, + R8 = 15u32, + Rgba16Snorm = 16u32, + Rg16Snorm = 17u32, + Rg8Snorm = 18u32, + R16Snorm = 19u32, + R8Snorm = 20u32, + Rgba32i = 21u32, + Rgba16i = 22u32, + Rgba8i = 23u32, + R32i = 24u32, + Rg32i = 25u32, + Rg16i = 26u32, + Rg8i = 27u32, + R16i = 28u32, + R8i = 29u32, + Rgba32ui = 30u32, + Rgba16ui = 31u32, + Rgba8ui = 32u32, + R32ui = 33u32, + Rgb10a2ui = 34u32, + Rg32ui = 35u32, + Rg16ui = 36u32, + Rg8ui = 37u32, + R16ui = 38u32, + R8ui = 39u32, +} +#[allow(non_upper_case_globals)] +impl ImageFormat { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + ImageFormat::Unknown => &[], + ImageFormat::Rgba32f + | ImageFormat::Rgba16f + | ImageFormat::R32f + | ImageFormat::Rgba8 + | ImageFormat::Rgba8Snorm + | ImageFormat::Rgba32i + | ImageFormat::Rgba16i + | ImageFormat::Rgba8i + | ImageFormat::R32i + | ImageFormat::Rgba32ui + | ImageFormat::Rgba16ui + | ImageFormat::Rgba8ui + | ImageFormat::R32ui => &[Capability::Shader], + ImageFormat::Rg32f + | ImageFormat::Rg16f + | ImageFormat::R11fG11fB10f + | ImageFormat::R16f + | ImageFormat::Rgba16 + | ImageFormat::Rgb10A2 + | ImageFormat::Rg16 + | ImageFormat::Rg8 + | ImageFormat::R16 + | ImageFormat::R8 + | ImageFormat::Rgba16Snorm + | ImageFormat::Rg16Snorm + | ImageFormat::Rg8Snorm + | ImageFormat::R16Snorm + | ImageFormat::R8Snorm + | ImageFormat::Rg32i + | ImageFormat::Rg16i + | ImageFormat::Rg8i + | ImageFormat::R16i + | ImageFormat::R8i + | ImageFormat::Rgb10a2ui + | ImageFormat::Rg32ui + | ImageFormat::Rg16ui + | ImageFormat::Rg8ui + | ImageFormat::R16ui + | ImageFormat::R8ui => &[Capability::StorageImageExtendedFormats], + } + } +} +impl num_traits::FromPrimitive for ImageFormat { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => ImageFormat::Unknown, + 1u32 => ImageFormat::Rgba32f, + 2u32 => ImageFormat::Rgba16f, + 3u32 => ImageFormat::R32f, + 4u32 => ImageFormat::Rgba8, + 5u32 => ImageFormat::Rgba8Snorm, + 6u32 => ImageFormat::Rg32f, + 7u32 => ImageFormat::Rg16f, + 8u32 => ImageFormat::R11fG11fB10f, + 9u32 => ImageFormat::R16f, + 10u32 => ImageFormat::Rgba16, + 11u32 => ImageFormat::Rgb10A2, + 12u32 => ImageFormat::Rg16, + 13u32 => ImageFormat::Rg8, + 14u32 => ImageFormat::R16, + 15u32 => ImageFormat::R8, + 16u32 => ImageFormat::Rgba16Snorm, + 17u32 => ImageFormat::Rg16Snorm, + 18u32 => ImageFormat::Rg8Snorm, + 19u32 => ImageFormat::R16Snorm, + 20u32 => ImageFormat::R8Snorm, + 21u32 => ImageFormat::Rgba32i, + 22u32 => ImageFormat::Rgba16i, + 23u32 => ImageFormat::Rgba8i, + 24u32 => ImageFormat::R32i, + 25u32 => ImageFormat::Rg32i, + 26u32 => ImageFormat::Rg16i, + 27u32 => ImageFormat::Rg8i, + 28u32 => ImageFormat::R16i, + 29u32 => ImageFormat::R8i, + 30u32 => ImageFormat::Rgba32ui, + 31u32 => ImageFormat::Rgba16ui, + 32u32 => ImageFormat::Rgba8ui, + 33u32 => ImageFormat::R32ui, + 34u32 => ImageFormat::Rgb10a2ui, + 35u32 => ImageFormat::Rg32ui, + 36u32 => ImageFormat::Rg16ui, + 37u32 => ImageFormat::Rg8ui, + 38u32 => ImageFormat::R16ui, + 39u32 => ImageFormat::R8ui, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [ImageChannelOrder](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_image_channel_order_a_image_channel_order)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ImageChannelOrder { + R = 0u32, + A = 1u32, + RG = 2u32, + RA = 3u32, + RGB = 4u32, + RGBA = 5u32, + BGRA = 6u32, + ARGB = 7u32, + Intensity = 8u32, + Luminance = 9u32, + Rx = 10u32, + RGx = 11u32, + RGBx = 12u32, + Depth = 13u32, + DepthStencil = 14u32, + sRGB = 15u32, + sRGBx = 16u32, + sRGBA = 17u32, + sBGRA = 18u32, + ABGR = 19u32, +} +#[allow(non_upper_case_globals)] +impl ImageChannelOrder { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + ImageChannelOrder::R + | ImageChannelOrder::A + | ImageChannelOrder::RG + | ImageChannelOrder::RA + | ImageChannelOrder::RGB + | ImageChannelOrder::RGBA + | ImageChannelOrder::BGRA + | ImageChannelOrder::ARGB + | ImageChannelOrder::Intensity + | ImageChannelOrder::Luminance + | ImageChannelOrder::Rx + | ImageChannelOrder::RGx + | ImageChannelOrder::RGBx + | ImageChannelOrder::Depth + | ImageChannelOrder::DepthStencil + | ImageChannelOrder::sRGB + | ImageChannelOrder::sRGBx + | ImageChannelOrder::sRGBA + | ImageChannelOrder::sBGRA + | ImageChannelOrder::ABGR => &[Capability::Kernel], + } + } +} +impl num_traits::FromPrimitive for ImageChannelOrder { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => ImageChannelOrder::R, + 1u32 => ImageChannelOrder::A, + 2u32 => ImageChannelOrder::RG, + 3u32 => ImageChannelOrder::RA, + 4u32 => ImageChannelOrder::RGB, + 5u32 => ImageChannelOrder::RGBA, + 6u32 => ImageChannelOrder::BGRA, + 7u32 => ImageChannelOrder::ARGB, + 8u32 => ImageChannelOrder::Intensity, + 9u32 => ImageChannelOrder::Luminance, + 10u32 => ImageChannelOrder::Rx, + 11u32 => ImageChannelOrder::RGx, + 12u32 => ImageChannelOrder::RGBx, + 13u32 => ImageChannelOrder::Depth, + 14u32 => ImageChannelOrder::DepthStencil, + 15u32 => ImageChannelOrder::sRGB, + 16u32 => ImageChannelOrder::sRGBx, + 17u32 => ImageChannelOrder::sRGBA, + 18u32 => ImageChannelOrder::sBGRA, + 19u32 => ImageChannelOrder::ABGR, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [ImageChannelDataType](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_image_channel_data_type_a_image_channel_data_type)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ImageChannelDataType { + SnormInt8 = 0u32, + SnormInt16 = 1u32, + UnormInt8 = 2u32, + UnormInt16 = 3u32, + UnormShort565 = 4u32, + UnormShort555 = 5u32, + UnormInt101010 = 6u32, + SignedInt8 = 7u32, + SignedInt16 = 8u32, + SignedInt32 = 9u32, + UnsignedInt8 = 10u32, + UnsignedInt16 = 11u32, + UnsignedInt32 = 12u32, + HalfFloat = 13u32, + Float = 14u32, + UnormInt24 = 15u32, + UnormInt101010_2 = 16u32, +} +#[allow(non_upper_case_globals)] +impl ImageChannelDataType { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + ImageChannelDataType::SnormInt8 + | ImageChannelDataType::SnormInt16 + | ImageChannelDataType::UnormInt8 + | ImageChannelDataType::UnormInt16 + | ImageChannelDataType::UnormShort565 + | ImageChannelDataType::UnormShort555 + | ImageChannelDataType::UnormInt101010 + | ImageChannelDataType::SignedInt8 + | ImageChannelDataType::SignedInt16 + | ImageChannelDataType::SignedInt32 + | ImageChannelDataType::UnsignedInt8 + | ImageChannelDataType::UnsignedInt16 + | ImageChannelDataType::UnsignedInt32 + | ImageChannelDataType::HalfFloat + | ImageChannelDataType::Float + | ImageChannelDataType::UnormInt24 + | ImageChannelDataType::UnormInt101010_2 => &[Capability::Kernel], + } + } +} +impl num_traits::FromPrimitive for ImageChannelDataType { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => ImageChannelDataType::SnormInt8, + 1u32 => ImageChannelDataType::SnormInt16, + 2u32 => ImageChannelDataType::UnormInt8, + 3u32 => ImageChannelDataType::UnormInt16, + 4u32 => ImageChannelDataType::UnormShort565, + 5u32 => ImageChannelDataType::UnormShort555, + 6u32 => ImageChannelDataType::UnormInt101010, + 7u32 => ImageChannelDataType::SignedInt8, + 8u32 => ImageChannelDataType::SignedInt16, + 9u32 => ImageChannelDataType::SignedInt32, + 10u32 => ImageChannelDataType::UnsignedInt8, + 11u32 => ImageChannelDataType::UnsignedInt16, + 12u32 => ImageChannelDataType::UnsignedInt32, + 13u32 => ImageChannelDataType::HalfFloat, + 14u32 => ImageChannelDataType::Float, + 15u32 => ImageChannelDataType::UnormInt24, + 16u32 => ImageChannelDataType::UnormInt101010_2, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [FPRoundingMode](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_fp_rounding_mode_a_fp_rounding_mode)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum FPRoundingMode { + RTE = 0u32, + RTZ = 1u32, + RTP = 2u32, + RTN = 3u32, +} +#[allow(non_upper_case_globals)] +impl FPRoundingMode { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + FPRoundingMode::RTE + | FPRoundingMode::RTZ + | FPRoundingMode::RTP + | FPRoundingMode::RTN => &[], + } + } +} +impl num_traits::FromPrimitive for FPRoundingMode { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => FPRoundingMode::RTE, + 1u32 => FPRoundingMode::RTZ, + 2u32 => FPRoundingMode::RTP, + 3u32 => FPRoundingMode::RTN, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [LinkageType](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_linkage_type_a_linkage_type)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum LinkageType { + Export = 0u32, + Import = 1u32, +} +#[allow(non_upper_case_globals)] +impl LinkageType { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + LinkageType::Export | LinkageType::Import => &[Capability::Linkage], + } + } +} +impl num_traits::FromPrimitive for LinkageType { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => LinkageType::Export, + 1u32 => LinkageType::Import, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [AccessQualifier](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_access_qualifier_a_access_qualifier)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum AccessQualifier { + ReadOnly = 0u32, + WriteOnly = 1u32, + ReadWrite = 2u32, +} +#[allow(non_upper_case_globals)] +impl AccessQualifier { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + AccessQualifier::ReadOnly | AccessQualifier::WriteOnly | AccessQualifier::ReadWrite => { + &[Capability::Kernel] + } + } + } +} +impl num_traits::FromPrimitive for AccessQualifier { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => AccessQualifier::ReadOnly, + 1u32 => AccessQualifier::WriteOnly, + 2u32 => AccessQualifier::ReadWrite, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [FunctionParameterAttribute](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_function_parameter_attribute_a_function_parameter_attribute)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum FunctionParameterAttribute { + Zext = 0u32, + Sext = 1u32, + ByVal = 2u32, + Sret = 3u32, + NoAlias = 4u32, + NoCapture = 5u32, + NoWrite = 6u32, + NoReadWrite = 7u32, +} +#[allow(non_upper_case_globals)] +impl FunctionParameterAttribute { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + FunctionParameterAttribute::Zext + | FunctionParameterAttribute::Sext + | FunctionParameterAttribute::ByVal + | FunctionParameterAttribute::Sret + | FunctionParameterAttribute::NoAlias + | FunctionParameterAttribute::NoCapture + | FunctionParameterAttribute::NoWrite + | FunctionParameterAttribute::NoReadWrite => &[Capability::Kernel], + } + } +} +impl num_traits::FromPrimitive for FunctionParameterAttribute { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => FunctionParameterAttribute::Zext, + 1u32 => FunctionParameterAttribute::Sext, + 2u32 => FunctionParameterAttribute::ByVal, + 3u32 => FunctionParameterAttribute::Sret, + 4u32 => FunctionParameterAttribute::NoAlias, + 5u32 => FunctionParameterAttribute::NoCapture, + 6u32 => FunctionParameterAttribute::NoWrite, + 7u32 => FunctionParameterAttribute::NoReadWrite, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [Decoration](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_decoration_a_decoration)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Decoration { + RelaxedPrecision = 0u32, + SpecId = 1u32, + Block = 2u32, + BufferBlock = 3u32, + RowMajor = 4u32, + ColMajor = 5u32, + ArrayStride = 6u32, + MatrixStride = 7u32, + GLSLShared = 8u32, + GLSLPacked = 9u32, + CPacked = 10u32, + BuiltIn = 11u32, + NoPerspective = 13u32, + Flat = 14u32, + Patch = 15u32, + Centroid = 16u32, + Sample = 17u32, + Invariant = 18u32, + Restrict = 19u32, + Aliased = 20u32, + Volatile = 21u32, + Constant = 22u32, + Coherent = 23u32, + NonWritable = 24u32, + NonReadable = 25u32, + Uniform = 26u32, + UniformId = 27u32, + SaturatedConversion = 28u32, + Stream = 29u32, + Location = 30u32, + Component = 31u32, + Index = 32u32, + Binding = 33u32, + DescriptorSet = 34u32, + Offset = 35u32, + XfbBuffer = 36u32, + XfbStride = 37u32, + FuncParamAttr = 38u32, + FPRoundingMode = 39u32, + FPFastMathMode = 40u32, + LinkageAttributes = 41u32, + NoContraction = 42u32, + InputAttachmentIndex = 43u32, + Alignment = 44u32, + MaxByteOffset = 45u32, + AlignmentId = 46u32, + MaxByteOffsetId = 47u32, + NoSignedWrap = 4469u32, + NoUnsignedWrap = 4470u32, + ExplicitInterpAMD = 4999u32, + OverrideCoverageNV = 5248u32, + PassthroughNV = 5250u32, + ViewportRelativeNV = 5252u32, + SecondaryViewportRelativeNV = 5256u32, + PerPrimitiveNV = 5271u32, + PerViewNV = 5272u32, + PerTaskNV = 5273u32, + PerVertexNV = 5285u32, + NonUniformEXT = 5300u32, + CounterBuffer = 5634u32, + UserSemantic = 5635u32, + RestrictPointerEXT = 5355u32, + AliasedPointerEXT = 5356u32, +} +#[allow(non_upper_case_globals)] +impl Decoration { + pub const HlslCounterBufferGOOGLE: Decoration = Decoration::CounterBuffer; + pub const HlslSemanticGOOGLE: Decoration = Decoration::UserSemantic; + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + Decoration::BuiltIn + | Decoration::Restrict + | Decoration::Aliased + | Decoration::Volatile + | Decoration::Coherent + | Decoration::NonWritable + | Decoration::NonReadable + | Decoration::FPRoundingMode + | Decoration::NoSignedWrap + | Decoration::NoUnsignedWrap + | Decoration::ExplicitInterpAMD + | Decoration::CounterBuffer + | Decoration::UserSemantic => &[], + Decoration::MaxByteOffset | Decoration::MaxByteOffsetId => &[Capability::Addresses], + Decoration::PerVertexNV => &[Capability::FragmentBarycentricNV], + Decoration::PassthroughNV => &[Capability::GeometryShaderPassthroughNV], + Decoration::Stream => &[Capability::GeometryStreams], + Decoration::InputAttachmentIndex => &[Capability::InputAttachment], + Decoration::CPacked + | Decoration::Constant + | Decoration::SaturatedConversion + | Decoration::FuncParamAttr + | Decoration::FPFastMathMode + | Decoration::Alignment + | Decoration::AlignmentId => &[Capability::Kernel], + Decoration::LinkageAttributes => &[Capability::Linkage], + Decoration::RowMajor | Decoration::ColMajor | Decoration::MatrixStride => { + &[Capability::Matrix] + } + Decoration::PerPrimitiveNV | Decoration::PerViewNV | Decoration::PerTaskNV => { + &[Capability::MeshShadingNV] + } + Decoration::RestrictPointerEXT | Decoration::AliasedPointerEXT => { + &[Capability::PhysicalStorageBufferAddressesEXT] + } + Decoration::OverrideCoverageNV => &[Capability::SampleMaskOverrideCoverageNV], + Decoration::Sample => &[Capability::SampleRateShading], + Decoration::RelaxedPrecision + | Decoration::Block + | Decoration::BufferBlock + | Decoration::ArrayStride + | Decoration::GLSLShared + | Decoration::GLSLPacked + | Decoration::NoPerspective + | Decoration::Flat + | Decoration::Centroid + | Decoration::Invariant + | Decoration::Uniform + | Decoration::UniformId + | Decoration::Location + | Decoration::Component + | Decoration::Index + | Decoration::Binding + | Decoration::DescriptorSet + | Decoration::Offset + | Decoration::NoContraction => &[Capability::Shader], + Decoration::SpecId => &[Capability::Shader, Capability::Kernel], + Decoration::NonUniformEXT => &[Capability::ShaderNonUniformEXT], + Decoration::SecondaryViewportRelativeNV => &[Capability::ShaderStereoViewNV], + Decoration::ViewportRelativeNV => &[Capability::ShaderViewportMaskNV], + Decoration::Patch => &[Capability::Tessellation], + Decoration::XfbBuffer | Decoration::XfbStride => &[Capability::TransformFeedback], + } + } +} +impl num_traits::FromPrimitive for Decoration { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => Decoration::RelaxedPrecision, + 1u32 => Decoration::SpecId, + 2u32 => Decoration::Block, + 3u32 => Decoration::BufferBlock, + 4u32 => Decoration::RowMajor, + 5u32 => Decoration::ColMajor, + 6u32 => Decoration::ArrayStride, + 7u32 => Decoration::MatrixStride, + 8u32 => Decoration::GLSLShared, + 9u32 => Decoration::GLSLPacked, + 10u32 => Decoration::CPacked, + 11u32 => Decoration::BuiltIn, + 13u32 => Decoration::NoPerspective, + 14u32 => Decoration::Flat, + 15u32 => Decoration::Patch, + 16u32 => Decoration::Centroid, + 17u32 => Decoration::Sample, + 18u32 => Decoration::Invariant, + 19u32 => Decoration::Restrict, + 20u32 => Decoration::Aliased, + 21u32 => Decoration::Volatile, + 22u32 => Decoration::Constant, + 23u32 => Decoration::Coherent, + 24u32 => Decoration::NonWritable, + 25u32 => Decoration::NonReadable, + 26u32 => Decoration::Uniform, + 27u32 => Decoration::UniformId, + 28u32 => Decoration::SaturatedConversion, + 29u32 => Decoration::Stream, + 30u32 => Decoration::Location, + 31u32 => Decoration::Component, + 32u32 => Decoration::Index, + 33u32 => Decoration::Binding, + 34u32 => Decoration::DescriptorSet, + 35u32 => Decoration::Offset, + 36u32 => Decoration::XfbBuffer, + 37u32 => Decoration::XfbStride, + 38u32 => Decoration::FuncParamAttr, + 39u32 => Decoration::FPRoundingMode, + 40u32 => Decoration::FPFastMathMode, + 41u32 => Decoration::LinkageAttributes, + 42u32 => Decoration::NoContraction, + 43u32 => Decoration::InputAttachmentIndex, + 44u32 => Decoration::Alignment, + 45u32 => Decoration::MaxByteOffset, + 46u32 => Decoration::AlignmentId, + 47u32 => Decoration::MaxByteOffsetId, + 4469u32 => Decoration::NoSignedWrap, + 4470u32 => Decoration::NoUnsignedWrap, + 4999u32 => Decoration::ExplicitInterpAMD, + 5248u32 => Decoration::OverrideCoverageNV, + 5250u32 => Decoration::PassthroughNV, + 5252u32 => Decoration::ViewportRelativeNV, + 5256u32 => Decoration::SecondaryViewportRelativeNV, + 5271u32 => Decoration::PerPrimitiveNV, + 5272u32 => Decoration::PerViewNV, + 5273u32 => Decoration::PerTaskNV, + 5285u32 => Decoration::PerVertexNV, + 5300u32 => Decoration::NonUniformEXT, + 5634u32 => Decoration::CounterBuffer, + 5635u32 => Decoration::UserSemantic, + 5355u32 => Decoration::RestrictPointerEXT, + 5356u32 => Decoration::AliasedPointerEXT, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [BuiltIn](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_built_in_a_built_in)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum BuiltIn { + Position = 0u32, + PointSize = 1u32, + ClipDistance = 3u32, + CullDistance = 4u32, + VertexId = 5u32, + InstanceId = 6u32, + PrimitiveId = 7u32, + InvocationId = 8u32, + Layer = 9u32, + ViewportIndex = 10u32, + TessLevelOuter = 11u32, + TessLevelInner = 12u32, + TessCoord = 13u32, + PatchVertices = 14u32, + FragCoord = 15u32, + PointCoord = 16u32, + FrontFacing = 17u32, + SampleId = 18u32, + SamplePosition = 19u32, + SampleMask = 20u32, + FragDepth = 22u32, + HelperInvocation = 23u32, + NumWorkgroups = 24u32, + WorkgroupSize = 25u32, + WorkgroupId = 26u32, + LocalInvocationId = 27u32, + GlobalInvocationId = 28u32, + LocalInvocationIndex = 29u32, + WorkDim = 30u32, + GlobalSize = 31u32, + EnqueuedWorkgroupSize = 32u32, + GlobalOffset = 33u32, + GlobalLinearId = 34u32, + SubgroupSize = 36u32, + SubgroupMaxSize = 37u32, + NumSubgroups = 38u32, + NumEnqueuedSubgroups = 39u32, + SubgroupId = 40u32, + SubgroupLocalInvocationId = 41u32, + VertexIndex = 42u32, + InstanceIndex = 43u32, + SubgroupEqMask = 4416u32, + SubgroupGeMask = 4417u32, + SubgroupGtMask = 4418u32, + SubgroupLeMask = 4419u32, + SubgroupLtMask = 4420u32, + BaseVertex = 4424u32, + BaseInstance = 4425u32, + DrawIndex = 4426u32, + DeviceIndex = 4438u32, + ViewIndex = 4440u32, + BaryCoordNoPerspAMD = 4992u32, + BaryCoordNoPerspCentroidAMD = 4993u32, + BaryCoordNoPerspSampleAMD = 4994u32, + BaryCoordSmoothAMD = 4995u32, + BaryCoordSmoothCentroidAMD = 4996u32, + BaryCoordSmoothSampleAMD = 4997u32, + BaryCoordPullModelAMD = 4998u32, + FragStencilRefEXT = 5014u32, + ViewportMaskNV = 5253u32, + SecondaryPositionNV = 5257u32, + SecondaryViewportMaskNV = 5258u32, + PositionPerViewNV = 5261u32, + ViewportMaskPerViewNV = 5262u32, + FullyCoveredEXT = 5264u32, + TaskCountNV = 5274u32, + PrimitiveCountNV = 5275u32, + PrimitiveIndicesNV = 5276u32, + ClipDistancePerViewNV = 5277u32, + CullDistancePerViewNV = 5278u32, + LayerPerViewNV = 5279u32, + MeshViewCountNV = 5280u32, + MeshViewIndicesNV = 5281u32, + BaryCoordNV = 5286u32, + BaryCoordNoPerspNV = 5287u32, + FragSizeEXT = 5292u32, + FragInvocationCountEXT = 5293u32, + LaunchIdNV = 5319u32, + LaunchSizeNV = 5320u32, + WorldRayOriginNV = 5321u32, + WorldRayDirectionNV = 5322u32, + ObjectRayOriginNV = 5323u32, + ObjectRayDirectionNV = 5324u32, + RayTminNV = 5325u32, + RayTmaxNV = 5326u32, + InstanceCustomIndexNV = 5327u32, + ObjectToWorldNV = 5330u32, + WorldToObjectNV = 5331u32, + HitTNV = 5332u32, + HitKindNV = 5333u32, + IncomingRayFlagsNV = 5351u32, +} +#[allow(non_upper_case_globals)] +impl BuiltIn { + pub const SubgroupEqMaskKHR: BuiltIn = BuiltIn::SubgroupEqMask; + pub const SubgroupGeMaskKHR: BuiltIn = BuiltIn::SubgroupGeMask; + pub const SubgroupGtMaskKHR: BuiltIn = BuiltIn::SubgroupGtMask; + pub const SubgroupLeMaskKHR: BuiltIn = BuiltIn::SubgroupLeMask; + pub const SubgroupLtMaskKHR: BuiltIn = BuiltIn::SubgroupLtMask; + pub const FragmentSizeNV: BuiltIn = BuiltIn::FragSizeEXT; + pub const InvocationsPerPixelNV: BuiltIn = BuiltIn::FragInvocationCountEXT; + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + BuiltIn::NumWorkgroups + | BuiltIn::WorkgroupSize + | BuiltIn::WorkgroupId + | BuiltIn::LocalInvocationId + | BuiltIn::GlobalInvocationId + | BuiltIn::LocalInvocationIndex + | BuiltIn::BaryCoordNoPerspAMD + | BuiltIn::BaryCoordNoPerspCentroidAMD + | BuiltIn::BaryCoordNoPerspSampleAMD + | BuiltIn::BaryCoordSmoothAMD + | BuiltIn::BaryCoordSmoothCentroidAMD + | BuiltIn::BaryCoordSmoothSampleAMD + | BuiltIn::BaryCoordPullModelAMD => &[], + BuiltIn::ClipDistance => &[Capability::ClipDistance], + BuiltIn::CullDistance => &[Capability::CullDistance], + BuiltIn::DeviceIndex => &[Capability::DeviceGroup], + BuiltIn::BaseVertex | BuiltIn::BaseInstance => &[Capability::DrawParameters], + BuiltIn::DrawIndex => &[Capability::DrawParameters, Capability::MeshShadingNV], + BuiltIn::BaryCoordNV | BuiltIn::BaryCoordNoPerspNV => { + &[Capability::FragmentBarycentricNV] + } + BuiltIn::FragSizeEXT | BuiltIn::FragInvocationCountEXT => { + &[Capability::FragmentDensityEXT, Capability::ShadingRateNV] + } + BuiltIn::FullyCoveredEXT => &[Capability::FragmentFullyCoveredEXT], + BuiltIn::Layer => &[Capability::Geometry], + BuiltIn::InvocationId => &[Capability::Geometry, Capability::Tessellation], + BuiltIn::PrimitiveId => &[ + Capability::Geometry, + Capability::Tessellation, + Capability::RayTracingNV, + ], + BuiltIn::WorkDim + | BuiltIn::GlobalSize + | BuiltIn::EnqueuedWorkgroupSize + | BuiltIn::GlobalOffset + | BuiltIn::GlobalLinearId + | BuiltIn::SubgroupMaxSize + | BuiltIn::NumEnqueuedSubgroups => &[Capability::Kernel], + BuiltIn::NumSubgroups | BuiltIn::SubgroupId => { + &[Capability::Kernel, Capability::GroupNonUniform] + } + BuiltIn::SubgroupSize | BuiltIn::SubgroupLocalInvocationId => &[ + Capability::Kernel, + Capability::GroupNonUniform, + Capability::SubgroupBallotKHR, + ], + BuiltIn::TaskCountNV + | BuiltIn::PrimitiveCountNV + | BuiltIn::PrimitiveIndicesNV + | BuiltIn::ClipDistancePerViewNV + | BuiltIn::CullDistancePerViewNV + | BuiltIn::LayerPerViewNV + | BuiltIn::MeshViewCountNV + | BuiltIn::MeshViewIndicesNV => &[Capability::MeshShadingNV], + BuiltIn::ViewIndex => &[Capability::MultiView], + BuiltIn::ViewportIndex => &[Capability::MultiViewport], + BuiltIn::PositionPerViewNV | BuiltIn::ViewportMaskPerViewNV => { + &[Capability::PerViewAttributesNV, Capability::MeshShadingNV] + } + BuiltIn::LaunchIdNV + | BuiltIn::LaunchSizeNV + | BuiltIn::WorldRayOriginNV + | BuiltIn::WorldRayDirectionNV + | BuiltIn::ObjectRayOriginNV + | BuiltIn::ObjectRayDirectionNV + | BuiltIn::RayTminNV + | BuiltIn::RayTmaxNV + | BuiltIn::InstanceCustomIndexNV + | BuiltIn::ObjectToWorldNV + | BuiltIn::WorldToObjectNV + | BuiltIn::HitTNV + | BuiltIn::HitKindNV + | BuiltIn::IncomingRayFlagsNV => &[Capability::RayTracingNV], + BuiltIn::SampleId | BuiltIn::SamplePosition => &[Capability::SampleRateShading], + BuiltIn::Position + | BuiltIn::PointSize + | BuiltIn::VertexId + | BuiltIn::InstanceId + | BuiltIn::FragCoord + | BuiltIn::PointCoord + | BuiltIn::FrontFacing + | BuiltIn::SampleMask + | BuiltIn::FragDepth + | BuiltIn::HelperInvocation + | BuiltIn::VertexIndex + | BuiltIn::InstanceIndex => &[Capability::Shader], + BuiltIn::SecondaryPositionNV | BuiltIn::SecondaryViewportMaskNV => { + &[Capability::ShaderStereoViewNV] + } + BuiltIn::ViewportMaskNV => { + &[Capability::ShaderViewportMaskNV, Capability::MeshShadingNV] + } + BuiltIn::FragStencilRefEXT => &[Capability::StencilExportEXT], + BuiltIn::SubgroupEqMask + | BuiltIn::SubgroupGeMask + | BuiltIn::SubgroupGtMask + | BuiltIn::SubgroupLeMask + | BuiltIn::SubgroupLtMask => &[ + Capability::SubgroupBallotKHR, + Capability::GroupNonUniformBallot, + ], + BuiltIn::TessLevelOuter + | BuiltIn::TessLevelInner + | BuiltIn::TessCoord + | BuiltIn::PatchVertices => &[Capability::Tessellation], + } + } +} +impl num_traits::FromPrimitive for BuiltIn { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => BuiltIn::Position, + 1u32 => BuiltIn::PointSize, + 3u32 => BuiltIn::ClipDistance, + 4u32 => BuiltIn::CullDistance, + 5u32 => BuiltIn::VertexId, + 6u32 => BuiltIn::InstanceId, + 7u32 => BuiltIn::PrimitiveId, + 8u32 => BuiltIn::InvocationId, + 9u32 => BuiltIn::Layer, + 10u32 => BuiltIn::ViewportIndex, + 11u32 => BuiltIn::TessLevelOuter, + 12u32 => BuiltIn::TessLevelInner, + 13u32 => BuiltIn::TessCoord, + 14u32 => BuiltIn::PatchVertices, + 15u32 => BuiltIn::FragCoord, + 16u32 => BuiltIn::PointCoord, + 17u32 => BuiltIn::FrontFacing, + 18u32 => BuiltIn::SampleId, + 19u32 => BuiltIn::SamplePosition, + 20u32 => BuiltIn::SampleMask, + 22u32 => BuiltIn::FragDepth, + 23u32 => BuiltIn::HelperInvocation, + 24u32 => BuiltIn::NumWorkgroups, + 25u32 => BuiltIn::WorkgroupSize, + 26u32 => BuiltIn::WorkgroupId, + 27u32 => BuiltIn::LocalInvocationId, + 28u32 => BuiltIn::GlobalInvocationId, + 29u32 => BuiltIn::LocalInvocationIndex, + 30u32 => BuiltIn::WorkDim, + 31u32 => BuiltIn::GlobalSize, + 32u32 => BuiltIn::EnqueuedWorkgroupSize, + 33u32 => BuiltIn::GlobalOffset, + 34u32 => BuiltIn::GlobalLinearId, + 36u32 => BuiltIn::SubgroupSize, + 37u32 => BuiltIn::SubgroupMaxSize, + 38u32 => BuiltIn::NumSubgroups, + 39u32 => BuiltIn::NumEnqueuedSubgroups, + 40u32 => BuiltIn::SubgroupId, + 41u32 => BuiltIn::SubgroupLocalInvocationId, + 42u32 => BuiltIn::VertexIndex, + 43u32 => BuiltIn::InstanceIndex, + 4416u32 => BuiltIn::SubgroupEqMask, + 4417u32 => BuiltIn::SubgroupGeMask, + 4418u32 => BuiltIn::SubgroupGtMask, + 4419u32 => BuiltIn::SubgroupLeMask, + 4420u32 => BuiltIn::SubgroupLtMask, + 4424u32 => BuiltIn::BaseVertex, + 4425u32 => BuiltIn::BaseInstance, + 4426u32 => BuiltIn::DrawIndex, + 4438u32 => BuiltIn::DeviceIndex, + 4440u32 => BuiltIn::ViewIndex, + 4992u32 => BuiltIn::BaryCoordNoPerspAMD, + 4993u32 => BuiltIn::BaryCoordNoPerspCentroidAMD, + 4994u32 => BuiltIn::BaryCoordNoPerspSampleAMD, + 4995u32 => BuiltIn::BaryCoordSmoothAMD, + 4996u32 => BuiltIn::BaryCoordSmoothCentroidAMD, + 4997u32 => BuiltIn::BaryCoordSmoothSampleAMD, + 4998u32 => BuiltIn::BaryCoordPullModelAMD, + 5014u32 => BuiltIn::FragStencilRefEXT, + 5253u32 => BuiltIn::ViewportMaskNV, + 5257u32 => BuiltIn::SecondaryPositionNV, + 5258u32 => BuiltIn::SecondaryViewportMaskNV, + 5261u32 => BuiltIn::PositionPerViewNV, + 5262u32 => BuiltIn::ViewportMaskPerViewNV, + 5264u32 => BuiltIn::FullyCoveredEXT, + 5274u32 => BuiltIn::TaskCountNV, + 5275u32 => BuiltIn::PrimitiveCountNV, + 5276u32 => BuiltIn::PrimitiveIndicesNV, + 5277u32 => BuiltIn::ClipDistancePerViewNV, + 5278u32 => BuiltIn::CullDistancePerViewNV, + 5279u32 => BuiltIn::LayerPerViewNV, + 5280u32 => BuiltIn::MeshViewCountNV, + 5281u32 => BuiltIn::MeshViewIndicesNV, + 5286u32 => BuiltIn::BaryCoordNV, + 5287u32 => BuiltIn::BaryCoordNoPerspNV, + 5292u32 => BuiltIn::FragSizeEXT, + 5293u32 => BuiltIn::FragInvocationCountEXT, + 5319u32 => BuiltIn::LaunchIdNV, + 5320u32 => BuiltIn::LaunchSizeNV, + 5321u32 => BuiltIn::WorldRayOriginNV, + 5322u32 => BuiltIn::WorldRayDirectionNV, + 5323u32 => BuiltIn::ObjectRayOriginNV, + 5324u32 => BuiltIn::ObjectRayDirectionNV, + 5325u32 => BuiltIn::RayTminNV, + 5326u32 => BuiltIn::RayTmaxNV, + 5327u32 => BuiltIn::InstanceCustomIndexNV, + 5330u32 => BuiltIn::ObjectToWorldNV, + 5331u32 => BuiltIn::WorldToObjectNV, + 5332u32 => BuiltIn::HitTNV, + 5333u32 => BuiltIn::HitKindNV, + 5351u32 => BuiltIn::IncomingRayFlagsNV, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [Scope](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_scope_a_scope)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Scope { + CrossDevice = 0u32, + Device = 1u32, + Workgroup = 2u32, + Subgroup = 3u32, + Invocation = 4u32, + QueueFamilyKHR = 5u32, +} +#[allow(non_upper_case_globals)] +impl Scope { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + Scope::CrossDevice + | Scope::Device + | Scope::Workgroup + | Scope::Subgroup + | Scope::Invocation => &[], + Scope::QueueFamilyKHR => &[Capability::VulkanMemoryModelKHR], + } + } +} +impl num_traits::FromPrimitive for Scope { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => Scope::CrossDevice, + 1u32 => Scope::Device, + 2u32 => Scope::Workgroup, + 3u32 => Scope::Subgroup, + 4u32 => Scope::Invocation, + 5u32 => Scope::QueueFamilyKHR, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [GroupOperation](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_group_operation_a_group_operation)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum GroupOperation { + Reduce = 0u32, + InclusiveScan = 1u32, + ExclusiveScan = 2u32, + ClusteredReduce = 3u32, + PartitionedReduceNV = 6u32, + PartitionedInclusiveScanNV = 7u32, + PartitionedExclusiveScanNV = 8u32, +} +#[allow(non_upper_case_globals)] +impl GroupOperation { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + GroupOperation::ClusteredReduce => &[Capability::GroupNonUniformClustered], + GroupOperation::PartitionedReduceNV + | GroupOperation::PartitionedInclusiveScanNV + | GroupOperation::PartitionedExclusiveScanNV => { + &[Capability::GroupNonUniformPartitionedNV] + } + GroupOperation::Reduce + | GroupOperation::InclusiveScan + | GroupOperation::ExclusiveScan => &[ + Capability::Kernel, + Capability::GroupNonUniformArithmetic, + Capability::GroupNonUniformBallot, + ], + } + } +} +impl num_traits::FromPrimitive for GroupOperation { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => GroupOperation::Reduce, + 1u32 => GroupOperation::InclusiveScan, + 2u32 => GroupOperation::ExclusiveScan, + 3u32 => GroupOperation::ClusteredReduce, + 6u32 => GroupOperation::PartitionedReduceNV, + 7u32 => GroupOperation::PartitionedInclusiveScanNV, + 8u32 => GroupOperation::PartitionedExclusiveScanNV, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [KernelEnqueueFlags](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_kernel_enqueue_flags_a_kernel_enqueue_flags)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum KernelEnqueueFlags { + NoWait = 0u32, + WaitKernel = 1u32, + WaitWorkGroup = 2u32, +} +#[allow(non_upper_case_globals)] +impl KernelEnqueueFlags { + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + KernelEnqueueFlags::NoWait + | KernelEnqueueFlags::WaitKernel + | KernelEnqueueFlags::WaitWorkGroup => &[Capability::Kernel], + } + } +} +impl num_traits::FromPrimitive for KernelEnqueueFlags { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => KernelEnqueueFlags::NoWait, + 1u32 => KernelEnqueueFlags::WaitKernel, + 2u32 => KernelEnqueueFlags::WaitWorkGroup, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "/// SPIR-V operand kind: [Capability](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_capability_a_capability)"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Capability { + Matrix = 0u32, + Shader = 1u32, + Geometry = 2u32, + Tessellation = 3u32, + Addresses = 4u32, + Linkage = 5u32, + Kernel = 6u32, + Vector16 = 7u32, + Float16Buffer = 8u32, + Float16 = 9u32, + Float64 = 10u32, + Int64 = 11u32, + Int64Atomics = 12u32, + ImageBasic = 13u32, + ImageReadWrite = 14u32, + ImageMipmap = 15u32, + Pipes = 17u32, + Groups = 18u32, + DeviceEnqueue = 19u32, + LiteralSampler = 20u32, + AtomicStorage = 21u32, + Int16 = 22u32, + TessellationPointSize = 23u32, + GeometryPointSize = 24u32, + ImageGatherExtended = 25u32, + StorageImageMultisample = 27u32, + UniformBufferArrayDynamicIndexing = 28u32, + SampledImageArrayDynamicIndexing = 29u32, + StorageBufferArrayDynamicIndexing = 30u32, + StorageImageArrayDynamicIndexing = 31u32, + ClipDistance = 32u32, + CullDistance = 33u32, + ImageCubeArray = 34u32, + SampleRateShading = 35u32, + ImageRect = 36u32, + SampledRect = 37u32, + GenericPointer = 38u32, + Int8 = 39u32, + InputAttachment = 40u32, + SparseResidency = 41u32, + MinLod = 42u32, + Sampled1D = 43u32, + Image1D = 44u32, + SampledCubeArray = 45u32, + SampledBuffer = 46u32, + ImageBuffer = 47u32, + ImageMSArray = 48u32, + StorageImageExtendedFormats = 49u32, + ImageQuery = 50u32, + DerivativeControl = 51u32, + InterpolationFunction = 52u32, + TransformFeedback = 53u32, + GeometryStreams = 54u32, + StorageImageReadWithoutFormat = 55u32, + StorageImageWriteWithoutFormat = 56u32, + MultiViewport = 57u32, + SubgroupDispatch = 58u32, + NamedBarrier = 59u32, + PipeStorage = 60u32, + GroupNonUniform = 61u32, + GroupNonUniformVote = 62u32, + GroupNonUniformArithmetic = 63u32, + GroupNonUniformBallot = 64u32, + GroupNonUniformShuffle = 65u32, + GroupNonUniformShuffleRelative = 66u32, + GroupNonUniformClustered = 67u32, + GroupNonUniformQuad = 68u32, + SubgroupBallotKHR = 4423u32, + DrawParameters = 4427u32, + SubgroupVoteKHR = 4431u32, + StorageBuffer16BitAccess = 4433u32, + UniformAndStorageBuffer16BitAccess = 4434u32, + StoragePushConstant16 = 4435u32, + StorageInputOutput16 = 4436u32, + DeviceGroup = 4437u32, + MultiView = 4439u32, + VariablePointersStorageBuffer = 4441u32, + VariablePointers = 4442u32, + AtomicStorageOps = 4445u32, + SampleMaskPostDepthCoverage = 4447u32, + StorageBuffer8BitAccess = 4448u32, + UniformAndStorageBuffer8BitAccess = 4449u32, + StoragePushConstant8 = 4450u32, + DenormPreserve = 4464u32, + DenormFlushToZero = 4465u32, + SignedZeroInfNanPreserve = 4466u32, + RoundingModeRTE = 4467u32, + RoundingModeRTZ = 4468u32, + Float16ImageAMD = 5008u32, + ImageGatherBiasLodAMD = 5009u32, + FragmentMaskAMD = 5010u32, + StencilExportEXT = 5013u32, + ImageReadWriteLodAMD = 5015u32, + SampleMaskOverrideCoverageNV = 5249u32, + GeometryShaderPassthroughNV = 5251u32, + ShaderViewportIndexLayerEXT = 5254u32, + ShaderViewportMaskNV = 5255u32, + ShaderStereoViewNV = 5259u32, + PerViewAttributesNV = 5260u32, + FragmentFullyCoveredEXT = 5265u32, + MeshShadingNV = 5266u32, + ShaderNonUniformEXT = 5301u32, + RuntimeDescriptorArrayEXT = 5302u32, + InputAttachmentArrayDynamicIndexingEXT = 5303u32, + UniformTexelBufferArrayDynamicIndexingEXT = 5304u32, + StorageTexelBufferArrayDynamicIndexingEXT = 5305u32, + UniformBufferArrayNonUniformIndexingEXT = 5306u32, + SampledImageArrayNonUniformIndexingEXT = 5307u32, + StorageBufferArrayNonUniformIndexingEXT = 5308u32, + StorageImageArrayNonUniformIndexingEXT = 5309u32, + InputAttachmentArrayNonUniformIndexingEXT = 5310u32, + UniformTexelBufferArrayNonUniformIndexingEXT = 5311u32, + StorageTexelBufferArrayNonUniformIndexingEXT = 5312u32, + RayTracingNV = 5340u32, + SubgroupShuffleINTEL = 5568u32, + SubgroupBufferBlockIOINTEL = 5569u32, + SubgroupImageBlockIOINTEL = 5570u32, + SubgroupImageMediaBlockIOINTEL = 5579u32, + SubgroupAvcMotionEstimationINTEL = 5696u32, + SubgroupAvcMotionEstimationIntraINTEL = 5697u32, + SubgroupAvcMotionEstimationChromaINTEL = 5698u32, + GroupNonUniformPartitionedNV = 5297u32, + VulkanMemoryModelKHR = 5345u32, + VulkanMemoryModelDeviceScopeKHR = 5346u32, + ImageFootprintNV = 5282u32, + FragmentBarycentricNV = 5284u32, + ComputeDerivativeGroupQuadsNV = 5288u32, + ComputeDerivativeGroupLinearNV = 5350u32, + FragmentDensityEXT = 5291u32, + PhysicalStorageBufferAddressesEXT = 5347u32, + CooperativeMatrixNV = 5357u32, +} +#[allow(non_upper_case_globals)] +impl Capability { + pub const StorageUniformBufferBlock16: Capability = Capability::StorageBuffer16BitAccess; + pub const StorageUniform16: Capability = Capability::UniformAndStorageBuffer16BitAccess; + pub const ShaderViewportIndexLayerNV: Capability = Capability::ShaderViewportIndexLayerEXT; + pub const ShadingRateNV: Capability = Capability::FragmentDensityEXT; + pub fn required_capabilities(self) -> &'static [Capability] { + match self { + Capability::Matrix + | Capability::Addresses + | Capability::Linkage + | Capability::Kernel + | Capability::Float16 + | Capability::Float64 + | Capability::Int64 + | Capability::Groups + | Capability::Int16 + | Capability::Int8 + | Capability::Sampled1D + | Capability::SampledBuffer + | Capability::GroupNonUniform + | Capability::SubgroupBallotKHR + | Capability::SubgroupVoteKHR + | Capability::StorageBuffer16BitAccess + | Capability::StoragePushConstant16 + | Capability::StorageInputOutput16 + | Capability::DeviceGroup + | Capability::AtomicStorageOps + | Capability::SampleMaskPostDepthCoverage + | Capability::StorageBuffer8BitAccess + | Capability::StoragePushConstant8 + | Capability::DenormPreserve + | Capability::DenormFlushToZero + | Capability::SignedZeroInfNanPreserve + | Capability::RoundingModeRTE + | Capability::RoundingModeRTZ + | Capability::SubgroupShuffleINTEL + | Capability::SubgroupBufferBlockIOINTEL + | Capability::SubgroupImageBlockIOINTEL + | Capability::SubgroupImageMediaBlockIOINTEL + | Capability::SubgroupAvcMotionEstimationINTEL + | Capability::SubgroupAvcMotionEstimationIntraINTEL + | Capability::SubgroupAvcMotionEstimationChromaINTEL + | Capability::GroupNonUniformPartitionedNV + | Capability::VulkanMemoryModelKHR + | Capability::VulkanMemoryModelDeviceScopeKHR + | Capability::ImageFootprintNV + | Capability::FragmentBarycentricNV + | Capability::ComputeDerivativeGroupQuadsNV + | Capability::ComputeDerivativeGroupLinearNV => &[], + Capability::GenericPointer => &[Capability::Addresses], + Capability::SubgroupDispatch => &[Capability::DeviceEnqueue], + Capability::GeometryPointSize + | Capability::GeometryStreams + | Capability::MultiViewport + | Capability::GeometryShaderPassthroughNV => &[Capability::Geometry], + Capability::GroupNonUniformVote + | Capability::GroupNonUniformArithmetic + | Capability::GroupNonUniformBallot + | Capability::GroupNonUniformShuffle + | Capability::GroupNonUniformShuffleRelative + | Capability::GroupNonUniformClustered + | Capability::GroupNonUniformQuad => &[Capability::GroupNonUniform], + Capability::ImageReadWrite | Capability::ImageMipmap => &[Capability::ImageBasic], + Capability::StorageTexelBufferArrayDynamicIndexingEXT => &[Capability::ImageBuffer], + Capability::StorageTexelBufferArrayNonUniformIndexingEXT => { + &[Capability::ImageBuffer, Capability::ShaderNonUniformEXT] + } + Capability::InputAttachmentArrayDynamicIndexingEXT => &[Capability::InputAttachment], + Capability::InputAttachmentArrayNonUniformIndexingEXT => { + &[Capability::InputAttachment, Capability::ShaderNonUniformEXT] + } + Capability::Int64Atomics => &[Capability::Int64], + Capability::Vector16 + | Capability::Float16Buffer + | Capability::ImageBasic + | Capability::Pipes + | Capability::DeviceEnqueue + | Capability::LiteralSampler + | Capability::NamedBarrier => &[Capability::Kernel], + Capability::Shader => &[Capability::Matrix], + Capability::PerViewAttributesNV => &[Capability::MultiView], + Capability::ShaderViewportIndexLayerEXT => &[Capability::MultiViewport], + Capability::PipeStorage => &[Capability::Pipes], + Capability::SampleMaskOverrideCoverageNV => &[Capability::SampleRateShading], + Capability::Image1D => &[Capability::Sampled1D], + Capability::ImageBuffer | Capability::UniformTexelBufferArrayDynamicIndexingEXT => { + &[Capability::SampledBuffer] + } + Capability::UniformTexelBufferArrayNonUniformIndexingEXT => { + &[Capability::SampledBuffer, Capability::ShaderNonUniformEXT] + } + Capability::ImageCubeArray => &[Capability::SampledCubeArray], + Capability::ImageRect => &[Capability::SampledRect], + Capability::Geometry + | Capability::Tessellation + | Capability::AtomicStorage + | Capability::ImageGatherExtended + | Capability::StorageImageMultisample + | Capability::UniformBufferArrayDynamicIndexing + | Capability::SampledImageArrayDynamicIndexing + | Capability::StorageBufferArrayDynamicIndexing + | Capability::StorageImageArrayDynamicIndexing + | Capability::ClipDistance + | Capability::CullDistance + | Capability::SampleRateShading + | Capability::SampledRect + | Capability::InputAttachment + | Capability::SparseResidency + | Capability::MinLod + | Capability::SampledCubeArray + | Capability::ImageMSArray + | Capability::StorageImageExtendedFormats + | Capability::ImageQuery + | Capability::DerivativeControl + | Capability::InterpolationFunction + | Capability::TransformFeedback + | Capability::StorageImageReadWithoutFormat + | Capability::StorageImageWriteWithoutFormat + | Capability::DrawParameters + | Capability::MultiView + | Capability::VariablePointersStorageBuffer + | Capability::Float16ImageAMD + | Capability::ImageGatherBiasLodAMD + | Capability::FragmentMaskAMD + | Capability::StencilExportEXT + | Capability::ImageReadWriteLodAMD + | Capability::FragmentFullyCoveredEXT + | Capability::MeshShadingNV + | Capability::ShaderNonUniformEXT + | Capability::RuntimeDescriptorArrayEXT + | Capability::RayTracingNV + | Capability::FragmentDensityEXT + | Capability::PhysicalStorageBufferAddressesEXT + | Capability::CooperativeMatrixNV => &[Capability::Shader], + Capability::UniformBufferArrayNonUniformIndexingEXT + | Capability::SampledImageArrayNonUniformIndexingEXT + | Capability::StorageBufferArrayNonUniformIndexingEXT + | Capability::StorageImageArrayNonUniformIndexingEXT => { + &[Capability::ShaderNonUniformEXT] + } + Capability::ShaderViewportMaskNV => &[Capability::ShaderViewportIndexLayerNV], + Capability::ShaderStereoViewNV => &[Capability::ShaderViewportMaskNV], + Capability::UniformAndStorageBuffer16BitAccess => &[ + Capability::StorageBuffer16BitAccess, + Capability::StorageUniformBufferBlock16, + ], + Capability::UniformAndStorageBuffer8BitAccess => &[Capability::StorageBuffer8BitAccess], + Capability::TessellationPointSize => &[Capability::Tessellation], + Capability::VariablePointers => &[Capability::VariablePointersStorageBuffer], + } + } +} +impl num_traits::FromPrimitive for Capability { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => Capability::Matrix, + 1u32 => Capability::Shader, + 2u32 => Capability::Geometry, + 3u32 => Capability::Tessellation, + 4u32 => Capability::Addresses, + 5u32 => Capability::Linkage, + 6u32 => Capability::Kernel, + 7u32 => Capability::Vector16, + 8u32 => Capability::Float16Buffer, + 9u32 => Capability::Float16, + 10u32 => Capability::Float64, + 11u32 => Capability::Int64, + 12u32 => Capability::Int64Atomics, + 13u32 => Capability::ImageBasic, + 14u32 => Capability::ImageReadWrite, + 15u32 => Capability::ImageMipmap, + 17u32 => Capability::Pipes, + 18u32 => Capability::Groups, + 19u32 => Capability::DeviceEnqueue, + 20u32 => Capability::LiteralSampler, + 21u32 => Capability::AtomicStorage, + 22u32 => Capability::Int16, + 23u32 => Capability::TessellationPointSize, + 24u32 => Capability::GeometryPointSize, + 25u32 => Capability::ImageGatherExtended, + 27u32 => Capability::StorageImageMultisample, + 28u32 => Capability::UniformBufferArrayDynamicIndexing, + 29u32 => Capability::SampledImageArrayDynamicIndexing, + 30u32 => Capability::StorageBufferArrayDynamicIndexing, + 31u32 => Capability::StorageImageArrayDynamicIndexing, + 32u32 => Capability::ClipDistance, + 33u32 => Capability::CullDistance, + 34u32 => Capability::ImageCubeArray, + 35u32 => Capability::SampleRateShading, + 36u32 => Capability::ImageRect, + 37u32 => Capability::SampledRect, + 38u32 => Capability::GenericPointer, + 39u32 => Capability::Int8, + 40u32 => Capability::InputAttachment, + 41u32 => Capability::SparseResidency, + 42u32 => Capability::MinLod, + 43u32 => Capability::Sampled1D, + 44u32 => Capability::Image1D, + 45u32 => Capability::SampledCubeArray, + 46u32 => Capability::SampledBuffer, + 47u32 => Capability::ImageBuffer, + 48u32 => Capability::ImageMSArray, + 49u32 => Capability::StorageImageExtendedFormats, + 50u32 => Capability::ImageQuery, + 51u32 => Capability::DerivativeControl, + 52u32 => Capability::InterpolationFunction, + 53u32 => Capability::TransformFeedback, + 54u32 => Capability::GeometryStreams, + 55u32 => Capability::StorageImageReadWithoutFormat, + 56u32 => Capability::StorageImageWriteWithoutFormat, + 57u32 => Capability::MultiViewport, + 58u32 => Capability::SubgroupDispatch, + 59u32 => Capability::NamedBarrier, + 60u32 => Capability::PipeStorage, + 61u32 => Capability::GroupNonUniform, + 62u32 => Capability::GroupNonUniformVote, + 63u32 => Capability::GroupNonUniformArithmetic, + 64u32 => Capability::GroupNonUniformBallot, + 65u32 => Capability::GroupNonUniformShuffle, + 66u32 => Capability::GroupNonUniformShuffleRelative, + 67u32 => Capability::GroupNonUniformClustered, + 68u32 => Capability::GroupNonUniformQuad, + 4423u32 => Capability::SubgroupBallotKHR, + 4427u32 => Capability::DrawParameters, + 4431u32 => Capability::SubgroupVoteKHR, + 4433u32 => Capability::StorageBuffer16BitAccess, + 4434u32 => Capability::UniformAndStorageBuffer16BitAccess, + 4435u32 => Capability::StoragePushConstant16, + 4436u32 => Capability::StorageInputOutput16, + 4437u32 => Capability::DeviceGroup, + 4439u32 => Capability::MultiView, + 4441u32 => Capability::VariablePointersStorageBuffer, + 4442u32 => Capability::VariablePointers, + 4445u32 => Capability::AtomicStorageOps, + 4447u32 => Capability::SampleMaskPostDepthCoverage, + 4448u32 => Capability::StorageBuffer8BitAccess, + 4449u32 => Capability::UniformAndStorageBuffer8BitAccess, + 4450u32 => Capability::StoragePushConstant8, + 4464u32 => Capability::DenormPreserve, + 4465u32 => Capability::DenormFlushToZero, + 4466u32 => Capability::SignedZeroInfNanPreserve, + 4467u32 => Capability::RoundingModeRTE, + 4468u32 => Capability::RoundingModeRTZ, + 5008u32 => Capability::Float16ImageAMD, + 5009u32 => Capability::ImageGatherBiasLodAMD, + 5010u32 => Capability::FragmentMaskAMD, + 5013u32 => Capability::StencilExportEXT, + 5015u32 => Capability::ImageReadWriteLodAMD, + 5249u32 => Capability::SampleMaskOverrideCoverageNV, + 5251u32 => Capability::GeometryShaderPassthroughNV, + 5254u32 => Capability::ShaderViewportIndexLayerEXT, + 5255u32 => Capability::ShaderViewportMaskNV, + 5259u32 => Capability::ShaderStereoViewNV, + 5260u32 => Capability::PerViewAttributesNV, + 5265u32 => Capability::FragmentFullyCoveredEXT, + 5266u32 => Capability::MeshShadingNV, + 5301u32 => Capability::ShaderNonUniformEXT, + 5302u32 => Capability::RuntimeDescriptorArrayEXT, + 5303u32 => Capability::InputAttachmentArrayDynamicIndexingEXT, + 5304u32 => Capability::UniformTexelBufferArrayDynamicIndexingEXT, + 5305u32 => Capability::StorageTexelBufferArrayDynamicIndexingEXT, + 5306u32 => Capability::UniformBufferArrayNonUniformIndexingEXT, + 5307u32 => Capability::SampledImageArrayNonUniformIndexingEXT, + 5308u32 => Capability::StorageBufferArrayNonUniformIndexingEXT, + 5309u32 => Capability::StorageImageArrayNonUniformIndexingEXT, + 5310u32 => Capability::InputAttachmentArrayNonUniformIndexingEXT, + 5311u32 => Capability::UniformTexelBufferArrayNonUniformIndexingEXT, + 5312u32 => Capability::StorageTexelBufferArrayNonUniformIndexingEXT, + 5340u32 => Capability::RayTracingNV, + 5568u32 => Capability::SubgroupShuffleINTEL, + 5569u32 => Capability::SubgroupBufferBlockIOINTEL, + 5570u32 => Capability::SubgroupImageBlockIOINTEL, + 5579u32 => Capability::SubgroupImageMediaBlockIOINTEL, + 5696u32 => Capability::SubgroupAvcMotionEstimationINTEL, + 5697u32 => Capability::SubgroupAvcMotionEstimationIntraINTEL, + 5698u32 => Capability::SubgroupAvcMotionEstimationChromaINTEL, + 5297u32 => Capability::GroupNonUniformPartitionedNV, + 5345u32 => Capability::VulkanMemoryModelKHR, + 5346u32 => Capability::VulkanMemoryModelDeviceScopeKHR, + 5282u32 => Capability::ImageFootprintNV, + 5284u32 => Capability::FragmentBarycentricNV, + 5288u32 => Capability::ComputeDerivativeGroupQuadsNV, + 5350u32 => Capability::ComputeDerivativeGroupLinearNV, + 5291u32 => Capability::FragmentDensityEXT, + 5347u32 => Capability::PhysicalStorageBufferAddressesEXT, + 5357u32 => Capability::CooperativeMatrixNV, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "SPIR-V [instructions](https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_instructions_a_instructions) opcodes"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Op { + Nop = 0u32, + Undef = 1u32, + SourceContinued = 2u32, + Source = 3u32, + SourceExtension = 4u32, + Name = 5u32, + MemberName = 6u32, + String = 7u32, + Line = 8u32, + Extension = 10u32, + ExtInstImport = 11u32, + ExtInst = 12u32, + MemoryModel = 14u32, + EntryPoint = 15u32, + ExecutionMode = 16u32, + Capability = 17u32, + TypeVoid = 19u32, + TypeBool = 20u32, + TypeInt = 21u32, + TypeFloat = 22u32, + TypeVector = 23u32, + TypeMatrix = 24u32, + TypeImage = 25u32, + TypeSampler = 26u32, + TypeSampledImage = 27u32, + TypeArray = 28u32, + TypeRuntimeArray = 29u32, + TypeStruct = 30u32, + TypeOpaque = 31u32, + TypePointer = 32u32, + TypeFunction = 33u32, + TypeEvent = 34u32, + TypeDeviceEvent = 35u32, + TypeReserveId = 36u32, + TypeQueue = 37u32, + TypePipe = 38u32, + TypeForwardPointer = 39u32, + ConstantTrue = 41u32, + ConstantFalse = 42u32, + Constant = 43u32, + ConstantComposite = 44u32, + ConstantSampler = 45u32, + ConstantNull = 46u32, + SpecConstantTrue = 48u32, + SpecConstantFalse = 49u32, + SpecConstant = 50u32, + SpecConstantComposite = 51u32, + SpecConstantOp = 52u32, + Function = 54u32, + FunctionParameter = 55u32, + FunctionEnd = 56u32, + FunctionCall = 57u32, + Variable = 59u32, + ImageTexelPointer = 60u32, + Load = 61u32, + Store = 62u32, + CopyMemory = 63u32, + CopyMemorySized = 64u32, + AccessChain = 65u32, + InBoundsAccessChain = 66u32, + PtrAccessChain = 67u32, + ArrayLength = 68u32, + GenericPtrMemSemantics = 69u32, + InBoundsPtrAccessChain = 70u32, + Decorate = 71u32, + MemberDecorate = 72u32, + DecorationGroup = 73u32, + GroupDecorate = 74u32, + GroupMemberDecorate = 75u32, + VectorExtractDynamic = 77u32, + VectorInsertDynamic = 78u32, + VectorShuffle = 79u32, + CompositeConstruct = 80u32, + CompositeExtract = 81u32, + CompositeInsert = 82u32, + CopyObject = 83u32, + Transpose = 84u32, + SampledImage = 86u32, + ImageSampleImplicitLod = 87u32, + ImageSampleExplicitLod = 88u32, + ImageSampleDrefImplicitLod = 89u32, + ImageSampleDrefExplicitLod = 90u32, + ImageSampleProjImplicitLod = 91u32, + ImageSampleProjExplicitLod = 92u32, + ImageSampleProjDrefImplicitLod = 93u32, + ImageSampleProjDrefExplicitLod = 94u32, + ImageFetch = 95u32, + ImageGather = 96u32, + ImageDrefGather = 97u32, + ImageRead = 98u32, + ImageWrite = 99u32, + Image = 100u32, + ImageQueryFormat = 101u32, + ImageQueryOrder = 102u32, + ImageQuerySizeLod = 103u32, + ImageQuerySize = 104u32, + ImageQueryLod = 105u32, + ImageQueryLevels = 106u32, + ImageQuerySamples = 107u32, + ConvertFToU = 109u32, + ConvertFToS = 110u32, + ConvertSToF = 111u32, + ConvertUToF = 112u32, + UConvert = 113u32, + SConvert = 114u32, + FConvert = 115u32, + QuantizeToF16 = 116u32, + ConvertPtrToU = 117u32, + SatConvertSToU = 118u32, + SatConvertUToS = 119u32, + ConvertUToPtr = 120u32, + PtrCastToGeneric = 121u32, + GenericCastToPtr = 122u32, + GenericCastToPtrExplicit = 123u32, + Bitcast = 124u32, + SNegate = 126u32, + FNegate = 127u32, + IAdd = 128u32, + FAdd = 129u32, + ISub = 130u32, + FSub = 131u32, + IMul = 132u32, + FMul = 133u32, + UDiv = 134u32, + SDiv = 135u32, + FDiv = 136u32, + UMod = 137u32, + SRem = 138u32, + SMod = 139u32, + FRem = 140u32, + FMod = 141u32, + VectorTimesScalar = 142u32, + MatrixTimesScalar = 143u32, + VectorTimesMatrix = 144u32, + MatrixTimesVector = 145u32, + MatrixTimesMatrix = 146u32, + OuterProduct = 147u32, + Dot = 148u32, + IAddCarry = 149u32, + ISubBorrow = 150u32, + UMulExtended = 151u32, + SMulExtended = 152u32, + Any = 154u32, + All = 155u32, + IsNan = 156u32, + IsInf = 157u32, + IsFinite = 158u32, + IsNormal = 159u32, + SignBitSet = 160u32, + LessOrGreater = 161u32, + Ordered = 162u32, + Unordered = 163u32, + LogicalEqual = 164u32, + LogicalNotEqual = 165u32, + LogicalOr = 166u32, + LogicalAnd = 167u32, + LogicalNot = 168u32, + Select = 169u32, + IEqual = 170u32, + INotEqual = 171u32, + UGreaterThan = 172u32, + SGreaterThan = 173u32, + UGreaterThanEqual = 174u32, + SGreaterThanEqual = 175u32, + ULessThan = 176u32, + SLessThan = 177u32, + ULessThanEqual = 178u32, + SLessThanEqual = 179u32, + FOrdEqual = 180u32, + FUnordEqual = 181u32, + FOrdNotEqual = 182u32, + FUnordNotEqual = 183u32, + FOrdLessThan = 184u32, + FUnordLessThan = 185u32, + FOrdGreaterThan = 186u32, + FUnordGreaterThan = 187u32, + FOrdLessThanEqual = 188u32, + FUnordLessThanEqual = 189u32, + FOrdGreaterThanEqual = 190u32, + FUnordGreaterThanEqual = 191u32, + ShiftRightLogical = 194u32, + ShiftRightArithmetic = 195u32, + ShiftLeftLogical = 196u32, + BitwiseOr = 197u32, + BitwiseXor = 198u32, + BitwiseAnd = 199u32, + Not = 200u32, + BitFieldInsert = 201u32, + BitFieldSExtract = 202u32, + BitFieldUExtract = 203u32, + BitReverse = 204u32, + BitCount = 205u32, + DPdx = 207u32, + DPdy = 208u32, + Fwidth = 209u32, + DPdxFine = 210u32, + DPdyFine = 211u32, + FwidthFine = 212u32, + DPdxCoarse = 213u32, + DPdyCoarse = 214u32, + FwidthCoarse = 215u32, + EmitVertex = 218u32, + EndPrimitive = 219u32, + EmitStreamVertex = 220u32, + EndStreamPrimitive = 221u32, + ControlBarrier = 224u32, + MemoryBarrier = 225u32, + AtomicLoad = 227u32, + AtomicStore = 228u32, + AtomicExchange = 229u32, + AtomicCompareExchange = 230u32, + AtomicCompareExchangeWeak = 231u32, + AtomicIIncrement = 232u32, + AtomicIDecrement = 233u32, + AtomicIAdd = 234u32, + AtomicISub = 235u32, + AtomicSMin = 236u32, + AtomicUMin = 237u32, + AtomicSMax = 238u32, + AtomicUMax = 239u32, + AtomicAnd = 240u32, + AtomicOr = 241u32, + AtomicXor = 242u32, + Phi = 245u32, + LoopMerge = 246u32, + SelectionMerge = 247u32, + Label = 248u32, + Branch = 249u32, + BranchConditional = 250u32, + Switch = 251u32, + Kill = 252u32, + Return = 253u32, + ReturnValue = 254u32, + Unreachable = 255u32, + LifetimeStart = 256u32, + LifetimeStop = 257u32, + GroupAsyncCopy = 259u32, + GroupWaitEvents = 260u32, + GroupAll = 261u32, + GroupAny = 262u32, + GroupBroadcast = 263u32, + GroupIAdd = 264u32, + GroupFAdd = 265u32, + GroupFMin = 266u32, + GroupUMin = 267u32, + GroupSMin = 268u32, + GroupFMax = 269u32, + GroupUMax = 270u32, + GroupSMax = 271u32, + ReadPipe = 274u32, + WritePipe = 275u32, + ReservedReadPipe = 276u32, + ReservedWritePipe = 277u32, + ReserveReadPipePackets = 278u32, + ReserveWritePipePackets = 279u32, + CommitReadPipe = 280u32, + CommitWritePipe = 281u32, + IsValidReserveId = 282u32, + GetNumPipePackets = 283u32, + GetMaxPipePackets = 284u32, + GroupReserveReadPipePackets = 285u32, + GroupReserveWritePipePackets = 286u32, + GroupCommitReadPipe = 287u32, + GroupCommitWritePipe = 288u32, + EnqueueMarker = 291u32, + EnqueueKernel = 292u32, + GetKernelNDrangeSubGroupCount = 293u32, + GetKernelNDrangeMaxSubGroupSize = 294u32, + GetKernelWorkGroupSize = 295u32, + GetKernelPreferredWorkGroupSizeMultiple = 296u32, + RetainEvent = 297u32, + ReleaseEvent = 298u32, + CreateUserEvent = 299u32, + IsValidEvent = 300u32, + SetUserEventStatus = 301u32, + CaptureEventProfilingInfo = 302u32, + GetDefaultQueue = 303u32, + BuildNDRange = 304u32, + ImageSparseSampleImplicitLod = 305u32, + ImageSparseSampleExplicitLod = 306u32, + ImageSparseSampleDrefImplicitLod = 307u32, + ImageSparseSampleDrefExplicitLod = 308u32, + ImageSparseSampleProjImplicitLod = 309u32, + ImageSparseSampleProjExplicitLod = 310u32, + ImageSparseSampleProjDrefImplicitLod = 311u32, + ImageSparseSampleProjDrefExplicitLod = 312u32, + ImageSparseFetch = 313u32, + ImageSparseGather = 314u32, + ImageSparseDrefGather = 315u32, + ImageSparseTexelsResident = 316u32, + NoLine = 317u32, + AtomicFlagTestAndSet = 318u32, + AtomicFlagClear = 319u32, + ImageSparseRead = 320u32, + SizeOf = 321u32, + TypePipeStorage = 322u32, + ConstantPipeStorage = 323u32, + CreatePipeFromPipeStorage = 324u32, + GetKernelLocalSizeForSubgroupCount = 325u32, + GetKernelMaxNumSubgroups = 326u32, + TypeNamedBarrier = 327u32, + NamedBarrierInitialize = 328u32, + MemoryNamedBarrier = 329u32, + ModuleProcessed = 330u32, + ExecutionModeId = 331u32, + DecorateId = 332u32, + GroupNonUniformElect = 333u32, + GroupNonUniformAll = 334u32, + GroupNonUniformAny = 335u32, + GroupNonUniformAllEqual = 336u32, + GroupNonUniformBroadcast = 337u32, + GroupNonUniformBroadcastFirst = 338u32, + GroupNonUniformBallot = 339u32, + GroupNonUniformInverseBallot = 340u32, + GroupNonUniformBallotBitExtract = 341u32, + GroupNonUniformBallotBitCount = 342u32, + GroupNonUniformBallotFindLSB = 343u32, + GroupNonUniformBallotFindMSB = 344u32, + GroupNonUniformShuffle = 345u32, + GroupNonUniformShuffleXor = 346u32, + GroupNonUniformShuffleUp = 347u32, + GroupNonUniformShuffleDown = 348u32, + GroupNonUniformIAdd = 349u32, + GroupNonUniformFAdd = 350u32, + GroupNonUniformIMul = 351u32, + GroupNonUniformFMul = 352u32, + GroupNonUniformSMin = 353u32, + GroupNonUniformUMin = 354u32, + GroupNonUniformFMin = 355u32, + GroupNonUniformSMax = 356u32, + GroupNonUniformUMax = 357u32, + GroupNonUniformFMax = 358u32, + GroupNonUniformBitwiseAnd = 359u32, + GroupNonUniformBitwiseOr = 360u32, + GroupNonUniformBitwiseXor = 361u32, + GroupNonUniformLogicalAnd = 362u32, + GroupNonUniformLogicalOr = 363u32, + GroupNonUniformLogicalXor = 364u32, + GroupNonUniformQuadBroadcast = 365u32, + GroupNonUniformQuadSwap = 366u32, + CopyLogical = 400u32, + PtrEqual = 401u32, + PtrNotEqual = 402u32, + PtrDiff = 403u32, + SubgroupBallotKHR = 4421u32, + SubgroupFirstInvocationKHR = 4422u32, + SubgroupAllKHR = 4428u32, + SubgroupAnyKHR = 4429u32, + SubgroupAllEqualKHR = 4430u32, + SubgroupReadInvocationKHR = 4432u32, + GroupIAddNonUniformAMD = 5000u32, + GroupFAddNonUniformAMD = 5001u32, + GroupFMinNonUniformAMD = 5002u32, + GroupUMinNonUniformAMD = 5003u32, + GroupSMinNonUniformAMD = 5004u32, + GroupFMaxNonUniformAMD = 5005u32, + GroupUMaxNonUniformAMD = 5006u32, + GroupSMaxNonUniformAMD = 5007u32, + FragmentMaskFetchAMD = 5011u32, + FragmentFetchAMD = 5012u32, + ImageSampleFootprintNV = 5283u32, + GroupNonUniformPartitionNV = 5296u32, + WritePackedPrimitiveIndices4x8NV = 5299u32, + ReportIntersectionNV = 5334u32, + IgnoreIntersectionNV = 5335u32, + TerminateRayNV = 5336u32, + TraceNV = 5337u32, + TypeAccelerationStructureNV = 5341u32, + ExecuteCallableNV = 5344u32, + TypeCooperativeMatrixNV = 5358u32, + CooperativeMatrixLoadNV = 5359u32, + CooperativeMatrixStoreNV = 5360u32, + CooperativeMatrixMulAddNV = 5361u32, + CooperativeMatrixLengthNV = 5362u32, + SubgroupShuffleINTEL = 5571u32, + SubgroupShuffleDownINTEL = 5572u32, + SubgroupShuffleUpINTEL = 5573u32, + SubgroupShuffleXorINTEL = 5574u32, + SubgroupBlockReadINTEL = 5575u32, + SubgroupBlockWriteINTEL = 5576u32, + SubgroupImageBlockReadINTEL = 5577u32, + SubgroupImageBlockWriteINTEL = 5578u32, + SubgroupImageMediaBlockReadINTEL = 5580u32, + SubgroupImageMediaBlockWriteINTEL = 5581u32, + DecorateString = 5632u32, + MemberDecorateString = 5633u32, + VmeImageINTEL = 5699u32, + TypeVmeImageINTEL = 5700u32, + TypeAvcImePayloadINTEL = 5701u32, + TypeAvcRefPayloadINTEL = 5702u32, + TypeAvcSicPayloadINTEL = 5703u32, + TypeAvcMcePayloadINTEL = 5704u32, + TypeAvcMceResultINTEL = 5705u32, + TypeAvcImeResultINTEL = 5706u32, + TypeAvcImeResultSingleReferenceStreamoutINTEL = 5707u32, + TypeAvcImeResultDualReferenceStreamoutINTEL = 5708u32, + TypeAvcImeSingleReferenceStreaminINTEL = 5709u32, + TypeAvcImeDualReferenceStreaminINTEL = 5710u32, + TypeAvcRefResultINTEL = 5711u32, + TypeAvcSicResultINTEL = 5712u32, + SubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713u32, + SubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714u32, + SubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715u32, + SubgroupAvcMceSetInterShapePenaltyINTEL = 5716u32, + SubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717u32, + SubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718u32, + SubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719u32, + SubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720u32, + SubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721u32, + SubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722u32, + SubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723u32, + SubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724u32, + SubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725u32, + SubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726u32, + SubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727u32, + SubgroupAvcMceSetAcOnlyHaarINTEL = 5728u32, + SubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729u32, + SubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730u32, + SubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731u32, + SubgroupAvcMceConvertToImePayloadINTEL = 5732u32, + SubgroupAvcMceConvertToImeResultINTEL = 5733u32, + SubgroupAvcMceConvertToRefPayloadINTEL = 5734u32, + SubgroupAvcMceConvertToRefResultINTEL = 5735u32, + SubgroupAvcMceConvertToSicPayloadINTEL = 5736u32, + SubgroupAvcMceConvertToSicResultINTEL = 5737u32, + SubgroupAvcMceGetMotionVectorsINTEL = 5738u32, + SubgroupAvcMceGetInterDistortionsINTEL = 5739u32, + SubgroupAvcMceGetBestInterDistortionsINTEL = 5740u32, + SubgroupAvcMceGetInterMajorShapeINTEL = 5741u32, + SubgroupAvcMceGetInterMinorShapeINTEL = 5742u32, + SubgroupAvcMceGetInterDirectionsINTEL = 5743u32, + SubgroupAvcMceGetInterMotionVectorCountINTEL = 5744u32, + SubgroupAvcMceGetInterReferenceIdsINTEL = 5745u32, + SubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746u32, + SubgroupAvcImeInitializeINTEL = 5747u32, + SubgroupAvcImeSetSingleReferenceINTEL = 5748u32, + SubgroupAvcImeSetDualReferenceINTEL = 5749u32, + SubgroupAvcImeRefWindowSizeINTEL = 5750u32, + SubgroupAvcImeAdjustRefOffsetINTEL = 5751u32, + SubgroupAvcImeConvertToMcePayloadINTEL = 5752u32, + SubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753u32, + SubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754u32, + SubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755u32, + SubgroupAvcImeSetWeightedSadINTEL = 5756u32, + SubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757u32, + SubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758u32, + SubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759u32, + SubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760u32, + SubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761u32, + SubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762u32, + SubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763u32, + SubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764u32, + SubgroupAvcImeConvertToMceResultINTEL = 5765u32, + SubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766u32, + SubgroupAvcImeGetDualReferenceStreaminINTEL = 5767u32, + SubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768u32, + SubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769u32, + SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770u32, + SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771u32, + SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772u32, + SubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773u32, + SubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774u32, + SubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775u32, + SubgroupAvcImeGetBorderReachedINTEL = 5776u32, + SubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777u32, + SubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778u32, + SubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779u32, + SubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780u32, + SubgroupAvcFmeInitializeINTEL = 5781u32, + SubgroupAvcBmeInitializeINTEL = 5782u32, + SubgroupAvcRefConvertToMcePayloadINTEL = 5783u32, + SubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784u32, + SubgroupAvcRefSetBilinearFilterEnableINTEL = 5785u32, + SubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786u32, + SubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787u32, + SubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788u32, + SubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789u32, + SubgroupAvcRefConvertToMceResultINTEL = 5790u32, + SubgroupAvcSicInitializeINTEL = 5791u32, + SubgroupAvcSicConfigureSkcINTEL = 5792u32, + SubgroupAvcSicConfigureIpeLumaINTEL = 5793u32, + SubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794u32, + SubgroupAvcSicGetMotionVectorMaskINTEL = 5795u32, + SubgroupAvcSicConvertToMcePayloadINTEL = 5796u32, + SubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797u32, + SubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798u32, + SubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799u32, + SubgroupAvcSicSetBilinearFilterEnableINTEL = 5800u32, + SubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801u32, + SubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802u32, + SubgroupAvcSicEvaluateIpeINTEL = 5803u32, + SubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804u32, + SubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805u32, + SubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806u32, + SubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807u32, + SubgroupAvcSicConvertToMceResultINTEL = 5808u32, + SubgroupAvcSicGetIpeLumaShapeINTEL = 5809u32, + SubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810u32, + SubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811u32, + SubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812u32, + SubgroupAvcSicGetIpeChromaModeINTEL = 5813u32, + SubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814u32, + SubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815u32, + SubgroupAvcSicGetInterRawSadsINTEL = 5816u32, +} +#[allow(non_upper_case_globals)] +impl Op { + pub const DecorateStringGOOGLE: Op = Op::DecorateString; + pub const MemberDecorateStringGOOGLE: Op = Op::MemberDecorateString; +} +impl num_traits::FromPrimitive for Op { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => Op::Nop, + 1u32 => Op::Undef, + 2u32 => Op::SourceContinued, + 3u32 => Op::Source, + 4u32 => Op::SourceExtension, + 5u32 => Op::Name, + 6u32 => Op::MemberName, + 7u32 => Op::String, + 8u32 => Op::Line, + 10u32 => Op::Extension, + 11u32 => Op::ExtInstImport, + 12u32 => Op::ExtInst, + 14u32 => Op::MemoryModel, + 15u32 => Op::EntryPoint, + 16u32 => Op::ExecutionMode, + 17u32 => Op::Capability, + 19u32 => Op::TypeVoid, + 20u32 => Op::TypeBool, + 21u32 => Op::TypeInt, + 22u32 => Op::TypeFloat, + 23u32 => Op::TypeVector, + 24u32 => Op::TypeMatrix, + 25u32 => Op::TypeImage, + 26u32 => Op::TypeSampler, + 27u32 => Op::TypeSampledImage, + 28u32 => Op::TypeArray, + 29u32 => Op::TypeRuntimeArray, + 30u32 => Op::TypeStruct, + 31u32 => Op::TypeOpaque, + 32u32 => Op::TypePointer, + 33u32 => Op::TypeFunction, + 34u32 => Op::TypeEvent, + 35u32 => Op::TypeDeviceEvent, + 36u32 => Op::TypeReserveId, + 37u32 => Op::TypeQueue, + 38u32 => Op::TypePipe, + 39u32 => Op::TypeForwardPointer, + 41u32 => Op::ConstantTrue, + 42u32 => Op::ConstantFalse, + 43u32 => Op::Constant, + 44u32 => Op::ConstantComposite, + 45u32 => Op::ConstantSampler, + 46u32 => Op::ConstantNull, + 48u32 => Op::SpecConstantTrue, + 49u32 => Op::SpecConstantFalse, + 50u32 => Op::SpecConstant, + 51u32 => Op::SpecConstantComposite, + 52u32 => Op::SpecConstantOp, + 54u32 => Op::Function, + 55u32 => Op::FunctionParameter, + 56u32 => Op::FunctionEnd, + 57u32 => Op::FunctionCall, + 59u32 => Op::Variable, + 60u32 => Op::ImageTexelPointer, + 61u32 => Op::Load, + 62u32 => Op::Store, + 63u32 => Op::CopyMemory, + 64u32 => Op::CopyMemorySized, + 65u32 => Op::AccessChain, + 66u32 => Op::InBoundsAccessChain, + 67u32 => Op::PtrAccessChain, + 68u32 => Op::ArrayLength, + 69u32 => Op::GenericPtrMemSemantics, + 70u32 => Op::InBoundsPtrAccessChain, + 71u32 => Op::Decorate, + 72u32 => Op::MemberDecorate, + 73u32 => Op::DecorationGroup, + 74u32 => Op::GroupDecorate, + 75u32 => Op::GroupMemberDecorate, + 77u32 => Op::VectorExtractDynamic, + 78u32 => Op::VectorInsertDynamic, + 79u32 => Op::VectorShuffle, + 80u32 => Op::CompositeConstruct, + 81u32 => Op::CompositeExtract, + 82u32 => Op::CompositeInsert, + 83u32 => Op::CopyObject, + 84u32 => Op::Transpose, + 86u32 => Op::SampledImage, + 87u32 => Op::ImageSampleImplicitLod, + 88u32 => Op::ImageSampleExplicitLod, + 89u32 => Op::ImageSampleDrefImplicitLod, + 90u32 => Op::ImageSampleDrefExplicitLod, + 91u32 => Op::ImageSampleProjImplicitLod, + 92u32 => Op::ImageSampleProjExplicitLod, + 93u32 => Op::ImageSampleProjDrefImplicitLod, + 94u32 => Op::ImageSampleProjDrefExplicitLod, + 95u32 => Op::ImageFetch, + 96u32 => Op::ImageGather, + 97u32 => Op::ImageDrefGather, + 98u32 => Op::ImageRead, + 99u32 => Op::ImageWrite, + 100u32 => Op::Image, + 101u32 => Op::ImageQueryFormat, + 102u32 => Op::ImageQueryOrder, + 103u32 => Op::ImageQuerySizeLod, + 104u32 => Op::ImageQuerySize, + 105u32 => Op::ImageQueryLod, + 106u32 => Op::ImageQueryLevels, + 107u32 => Op::ImageQuerySamples, + 109u32 => Op::ConvertFToU, + 110u32 => Op::ConvertFToS, + 111u32 => Op::ConvertSToF, + 112u32 => Op::ConvertUToF, + 113u32 => Op::UConvert, + 114u32 => Op::SConvert, + 115u32 => Op::FConvert, + 116u32 => Op::QuantizeToF16, + 117u32 => Op::ConvertPtrToU, + 118u32 => Op::SatConvertSToU, + 119u32 => Op::SatConvertUToS, + 120u32 => Op::ConvertUToPtr, + 121u32 => Op::PtrCastToGeneric, + 122u32 => Op::GenericCastToPtr, + 123u32 => Op::GenericCastToPtrExplicit, + 124u32 => Op::Bitcast, + 126u32 => Op::SNegate, + 127u32 => Op::FNegate, + 128u32 => Op::IAdd, + 129u32 => Op::FAdd, + 130u32 => Op::ISub, + 131u32 => Op::FSub, + 132u32 => Op::IMul, + 133u32 => Op::FMul, + 134u32 => Op::UDiv, + 135u32 => Op::SDiv, + 136u32 => Op::FDiv, + 137u32 => Op::UMod, + 138u32 => Op::SRem, + 139u32 => Op::SMod, + 140u32 => Op::FRem, + 141u32 => Op::FMod, + 142u32 => Op::VectorTimesScalar, + 143u32 => Op::MatrixTimesScalar, + 144u32 => Op::VectorTimesMatrix, + 145u32 => Op::MatrixTimesVector, + 146u32 => Op::MatrixTimesMatrix, + 147u32 => Op::OuterProduct, + 148u32 => Op::Dot, + 149u32 => Op::IAddCarry, + 150u32 => Op::ISubBorrow, + 151u32 => Op::UMulExtended, + 152u32 => Op::SMulExtended, + 154u32 => Op::Any, + 155u32 => Op::All, + 156u32 => Op::IsNan, + 157u32 => Op::IsInf, + 158u32 => Op::IsFinite, + 159u32 => Op::IsNormal, + 160u32 => Op::SignBitSet, + 161u32 => Op::LessOrGreater, + 162u32 => Op::Ordered, + 163u32 => Op::Unordered, + 164u32 => Op::LogicalEqual, + 165u32 => Op::LogicalNotEqual, + 166u32 => Op::LogicalOr, + 167u32 => Op::LogicalAnd, + 168u32 => Op::LogicalNot, + 169u32 => Op::Select, + 170u32 => Op::IEqual, + 171u32 => Op::INotEqual, + 172u32 => Op::UGreaterThan, + 173u32 => Op::SGreaterThan, + 174u32 => Op::UGreaterThanEqual, + 175u32 => Op::SGreaterThanEqual, + 176u32 => Op::ULessThan, + 177u32 => Op::SLessThan, + 178u32 => Op::ULessThanEqual, + 179u32 => Op::SLessThanEqual, + 180u32 => Op::FOrdEqual, + 181u32 => Op::FUnordEqual, + 182u32 => Op::FOrdNotEqual, + 183u32 => Op::FUnordNotEqual, + 184u32 => Op::FOrdLessThan, + 185u32 => Op::FUnordLessThan, + 186u32 => Op::FOrdGreaterThan, + 187u32 => Op::FUnordGreaterThan, + 188u32 => Op::FOrdLessThanEqual, + 189u32 => Op::FUnordLessThanEqual, + 190u32 => Op::FOrdGreaterThanEqual, + 191u32 => Op::FUnordGreaterThanEqual, + 194u32 => Op::ShiftRightLogical, + 195u32 => Op::ShiftRightArithmetic, + 196u32 => Op::ShiftLeftLogical, + 197u32 => Op::BitwiseOr, + 198u32 => Op::BitwiseXor, + 199u32 => Op::BitwiseAnd, + 200u32 => Op::Not, + 201u32 => Op::BitFieldInsert, + 202u32 => Op::BitFieldSExtract, + 203u32 => Op::BitFieldUExtract, + 204u32 => Op::BitReverse, + 205u32 => Op::BitCount, + 207u32 => Op::DPdx, + 208u32 => Op::DPdy, + 209u32 => Op::Fwidth, + 210u32 => Op::DPdxFine, + 211u32 => Op::DPdyFine, + 212u32 => Op::FwidthFine, + 213u32 => Op::DPdxCoarse, + 214u32 => Op::DPdyCoarse, + 215u32 => Op::FwidthCoarse, + 218u32 => Op::EmitVertex, + 219u32 => Op::EndPrimitive, + 220u32 => Op::EmitStreamVertex, + 221u32 => Op::EndStreamPrimitive, + 224u32 => Op::ControlBarrier, + 225u32 => Op::MemoryBarrier, + 227u32 => Op::AtomicLoad, + 228u32 => Op::AtomicStore, + 229u32 => Op::AtomicExchange, + 230u32 => Op::AtomicCompareExchange, + 231u32 => Op::AtomicCompareExchangeWeak, + 232u32 => Op::AtomicIIncrement, + 233u32 => Op::AtomicIDecrement, + 234u32 => Op::AtomicIAdd, + 235u32 => Op::AtomicISub, + 236u32 => Op::AtomicSMin, + 237u32 => Op::AtomicUMin, + 238u32 => Op::AtomicSMax, + 239u32 => Op::AtomicUMax, + 240u32 => Op::AtomicAnd, + 241u32 => Op::AtomicOr, + 242u32 => Op::AtomicXor, + 245u32 => Op::Phi, + 246u32 => Op::LoopMerge, + 247u32 => Op::SelectionMerge, + 248u32 => Op::Label, + 249u32 => Op::Branch, + 250u32 => Op::BranchConditional, + 251u32 => Op::Switch, + 252u32 => Op::Kill, + 253u32 => Op::Return, + 254u32 => Op::ReturnValue, + 255u32 => Op::Unreachable, + 256u32 => Op::LifetimeStart, + 257u32 => Op::LifetimeStop, + 259u32 => Op::GroupAsyncCopy, + 260u32 => Op::GroupWaitEvents, + 261u32 => Op::GroupAll, + 262u32 => Op::GroupAny, + 263u32 => Op::GroupBroadcast, + 264u32 => Op::GroupIAdd, + 265u32 => Op::GroupFAdd, + 266u32 => Op::GroupFMin, + 267u32 => Op::GroupUMin, + 268u32 => Op::GroupSMin, + 269u32 => Op::GroupFMax, + 270u32 => Op::GroupUMax, + 271u32 => Op::GroupSMax, + 274u32 => Op::ReadPipe, + 275u32 => Op::WritePipe, + 276u32 => Op::ReservedReadPipe, + 277u32 => Op::ReservedWritePipe, + 278u32 => Op::ReserveReadPipePackets, + 279u32 => Op::ReserveWritePipePackets, + 280u32 => Op::CommitReadPipe, + 281u32 => Op::CommitWritePipe, + 282u32 => Op::IsValidReserveId, + 283u32 => Op::GetNumPipePackets, + 284u32 => Op::GetMaxPipePackets, + 285u32 => Op::GroupReserveReadPipePackets, + 286u32 => Op::GroupReserveWritePipePackets, + 287u32 => Op::GroupCommitReadPipe, + 288u32 => Op::GroupCommitWritePipe, + 291u32 => Op::EnqueueMarker, + 292u32 => Op::EnqueueKernel, + 293u32 => Op::GetKernelNDrangeSubGroupCount, + 294u32 => Op::GetKernelNDrangeMaxSubGroupSize, + 295u32 => Op::GetKernelWorkGroupSize, + 296u32 => Op::GetKernelPreferredWorkGroupSizeMultiple, + 297u32 => Op::RetainEvent, + 298u32 => Op::ReleaseEvent, + 299u32 => Op::CreateUserEvent, + 300u32 => Op::IsValidEvent, + 301u32 => Op::SetUserEventStatus, + 302u32 => Op::CaptureEventProfilingInfo, + 303u32 => Op::GetDefaultQueue, + 304u32 => Op::BuildNDRange, + 305u32 => Op::ImageSparseSampleImplicitLod, + 306u32 => Op::ImageSparseSampleExplicitLod, + 307u32 => Op::ImageSparseSampleDrefImplicitLod, + 308u32 => Op::ImageSparseSampleDrefExplicitLod, + 309u32 => Op::ImageSparseSampleProjImplicitLod, + 310u32 => Op::ImageSparseSampleProjExplicitLod, + 311u32 => Op::ImageSparseSampleProjDrefImplicitLod, + 312u32 => Op::ImageSparseSampleProjDrefExplicitLod, + 313u32 => Op::ImageSparseFetch, + 314u32 => Op::ImageSparseGather, + 315u32 => Op::ImageSparseDrefGather, + 316u32 => Op::ImageSparseTexelsResident, + 317u32 => Op::NoLine, + 318u32 => Op::AtomicFlagTestAndSet, + 319u32 => Op::AtomicFlagClear, + 320u32 => Op::ImageSparseRead, + 321u32 => Op::SizeOf, + 322u32 => Op::TypePipeStorage, + 323u32 => Op::ConstantPipeStorage, + 324u32 => Op::CreatePipeFromPipeStorage, + 325u32 => Op::GetKernelLocalSizeForSubgroupCount, + 326u32 => Op::GetKernelMaxNumSubgroups, + 327u32 => Op::TypeNamedBarrier, + 328u32 => Op::NamedBarrierInitialize, + 329u32 => Op::MemoryNamedBarrier, + 330u32 => Op::ModuleProcessed, + 331u32 => Op::ExecutionModeId, + 332u32 => Op::DecorateId, + 333u32 => Op::GroupNonUniformElect, + 334u32 => Op::GroupNonUniformAll, + 335u32 => Op::GroupNonUniformAny, + 336u32 => Op::GroupNonUniformAllEqual, + 337u32 => Op::GroupNonUniformBroadcast, + 338u32 => Op::GroupNonUniformBroadcastFirst, + 339u32 => Op::GroupNonUniformBallot, + 340u32 => Op::GroupNonUniformInverseBallot, + 341u32 => Op::GroupNonUniformBallotBitExtract, + 342u32 => Op::GroupNonUniformBallotBitCount, + 343u32 => Op::GroupNonUniformBallotFindLSB, + 344u32 => Op::GroupNonUniformBallotFindMSB, + 345u32 => Op::GroupNonUniformShuffle, + 346u32 => Op::GroupNonUniformShuffleXor, + 347u32 => Op::GroupNonUniformShuffleUp, + 348u32 => Op::GroupNonUniformShuffleDown, + 349u32 => Op::GroupNonUniformIAdd, + 350u32 => Op::GroupNonUniformFAdd, + 351u32 => Op::GroupNonUniformIMul, + 352u32 => Op::GroupNonUniformFMul, + 353u32 => Op::GroupNonUniformSMin, + 354u32 => Op::GroupNonUniformUMin, + 355u32 => Op::GroupNonUniformFMin, + 356u32 => Op::GroupNonUniformSMax, + 357u32 => Op::GroupNonUniformUMax, + 358u32 => Op::GroupNonUniformFMax, + 359u32 => Op::GroupNonUniformBitwiseAnd, + 360u32 => Op::GroupNonUniformBitwiseOr, + 361u32 => Op::GroupNonUniformBitwiseXor, + 362u32 => Op::GroupNonUniformLogicalAnd, + 363u32 => Op::GroupNonUniformLogicalOr, + 364u32 => Op::GroupNonUniformLogicalXor, + 365u32 => Op::GroupNonUniformQuadBroadcast, + 366u32 => Op::GroupNonUniformQuadSwap, + 400u32 => Op::CopyLogical, + 401u32 => Op::PtrEqual, + 402u32 => Op::PtrNotEqual, + 403u32 => Op::PtrDiff, + 4421u32 => Op::SubgroupBallotKHR, + 4422u32 => Op::SubgroupFirstInvocationKHR, + 4428u32 => Op::SubgroupAllKHR, + 4429u32 => Op::SubgroupAnyKHR, + 4430u32 => Op::SubgroupAllEqualKHR, + 4432u32 => Op::SubgroupReadInvocationKHR, + 5000u32 => Op::GroupIAddNonUniformAMD, + 5001u32 => Op::GroupFAddNonUniformAMD, + 5002u32 => Op::GroupFMinNonUniformAMD, + 5003u32 => Op::GroupUMinNonUniformAMD, + 5004u32 => Op::GroupSMinNonUniformAMD, + 5005u32 => Op::GroupFMaxNonUniformAMD, + 5006u32 => Op::GroupUMaxNonUniformAMD, + 5007u32 => Op::GroupSMaxNonUniformAMD, + 5011u32 => Op::FragmentMaskFetchAMD, + 5012u32 => Op::FragmentFetchAMD, + 5283u32 => Op::ImageSampleFootprintNV, + 5296u32 => Op::GroupNonUniformPartitionNV, + 5299u32 => Op::WritePackedPrimitiveIndices4x8NV, + 5334u32 => Op::ReportIntersectionNV, + 5335u32 => Op::IgnoreIntersectionNV, + 5336u32 => Op::TerminateRayNV, + 5337u32 => Op::TraceNV, + 5341u32 => Op::TypeAccelerationStructureNV, + 5344u32 => Op::ExecuteCallableNV, + 5358u32 => Op::TypeCooperativeMatrixNV, + 5359u32 => Op::CooperativeMatrixLoadNV, + 5360u32 => Op::CooperativeMatrixStoreNV, + 5361u32 => Op::CooperativeMatrixMulAddNV, + 5362u32 => Op::CooperativeMatrixLengthNV, + 5571u32 => Op::SubgroupShuffleINTEL, + 5572u32 => Op::SubgroupShuffleDownINTEL, + 5573u32 => Op::SubgroupShuffleUpINTEL, + 5574u32 => Op::SubgroupShuffleXorINTEL, + 5575u32 => Op::SubgroupBlockReadINTEL, + 5576u32 => Op::SubgroupBlockWriteINTEL, + 5577u32 => Op::SubgroupImageBlockReadINTEL, + 5578u32 => Op::SubgroupImageBlockWriteINTEL, + 5580u32 => Op::SubgroupImageMediaBlockReadINTEL, + 5581u32 => Op::SubgroupImageMediaBlockWriteINTEL, + 5632u32 => Op::DecorateString, + 5633u32 => Op::MemberDecorateString, + 5699u32 => Op::VmeImageINTEL, + 5700u32 => Op::TypeVmeImageINTEL, + 5701u32 => Op::TypeAvcImePayloadINTEL, + 5702u32 => Op::TypeAvcRefPayloadINTEL, + 5703u32 => Op::TypeAvcSicPayloadINTEL, + 5704u32 => Op::TypeAvcMcePayloadINTEL, + 5705u32 => Op::TypeAvcMceResultINTEL, + 5706u32 => Op::TypeAvcImeResultINTEL, + 5707u32 => Op::TypeAvcImeResultSingleReferenceStreamoutINTEL, + 5708u32 => Op::TypeAvcImeResultDualReferenceStreamoutINTEL, + 5709u32 => Op::TypeAvcImeSingleReferenceStreaminINTEL, + 5710u32 => Op::TypeAvcImeDualReferenceStreaminINTEL, + 5711u32 => Op::TypeAvcRefResultINTEL, + 5712u32 => Op::TypeAvcSicResultINTEL, + 5713u32 => Op::SubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL, + 5714u32 => Op::SubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL, + 5715u32 => Op::SubgroupAvcMceGetDefaultInterShapePenaltyINTEL, + 5716u32 => Op::SubgroupAvcMceSetInterShapePenaltyINTEL, + 5717u32 => Op::SubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL, + 5718u32 => Op::SubgroupAvcMceSetInterDirectionPenaltyINTEL, + 5719u32 => Op::SubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL, + 5720u32 => Op::SubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL, + 5721u32 => Op::SubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL, + 5722u32 => Op::SubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL, + 5723u32 => Op::SubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL, + 5724u32 => Op::SubgroupAvcMceSetMotionVectorCostFunctionINTEL, + 5725u32 => Op::SubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL, + 5726u32 => Op::SubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL, + 5727u32 => Op::SubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL, + 5728u32 => Op::SubgroupAvcMceSetAcOnlyHaarINTEL, + 5729u32 => Op::SubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL, + 5730u32 => Op::SubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL, + 5731u32 => Op::SubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL, + 5732u32 => Op::SubgroupAvcMceConvertToImePayloadINTEL, + 5733u32 => Op::SubgroupAvcMceConvertToImeResultINTEL, + 5734u32 => Op::SubgroupAvcMceConvertToRefPayloadINTEL, + 5735u32 => Op::SubgroupAvcMceConvertToRefResultINTEL, + 5736u32 => Op::SubgroupAvcMceConvertToSicPayloadINTEL, + 5737u32 => Op::SubgroupAvcMceConvertToSicResultINTEL, + 5738u32 => Op::SubgroupAvcMceGetMotionVectorsINTEL, + 5739u32 => Op::SubgroupAvcMceGetInterDistortionsINTEL, + 5740u32 => Op::SubgroupAvcMceGetBestInterDistortionsINTEL, + 5741u32 => Op::SubgroupAvcMceGetInterMajorShapeINTEL, + 5742u32 => Op::SubgroupAvcMceGetInterMinorShapeINTEL, + 5743u32 => Op::SubgroupAvcMceGetInterDirectionsINTEL, + 5744u32 => Op::SubgroupAvcMceGetInterMotionVectorCountINTEL, + 5745u32 => Op::SubgroupAvcMceGetInterReferenceIdsINTEL, + 5746u32 => Op::SubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL, + 5747u32 => Op::SubgroupAvcImeInitializeINTEL, + 5748u32 => Op::SubgroupAvcImeSetSingleReferenceINTEL, + 5749u32 => Op::SubgroupAvcImeSetDualReferenceINTEL, + 5750u32 => Op::SubgroupAvcImeRefWindowSizeINTEL, + 5751u32 => Op::SubgroupAvcImeAdjustRefOffsetINTEL, + 5752u32 => Op::SubgroupAvcImeConvertToMcePayloadINTEL, + 5753u32 => Op::SubgroupAvcImeSetMaxMotionVectorCountINTEL, + 5754u32 => Op::SubgroupAvcImeSetUnidirectionalMixDisableINTEL, + 5755u32 => Op::SubgroupAvcImeSetEarlySearchTerminationThresholdINTEL, + 5756u32 => Op::SubgroupAvcImeSetWeightedSadINTEL, + 5757u32 => Op::SubgroupAvcImeEvaluateWithSingleReferenceINTEL, + 5758u32 => Op::SubgroupAvcImeEvaluateWithDualReferenceINTEL, + 5759u32 => Op::SubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL, + 5760u32 => Op::SubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL, + 5761u32 => Op::SubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL, + 5762u32 => Op::SubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL, + 5763u32 => Op::SubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL, + 5764u32 => Op::SubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL, + 5765u32 => Op::SubgroupAvcImeConvertToMceResultINTEL, + 5766u32 => Op::SubgroupAvcImeGetSingleReferenceStreaminINTEL, + 5767u32 => Op::SubgroupAvcImeGetDualReferenceStreaminINTEL, + 5768u32 => Op::SubgroupAvcImeStripSingleReferenceStreamoutINTEL, + 5769u32 => Op::SubgroupAvcImeStripDualReferenceStreamoutINTEL, + 5770u32 => Op::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL, + 5771u32 => Op::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL, + 5772u32 => Op::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL, + 5773u32 => Op::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL, + 5774u32 => Op::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL, + 5775u32 => Op::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL, + 5776u32 => Op::SubgroupAvcImeGetBorderReachedINTEL, + 5777u32 => Op::SubgroupAvcImeGetTruncatedSearchIndicationINTEL, + 5778u32 => Op::SubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL, + 5779u32 => Op::SubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL, + 5780u32 => Op::SubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL, + 5781u32 => Op::SubgroupAvcFmeInitializeINTEL, + 5782u32 => Op::SubgroupAvcBmeInitializeINTEL, + 5783u32 => Op::SubgroupAvcRefConvertToMcePayloadINTEL, + 5784u32 => Op::SubgroupAvcRefSetBidirectionalMixDisableINTEL, + 5785u32 => Op::SubgroupAvcRefSetBilinearFilterEnableINTEL, + 5786u32 => Op::SubgroupAvcRefEvaluateWithSingleReferenceINTEL, + 5787u32 => Op::SubgroupAvcRefEvaluateWithDualReferenceINTEL, + 5788u32 => Op::SubgroupAvcRefEvaluateWithMultiReferenceINTEL, + 5789u32 => Op::SubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL, + 5790u32 => Op::SubgroupAvcRefConvertToMceResultINTEL, + 5791u32 => Op::SubgroupAvcSicInitializeINTEL, + 5792u32 => Op::SubgroupAvcSicConfigureSkcINTEL, + 5793u32 => Op::SubgroupAvcSicConfigureIpeLumaINTEL, + 5794u32 => Op::SubgroupAvcSicConfigureIpeLumaChromaINTEL, + 5795u32 => Op::SubgroupAvcSicGetMotionVectorMaskINTEL, + 5796u32 => Op::SubgroupAvcSicConvertToMcePayloadINTEL, + 5797u32 => Op::SubgroupAvcSicSetIntraLumaShapePenaltyINTEL, + 5798u32 => Op::SubgroupAvcSicSetIntraLumaModeCostFunctionINTEL, + 5799u32 => Op::SubgroupAvcSicSetIntraChromaModeCostFunctionINTEL, + 5800u32 => Op::SubgroupAvcSicSetBilinearFilterEnableINTEL, + 5801u32 => Op::SubgroupAvcSicSetSkcForwardTransformEnableINTEL, + 5802u32 => Op::SubgroupAvcSicSetBlockBasedRawSkipSadINTEL, + 5803u32 => Op::SubgroupAvcSicEvaluateIpeINTEL, + 5804u32 => Op::SubgroupAvcSicEvaluateWithSingleReferenceINTEL, + 5805u32 => Op::SubgroupAvcSicEvaluateWithDualReferenceINTEL, + 5806u32 => Op::SubgroupAvcSicEvaluateWithMultiReferenceINTEL, + 5807u32 => Op::SubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL, + 5808u32 => Op::SubgroupAvcSicConvertToMceResultINTEL, + 5809u32 => Op::SubgroupAvcSicGetIpeLumaShapeINTEL, + 5810u32 => Op::SubgroupAvcSicGetBestIpeLumaDistortionINTEL, + 5811u32 => Op::SubgroupAvcSicGetBestIpeChromaDistortionINTEL, + 5812u32 => Op::SubgroupAvcSicGetPackedIpeLumaModesINTEL, + 5813u32 => Op::SubgroupAvcSicGetIpeChromaModeINTEL, + 5814u32 => Op::SubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL, + 5815u32 => Op::SubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL, + 5816u32 => Op::SubgroupAvcSicGetInterRawSadsINTEL, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "[GLSL.std.450](https://www.khronos.org/registry/spir-v/specs/unified1/GLSL.std.450.html) extended instruction opcode"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum GLOp { + Round = 1u32, + RoundEven = 2u32, + Trunc = 3u32, + FAbs = 4u32, + SAbs = 5u32, + FSign = 6u32, + SSign = 7u32, + Floor = 8u32, + Ceil = 9u32, + Fract = 10u32, + Radians = 11u32, + Degrees = 12u32, + Sin = 13u32, + Cos = 14u32, + Tan = 15u32, + Asin = 16u32, + Acos = 17u32, + Atan = 18u32, + Sinh = 19u32, + Cosh = 20u32, + Tanh = 21u32, + Asinh = 22u32, + Acosh = 23u32, + Atanh = 24u32, + Atan2 = 25u32, + Pow = 26u32, + Exp = 27u32, + Log = 28u32, + Exp2 = 29u32, + Log2 = 30u32, + Sqrt = 31u32, + InverseSqrt = 32u32, + Determinant = 33u32, + MatrixInverse = 34u32, + Modf = 35u32, + ModfStruct = 36u32, + FMin = 37u32, + UMin = 38u32, + SMin = 39u32, + FMax = 40u32, + UMax = 41u32, + SMax = 42u32, + FClamp = 43u32, + UClamp = 44u32, + SClamp = 45u32, + FMix = 46u32, + IMix = 47u32, + Step = 48u32, + SmoothStep = 49u32, + Fma = 50u32, + Frexp = 51u32, + FrexpStruct = 52u32, + Ldexp = 53u32, + PackSnorm4x8 = 54u32, + PackUnorm4x8 = 55u32, + PackSnorm2x16 = 56u32, + PackUnorm2x16 = 57u32, + PackHalf2x16 = 58u32, + PackDouble2x32 = 59u32, + UnpackSnorm2x16 = 60u32, + UnpackUnorm2x16 = 61u32, + UnpackHalf2x16 = 62u32, + UnpackSnorm4x8 = 63u32, + UnpackUnorm4x8 = 64u32, + UnpackDouble2x32 = 65u32, + Length = 66u32, + Distance = 67u32, + Cross = 68u32, + Normalize = 69u32, + FaceForward = 70u32, + Reflect = 71u32, + Refract = 72u32, + FindILsb = 73u32, + FindSMsb = 74u32, + FindUMsb = 75u32, + InterpolateAtCentroid = 76u32, + InterpolateAtSample = 77u32, + InterpolateAtOffset = 78u32, + NMin = 79u32, + NMax = 80u32, + NClamp = 81u32, +} +impl num_traits::FromPrimitive for GLOp { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 1u32 => GLOp::Round, + 2u32 => GLOp::RoundEven, + 3u32 => GLOp::Trunc, + 4u32 => GLOp::FAbs, + 5u32 => GLOp::SAbs, + 6u32 => GLOp::FSign, + 7u32 => GLOp::SSign, + 8u32 => GLOp::Floor, + 9u32 => GLOp::Ceil, + 10u32 => GLOp::Fract, + 11u32 => GLOp::Radians, + 12u32 => GLOp::Degrees, + 13u32 => GLOp::Sin, + 14u32 => GLOp::Cos, + 15u32 => GLOp::Tan, + 16u32 => GLOp::Asin, + 17u32 => GLOp::Acos, + 18u32 => GLOp::Atan, + 19u32 => GLOp::Sinh, + 20u32 => GLOp::Cosh, + 21u32 => GLOp::Tanh, + 22u32 => GLOp::Asinh, + 23u32 => GLOp::Acosh, + 24u32 => GLOp::Atanh, + 25u32 => GLOp::Atan2, + 26u32 => GLOp::Pow, + 27u32 => GLOp::Exp, + 28u32 => GLOp::Log, + 29u32 => GLOp::Exp2, + 30u32 => GLOp::Log2, + 31u32 => GLOp::Sqrt, + 32u32 => GLOp::InverseSqrt, + 33u32 => GLOp::Determinant, + 34u32 => GLOp::MatrixInverse, + 35u32 => GLOp::Modf, + 36u32 => GLOp::ModfStruct, + 37u32 => GLOp::FMin, + 38u32 => GLOp::UMin, + 39u32 => GLOp::SMin, + 40u32 => GLOp::FMax, + 41u32 => GLOp::UMax, + 42u32 => GLOp::SMax, + 43u32 => GLOp::FClamp, + 44u32 => GLOp::UClamp, + 45u32 => GLOp::SClamp, + 46u32 => GLOp::FMix, + 47u32 => GLOp::IMix, + 48u32 => GLOp::Step, + 49u32 => GLOp::SmoothStep, + 50u32 => GLOp::Fma, + 51u32 => GLOp::Frexp, + 52u32 => GLOp::FrexpStruct, + 53u32 => GLOp::Ldexp, + 54u32 => GLOp::PackSnorm4x8, + 55u32 => GLOp::PackUnorm4x8, + 56u32 => GLOp::PackSnorm2x16, + 57u32 => GLOp::PackUnorm2x16, + 58u32 => GLOp::PackHalf2x16, + 59u32 => GLOp::PackDouble2x32, + 60u32 => GLOp::UnpackSnorm2x16, + 61u32 => GLOp::UnpackUnorm2x16, + 62u32 => GLOp::UnpackHalf2x16, + 63u32 => GLOp::UnpackSnorm4x8, + 64u32 => GLOp::UnpackUnorm4x8, + 65u32 => GLOp::UnpackDouble2x32, + 66u32 => GLOp::Length, + 67u32 => GLOp::Distance, + 68u32 => GLOp::Cross, + 69u32 => GLOp::Normalize, + 70u32 => GLOp::FaceForward, + 71u32 => GLOp::Reflect, + 72u32 => GLOp::Refract, + 73u32 => GLOp::FindILsb, + 74u32 => GLOp::FindSMsb, + 75u32 => GLOp::FindUMsb, + 76u32 => GLOp::InterpolateAtCentroid, + 77u32 => GLOp::InterpolateAtSample, + 78u32 => GLOp::InterpolateAtOffset, + 79u32 => GLOp::NMin, + 80u32 => GLOp::NMax, + 81u32 => GLOp::NClamp, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} +#[doc = "[OpenCL.std](https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.ExtendedInstructionSet.100.html) extended instruction opcode"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum CLOp { + acos = 0u32, + acosh = 1u32, + acospi = 2u32, + asin = 3u32, + asinh = 4u32, + asinpi = 5u32, + atan = 6u32, + atan2 = 7u32, + atanh = 8u32, + atanpi = 9u32, + atan2pi = 10u32, + cbrt = 11u32, + ceil = 12u32, + copysign = 13u32, + cos = 14u32, + cosh = 15u32, + cospi = 16u32, + erfc = 17u32, + erf = 18u32, + exp = 19u32, + exp2 = 20u32, + exp10 = 21u32, + expm1 = 22u32, + fabs = 23u32, + fdim = 24u32, + floor = 25u32, + fma = 26u32, + fmax = 27u32, + fmin = 28u32, + fmod = 29u32, + fract = 30u32, + frexp = 31u32, + hypot = 32u32, + ilogb = 33u32, + ldexp = 34u32, + lgamma = 35u32, + lgamma_r = 36u32, + log = 37u32, + log2 = 38u32, + log10 = 39u32, + log1p = 40u32, + logb = 41u32, + mad = 42u32, + maxmag = 43u32, + minmag = 44u32, + modf = 45u32, + nan = 46u32, + nextafter = 47u32, + pow = 48u32, + pown = 49u32, + powr = 50u32, + remainder = 51u32, + remquo = 52u32, + rint = 53u32, + rootn = 54u32, + round = 55u32, + rsqrt = 56u32, + sin = 57u32, + sincos = 58u32, + sinh = 59u32, + sinpi = 60u32, + sqrt = 61u32, + tan = 62u32, + tanh = 63u32, + tanpi = 64u32, + tgamma = 65u32, + trunc = 66u32, + half_cos = 67u32, + half_divide = 68u32, + half_exp = 69u32, + half_exp2 = 70u32, + half_exp10 = 71u32, + half_log = 72u32, + half_log2 = 73u32, + half_log10 = 74u32, + half_powr = 75u32, + half_recip = 76u32, + half_rsqrt = 77u32, + half_sin = 78u32, + half_sqrt = 79u32, + half_tan = 80u32, + native_cos = 81u32, + native_divide = 82u32, + native_exp = 83u32, + native_exp2 = 84u32, + native_exp10 = 85u32, + native_log = 86u32, + native_log2 = 87u32, + native_log10 = 88u32, + native_powr = 89u32, + native_recip = 90u32, + native_rsqrt = 91u32, + native_sin = 92u32, + native_sqrt = 93u32, + native_tan = 94u32, + s_abs = 141u32, + s_abs_diff = 142u32, + s_add_sat = 143u32, + u_add_sat = 144u32, + s_hadd = 145u32, + u_hadd = 146u32, + s_rhadd = 147u32, + u_rhadd = 148u32, + s_clamp = 149u32, + u_clamp = 150u32, + clz = 151u32, + ctz = 152u32, + s_mad_hi = 153u32, + u_mad_sat = 154u32, + s_mad_sat = 155u32, + s_max = 156u32, + u_max = 157u32, + s_min = 158u32, + u_min = 159u32, + s_mul_hi = 160u32, + rotate = 161u32, + s_sub_sat = 162u32, + u_sub_sat = 163u32, + u_upsample = 164u32, + s_upsample = 165u32, + popcount = 166u32, + s_mad24 = 167u32, + u_mad24 = 168u32, + s_mul24 = 169u32, + u_mul24 = 170u32, + u_abs = 201u32, + u_abs_diff = 202u32, + u_mul_hi = 203u32, + u_mad_hi = 204u32, + fclamp = 95u32, + degrees = 96u32, + fmax_common = 97u32, + fmin_common = 98u32, + mix = 99u32, + radians = 100u32, + step = 101u32, + smoothstep = 102u32, + sign = 103u32, + cross = 104u32, + distance = 105u32, + length = 106u32, + normalize = 107u32, + fast_distance = 108u32, + fast_length = 109u32, + fast_normalize = 110u32, + bitselect = 186u32, + select = 187u32, + vloadn = 171u32, + vstoren = 172u32, + vload_half = 173u32, + vload_halfn = 174u32, + vstore_half = 175u32, + vstore_half_r = 176u32, + vstore_halfn = 177u32, + vstore_halfn_r = 178u32, + vloada_halfn = 179u32, + vstorea_halfn = 180u32, + vstorea_halfn_r = 181u32, + shuffle = 182u32, + shuffle2 = 183u32, + printf = 184u32, + prefetch = 185u32, +} +impl num_traits::FromPrimitive for CLOp { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 0u32 => CLOp::acos, + 1u32 => CLOp::acosh, + 2u32 => CLOp::acospi, + 3u32 => CLOp::asin, + 4u32 => CLOp::asinh, + 5u32 => CLOp::asinpi, + 6u32 => CLOp::atan, + 7u32 => CLOp::atan2, + 8u32 => CLOp::atanh, + 9u32 => CLOp::atanpi, + 10u32 => CLOp::atan2pi, + 11u32 => CLOp::cbrt, + 12u32 => CLOp::ceil, + 13u32 => CLOp::copysign, + 14u32 => CLOp::cos, + 15u32 => CLOp::cosh, + 16u32 => CLOp::cospi, + 17u32 => CLOp::erfc, + 18u32 => CLOp::erf, + 19u32 => CLOp::exp, + 20u32 => CLOp::exp2, + 21u32 => CLOp::exp10, + 22u32 => CLOp::expm1, + 23u32 => CLOp::fabs, + 24u32 => CLOp::fdim, + 25u32 => CLOp::floor, + 26u32 => CLOp::fma, + 27u32 => CLOp::fmax, + 28u32 => CLOp::fmin, + 29u32 => CLOp::fmod, + 30u32 => CLOp::fract, + 31u32 => CLOp::frexp, + 32u32 => CLOp::hypot, + 33u32 => CLOp::ilogb, + 34u32 => CLOp::ldexp, + 35u32 => CLOp::lgamma, + 36u32 => CLOp::lgamma_r, + 37u32 => CLOp::log, + 38u32 => CLOp::log2, + 39u32 => CLOp::log10, + 40u32 => CLOp::log1p, + 41u32 => CLOp::logb, + 42u32 => CLOp::mad, + 43u32 => CLOp::maxmag, + 44u32 => CLOp::minmag, + 45u32 => CLOp::modf, + 46u32 => CLOp::nan, + 47u32 => CLOp::nextafter, + 48u32 => CLOp::pow, + 49u32 => CLOp::pown, + 50u32 => CLOp::powr, + 51u32 => CLOp::remainder, + 52u32 => CLOp::remquo, + 53u32 => CLOp::rint, + 54u32 => CLOp::rootn, + 55u32 => CLOp::round, + 56u32 => CLOp::rsqrt, + 57u32 => CLOp::sin, + 58u32 => CLOp::sincos, + 59u32 => CLOp::sinh, + 60u32 => CLOp::sinpi, + 61u32 => CLOp::sqrt, + 62u32 => CLOp::tan, + 63u32 => CLOp::tanh, + 64u32 => CLOp::tanpi, + 65u32 => CLOp::tgamma, + 66u32 => CLOp::trunc, + 67u32 => CLOp::half_cos, + 68u32 => CLOp::half_divide, + 69u32 => CLOp::half_exp, + 70u32 => CLOp::half_exp2, + 71u32 => CLOp::half_exp10, + 72u32 => CLOp::half_log, + 73u32 => CLOp::half_log2, + 74u32 => CLOp::half_log10, + 75u32 => CLOp::half_powr, + 76u32 => CLOp::half_recip, + 77u32 => CLOp::half_rsqrt, + 78u32 => CLOp::half_sin, + 79u32 => CLOp::half_sqrt, + 80u32 => CLOp::half_tan, + 81u32 => CLOp::native_cos, + 82u32 => CLOp::native_divide, + 83u32 => CLOp::native_exp, + 84u32 => CLOp::native_exp2, + 85u32 => CLOp::native_exp10, + 86u32 => CLOp::native_log, + 87u32 => CLOp::native_log2, + 88u32 => CLOp::native_log10, + 89u32 => CLOp::native_powr, + 90u32 => CLOp::native_recip, + 91u32 => CLOp::native_rsqrt, + 92u32 => CLOp::native_sin, + 93u32 => CLOp::native_sqrt, + 94u32 => CLOp::native_tan, + 141u32 => CLOp::s_abs, + 142u32 => CLOp::s_abs_diff, + 143u32 => CLOp::s_add_sat, + 144u32 => CLOp::u_add_sat, + 145u32 => CLOp::s_hadd, + 146u32 => CLOp::u_hadd, + 147u32 => CLOp::s_rhadd, + 148u32 => CLOp::u_rhadd, + 149u32 => CLOp::s_clamp, + 150u32 => CLOp::u_clamp, + 151u32 => CLOp::clz, + 152u32 => CLOp::ctz, + 153u32 => CLOp::s_mad_hi, + 154u32 => CLOp::u_mad_sat, + 155u32 => CLOp::s_mad_sat, + 156u32 => CLOp::s_max, + 157u32 => CLOp::u_max, + 158u32 => CLOp::s_min, + 159u32 => CLOp::u_min, + 160u32 => CLOp::s_mul_hi, + 161u32 => CLOp::rotate, + 162u32 => CLOp::s_sub_sat, + 163u32 => CLOp::u_sub_sat, + 164u32 => CLOp::u_upsample, + 165u32 => CLOp::s_upsample, + 166u32 => CLOp::popcount, + 167u32 => CLOp::s_mad24, + 168u32 => CLOp::u_mad24, + 169u32 => CLOp::s_mul24, + 170u32 => CLOp::u_mul24, + 201u32 => CLOp::u_abs, + 202u32 => CLOp::u_abs_diff, + 203u32 => CLOp::u_mul_hi, + 204u32 => CLOp::u_mad_hi, + 95u32 => CLOp::fclamp, + 96u32 => CLOp::degrees, + 97u32 => CLOp::fmax_common, + 98u32 => CLOp::fmin_common, + 99u32 => CLOp::mix, + 100u32 => CLOp::radians, + 101u32 => CLOp::step, + 102u32 => CLOp::smoothstep, + 103u32 => CLOp::sign, + 104u32 => CLOp::cross, + 105u32 => CLOp::distance, + 106u32 => CLOp::length, + 107u32 => CLOp::normalize, + 108u32 => CLOp::fast_distance, + 109u32 => CLOp::fast_length, + 110u32 => CLOp::fast_normalize, + 186u32 => CLOp::bitselect, + 187u32 => CLOp::select, + 171u32 => CLOp::vloadn, + 172u32 => CLOp::vstoren, + 173u32 => CLOp::vload_half, + 174u32 => CLOp::vload_halfn, + 175u32 => CLOp::vstore_half, + 176u32 => CLOp::vstore_half_r, + 177u32 => CLOp::vstore_halfn, + 178u32 => CLOp::vstore_halfn_r, + 179u32 => CLOp::vloada_halfn, + 180u32 => CLOp::vstorea_halfn, + 181u32 => CLOp::vstorea_halfn_r, + 182u32 => CLOp::shuffle, + 183u32 => CLOp::shuffle2, + 184u32 => CLOp::printf, + 185u32 => CLOp::prefetch, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +} diff --git a/third_party/rust/spirv_headers/lib.rs b/third_party/rust/spirv_headers/lib.rs new file mode 100644 index 000000000000..fb19493aab29 --- /dev/null +++ b/third_party/rust/spirv_headers/lib.rs @@ -0,0 +1,16 @@ +#![doc(html_root_url = "https://docs.rs/spirv_headers/1.4/")] + +//! The SPIR-V header. +//! +//! This crate contains Rust definitions of all SPIR-V structs, enums, +//! and constants. +//! +//! The version of this crate is the version of SPIR-V it contains. + +#![allow(non_camel_case_types)] +#![cfg_attr(rustfmt, rustfmt_skip)] + +use bitflags::bitflags; +use num_traits; + +include!("autogen_spirv.rs");