From 58f6fa94a2251665819ec8747287fab1ef151086 Mon Sep 17 00:00:00 2001 From: Rich Churcher Date: Mon, 23 Sep 2024 02:51:14 +1200 Subject: [PATCH] Spirv passthrough main (adopted, part deux) (#15352) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Note:** This is an adoption of @Shfty 's adoption (#8131) of #3996! All I've done is updated the branch and run the docs CI. > **Note:** This is an adoption of #3996, originally authored by @molikto > > # Objective > Allow use of `wgpu::Features::SPIRV_SHADER_PASSTHROUGH` and the corresponding `wgpu::Device::create_shader_module_spirv` for SPIR-V shader assets. > > This enables use-cases where naga is not sufficient to load a given (valid) SPIR-V module, i.e. cases where naga lacks support for a given SPIR-V feature employed by a third-party codegen backend like `rust-gpu`. > > ## Solution > * Reimplemented the changes from [Spirv shader bypass #3996](https://github.com/bevyengine/bevy/pull/3996), on account of the original branch having been deleted. > * Documented the new `spirv_shader_passthrough` feature flag with the appropriate platform support context from [wgpu's documentation](https://docs.rs/wgpu/latest/wgpu/struct.Features.html#associatedconstant.SPIRV_SHADER_PASSTHROUGH). > > ## Changelog > * Adds a `spirv_shader_passthrough` feature flag to the following crates: > > * `bevy` > * `bevy_internal` > * `bevy_render` > * Extends `RenderDevice::create_shader_module` with a conditional call to `wgpu::Device::create_shader_module_spirv` if `spirv_shader_passthrough` is enabled and `wgpu::Features::SPIRV_SHADER_PASSTHROUGH` is present for the current platform. > * Documents the relevant `wgpu` platform support in `docs/cargo_features.md` --------- Co-authored-by: Josh Palmer <1253239+Shfty@users.noreply.github.com> Co-authored-by: Alice Cecile --- Cargo.toml | 3 +++ crates/bevy_internal/Cargo.toml | 3 +++ crates/bevy_render/Cargo.toml | 3 +++ .../bevy_render/src/renderer/render_device.rs | 22 +++++++++++++++++++ docs/cargo_features.md | 1 + 5 files changed, 32 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7186adb940..e913e3ef58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -164,6 +164,9 @@ bevy_gizmos = ["bevy_internal/bevy_gizmos", "bevy_color"] # Provides a collection of developer tools bevy_dev_tools = ["bevy_internal/bevy_dev_tools"] +# Enable passthrough loading for SPIR-V shaders (Only supported on Vulkan, shader capabilities and extensions must agree with the platform implementation) +spirv_shader_passthrough = ["bevy_internal/spirv_shader_passthrough"] + # Tracing support, saving a file in Chrome Tracing format trace_chrome = ["trace", "bevy_internal/trace_chrome"] diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 2cd6e22162..9550379682 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -44,6 +44,9 @@ ktx2 = ["bevy_render/ktx2"] zlib = ["bevy_render/zlib"] zstd = ["bevy_render/zstd"] +# Enable SPIR-V passthrough +spirv_shader_passthrough = ["bevy_render/spirv_shader_passthrough"] + # Include tonemapping LUT KTX2 files. tonemapping_luts = ["bevy_core_pipeline/tonemapping_luts"] diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 834fca03f1..628b5e6e21 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -27,6 +27,9 @@ shader_format_spirv = ["wgpu/spirv", "naga/spv-in", "naga/spv-out"] zlib = ["flate2"] zstd = ["ruzstd"] +# Enable SPIR-V shader passthrough +spirv_shader_passthrough = [] + trace = ["profiling"] tracing-tracy = [] ci_limits = [] diff --git a/crates/bevy_render/src/renderer/render_device.rs b/crates/bevy_render/src/renderer/render_device.rs index 1c0b26b912..4c2e41186f 100644 --- a/crates/bevy_render/src/renderer/render_device.rs +++ b/crates/bevy_render/src/renderer/render_device.rs @@ -49,6 +49,28 @@ impl RenderDevice { /// Creates a [`ShaderModule`](wgpu::ShaderModule) from either SPIR-V or WGSL source code. #[inline] pub fn create_shader_module(&self, desc: wgpu::ShaderModuleDescriptor) -> wgpu::ShaderModule { + #[cfg(feature = "spirv_shader_passthrough")] + match &desc.source { + wgpu::ShaderSource::SpirV(source) + if self + .features() + .contains(wgpu::Features::SPIRV_SHADER_PASSTHROUGH) => + { + // SAFETY: + // This call passes binary data to the backend as-is and can potentially result in a driver crash or bogus behaviour. + // No attempt is made to ensure that data is valid SPIR-V. + unsafe { + self.device + .create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV { + label: desc.label, + source: source.clone(), + }) + } + } + _ => self.device.create_shader_module(desc), + } + + #[cfg(not(feature = "spirv_shader_passthrough"))] self.device.create_shader_module(desc) } diff --git a/docs/cargo_features.md b/docs/cargo_features.md index c360c2eb8c..ca6b982b71 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -78,6 +78,7 @@ The default feature set enables most of the expected features of a game engine, |serialize|Enable serialization support through serde| |shader_format_glsl|Enable support for shaders in GLSL| |shader_format_spirv|Enable support for shaders in SPIR-V| +|spirv_shader_passthrough|Enable passthrough loading for SPIR-V shaders (Only supported on Vulkan, shader capabilities and extensions must agree with the platform implementation)| |symphonia-aac|AAC audio format support (through symphonia)| |symphonia-all|AAC, FLAC, MP3, MP4, OGG/VORBIS, and WAV audio formats support (through symphonia)| |symphonia-flac|FLAC audio format support (through symphonia)|