diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 082078823..1a1cb04a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,6 +178,9 @@ jobs: - name: check web if: matrix.kind == 'web' run: | + # build with no features + cargo ${{matrix.tool}} --target ${{ matrix.target }} -p wgpu --no-default-features + # build examples cargo ${{matrix.tool}} --target ${{ matrix.target }} -p wgpu --examples @@ -194,7 +197,7 @@ jobs: if: matrix.kind == 'em' run: | # build for Emscripten/WebGL - cargo ${{matrix.tool}} --target ${{ matrix.target }} -p wgpu -p wgpu-hal --features webgl,emscripten + cargo ${{matrix.tool}} --target ${{ matrix.target }} -p wgpu -p wgpu-hal --no-default-features --features webgl,emscripten # build raw-gles example cargo ${{matrix.tool}} --target ${{ matrix.target }} --example raw-gles --features webgl,emscripten @@ -203,7 +206,7 @@ jobs: if: matrix.kind == 'local' || matrix.kind == 'other' run: | # check with no features - cargo ${{matrix.tool}} --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player + cargo ${{matrix.tool}} --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player --no-default-features # check with all features # explicitly don't mention wgpu-hal so that --all-features don't apply to it diff --git a/CHANGELOG.md b/CHANGELOG.md index 83a731305..d427e7579 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,10 @@ Bottom level categories: - Convert all `Default` Implementations on Enums to `derive(Default)` - Implement `Default` for `CompositeAlphaMode` +### Added/New Features + +Add the `"wgsl"` feature, to enable WGSL shaders in `wgpu-core` and `wgpu`. Enabled by default in `wgpu`. By @daxpedda in [#2890](https://github.com/gfx-rs/wgpu/pull/2890). + ### Bug Fixes #### General diff --git a/deno_webgpu/Cargo.toml b/deno_webgpu/Cargo.toml index e144dcc7d..ea7cbf53a 100644 --- a/deno_webgpu/Cargo.toml +++ b/deno_webgpu/Cargo.toml @@ -14,5 +14,5 @@ description = "WebGPU implementation for Deno" deno_core = "0.151.0" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.19", features = ["full"] } -wgpu-core = { path = "../wgpu-core", features = ["trace", "replay", "serde", "strict_asserts"] } +wgpu-core = { path = "../wgpu-core", features = ["trace", "replay", "serde", "strict_asserts", "wgsl"] } wgpu-types = { path = "../wgpu-types", features = ["trace", "replay", "serde"] } diff --git a/player/Cargo.toml b/player/Cargo.toml index fa90877d8..8cfbbcff8 100644 --- a/player/Cargo.toml +++ b/player/Cargo.toml @@ -29,7 +29,7 @@ features = ["replay"] [dependencies.wgc] path = "../wgpu-core" package = "wgpu-core" -features = ["replay", "raw-window-handle", "strict_asserts"] +features = ["replay", "raw-window-handle", "strict_asserts", "wgsl"] [dev-dependencies] serde = "1" diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 73792f798..8dd063212 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -24,6 +24,8 @@ replay = ["serde", "wgt/replay", "arrayvec/serde", "naga/deserialize"] # Enable serializable compute/render passes, and bundle encoders. serial-pass = ["serde", "wgt/serde", "arrayvec/serde"] id32 = [] +# Enable `ShaderModuleSource::Wgsl` +wgsl = ["naga/wgsl-in"] vulkan-portability = ["hal/vulkan"] [dependencies] @@ -46,7 +48,7 @@ thiserror = "1" git = "https://github.com/gfx-rs/naga" rev = "c52d9102" version = "0.10" -features = ["clone", "span", "validate", "wgsl-in"] +features = ["clone", "span", "validate"] [dependencies.wgt] path = "../wgpu-types" diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 2da5fa43a..8f3e5ce4d 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1203,6 +1203,7 @@ impl Device { source: pipeline::ShaderModuleSource<'a>, ) -> Result, pipeline::CreateShaderModuleError> { let (module, source) = match source { + #[cfg(feature = "wgsl")] pipeline::ShaderModuleSource::Wgsl(code) => { profiling::scope!("naga::wgsl::parse_str"); let module = naga::front::wgsl::parse_str(&code).map_err(|inner| { @@ -1215,6 +1216,7 @@ impl Device { (Cow::Owned(module), code.into_owned()) } pipeline::ShaderModuleSource::Naga(module) => (module, String::new()), + pipeline::ShaderModuleSource::Dummy(_) => panic!("found `ShaderModuleSource::Dummy`"), }; for (_, var) in module.global_variables.iter() { match var.binding { @@ -4397,6 +4399,7 @@ impl Global { if let Some(ref trace) = device.trace { let mut trace = trace.lock(); let data = match source { + #[cfg(feature = "wgsl")] pipeline::ShaderModuleSource::Wgsl(ref code) => { trace.make_binary("wgsl", code.as_bytes()) } @@ -4406,6 +4409,9 @@ impl Global { .unwrap(); trace.make_binary("ron", string.as_bytes()) } + pipeline::ShaderModuleSource::Dummy(_) => { + panic!("found `ShaderModuleSource::Dummy`") + } }; trace.add(trace::Action::CreateShaderModule { id: fid.id(), diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 2b0e0804a..667b8b96e 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -6,7 +6,7 @@ use crate::{ validation, Label, LifeGuard, Stored, }; use arrayvec::ArrayVec; -use std::{borrow::Cow, error::Error, fmt, num::NonZeroU32}; +use std::{borrow::Cow, error::Error, fmt, marker::PhantomData, num::NonZeroU32}; use thiserror::Error; /// Information about buffer bindings, which @@ -20,8 +20,13 @@ pub(crate) struct LateSizedBufferGroup { #[allow(clippy::large_enum_variant)] pub enum ShaderModuleSource<'a> { + #[cfg(feature = "wgsl")] Wgsl(Cow<'a, str>), Naga(Cow<'static, naga::Module>), + /// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it + /// could be the last one active. + #[doc(hidden)] + Dummy(PhantomData<&'a ()>), } #[derive(Clone, Debug)] @@ -63,6 +68,7 @@ pub struct ShaderError { pub label: Option, pub inner: E, } +#[cfg(feature = "wgsl")] impl fmt::Display for ShaderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let label = self.label.as_deref().unwrap_or_default(); @@ -114,6 +120,7 @@ where //Note: `Clone` would require `WithSpan: Clone`. #[derive(Debug, Error)] pub enum CreateShaderModuleError { + #[cfg(feature = "wgsl")] #[error(transparent)] Parsing(#[from] ShaderError), #[error("Failed to generate the backend-specific code")] @@ -137,6 +144,7 @@ pub enum CreateShaderModuleError { impl CreateShaderModuleError { pub fn location(&self, source: &str) -> Option { match *self { + #[cfg(feature = "wgsl")] CreateShaderModuleError::Parsing(ref err) => err.inner.location(source), CreateShaderModuleError::Validation(ref err) => err.inner.location(source), _ => None, diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 8eb2c3c66..c7c5a76bb 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -8,7 +8,7 @@ homepage = "https://github.com/gfx-rs/wgpu" repository = "https://github.com/gfx-rs/wgpu" keywords = ["graphics"] license = "MIT OR Apache-2.0" -rust-version = "1.59" +rust-version = "1.60" [lib] diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 50dc584f1..1d9909c43 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -76,9 +76,10 @@ name = "water" test = true [features] -default = [] +default = ["wgsl"] spirv = ["naga/spv-in"] glsl = ["naga/glsl-in"] +wgsl = ["wgc?/wgsl"] trace = ["serde", "wgc/trace"] replay = ["serde", "wgc/replay"] angle = ["wgc/angle"] diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 8b4e3e8b7..93b313205 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1094,6 +1094,15 @@ impl crate::Context for Context { } } + #[cfg_attr( + not(any( + feature = "spirv", + feature = "glsl", + feature = "wgsl", + feature = "naga" + )), + allow(unreachable_code, unused_variables) + )] fn device_create_shader_module( &self, device: &Self::DeviceId, @@ -1134,9 +1143,11 @@ impl crate::Context for Context { wgc::pipeline::ShaderModuleSource::Naga(std::borrow::Cow::Owned(module)) } + #[cfg(feature = "wgsl")] ShaderSource::Wgsl(ref code) => wgc::pipeline::ShaderModuleSource::Wgsl(Borrowed(code)), #[cfg(feature = "naga")] ShaderSource::Naga(module) => wgc::pipeline::ShaderModuleSource::Naga(module), + ShaderSource::Dummy(_) => panic!("found `ShaderSource::Dummy`"), }; let (id, error) = wgc::gfx_select!( device.id => global.device_create_shader_module(device.id, &descriptor, source, ()) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 4bc158247..f92b06e7a 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1335,13 +1335,22 @@ impl crate::Context for Context { wgt::DownlevelCapabilities::default() } + #[cfg_attr( + not(any( + feature = "spirv", + feature = "glsl", + feature = "wgsl", + feature = "naga" + )), + allow(unreachable_code, unused_variables) + )] fn device_create_shader_module( &self, device: &Self::DeviceId, desc: crate::ShaderModuleDescriptor, _shader_bound_checks: wgt::ShaderBoundChecks, ) -> Self::ShaderModuleId { - let mut descriptor = match desc.source { + let mut descriptor: web_sys::GpuShaderModuleDescriptor = match desc.source { #[cfg(feature = "spirv")] crate::ShaderSource::SpirV(ref spv) => { use naga::{back, front, valid}; @@ -1393,6 +1402,7 @@ impl crate::Context for Context { .unwrap(); web_sys::GpuShaderModuleDescriptor::new(wgsl_text.as_str()) } + #[cfg(feature = "wgsl")] crate::ShaderSource::Wgsl(ref code) => web_sys::GpuShaderModuleDescriptor::new(code), #[cfg(feature = "naga")] crate::ShaderSource::Naga(module) => { @@ -1409,6 +1419,9 @@ impl crate::Context for Context { back::wgsl::write_string(&module, &module_info, writer_flags).unwrap(); web_sys::GpuShaderModuleDescriptor::new(wgsl_text.as_str()) } + crate::ShaderSource::Dummy(_) => { + panic!("found `ShaderSource::Dummy`") + } }; if let Some(label) = desc.label { descriptor.label(label); diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 912989572..9ee5c370a 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -858,11 +858,17 @@ pub enum ShaderSource<'a> { defines: naga::FastHashMap, }, /// WGSL module as a string slice. + #[cfg(feature = "wgsl")] + #[cfg_attr(docsrs, doc(cfg(feature = "wgsl")))] Wgsl(Cow<'a, str>), /// Naga module. #[cfg(feature = "naga")] #[cfg_attr(docsrs, doc(cfg(feature = "naga")))] Naga(Cow<'static, naga::Module>), + /// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it + /// could be the last one active. + #[doc(hidden)] + Dummy(PhantomData<&'a ()>), } static_assertions::assert_impl_all!(ShaderSource: Send, Sync);