Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ Difference for SPIR-V passthrough:
```
This allows using precompiled shaders without manually checking which backend's code to pass, for example if you have shaders precompiled for both DXIL and SPIR-V.

#### `EXPERIMENTAL_*` features now require unsafe code to enable

We want to be able to expose potentially experimental features to our users before we have ensured that they are fully sound to use.
As such, we now require any feature that is prefixed with `EXPERIMENTAL` to have a special unsafe token enabled in the device descriptor
acknowledging that the features may still have bugs in them and to report any they find.

```rust
adapter.request_device(&wgpu::DeviceDescriptor {
features: wgpu::Features::EXPERIMENTAL_MESH_SHADER,
experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() }
..
})
```

By @cwfitzgerald in [#8163](https://github.com/gfx-rs/wgpu/pull/8163).

#### Multi-draw indirect is now unconditionally supported when indirect draws are supported

Expand Down
1 change: 1 addition & 0 deletions benches/benches/wgpu-benchmark/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ impl DeviceState {
required_features: adapter.features(),
required_limits: adapter.limits(),
memory_hints: wgpu::MemoryHints::Performance,
experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() },
label: Some("Compute/RenderPass Device"),
trace: wgpu::Trace::Off,
}))
Expand Down
1 change: 1 addition & 0 deletions deno_webgpu/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ impl GPUAdapter {
descriptor.required_features,
),
required_limits,
experimental_features: wgpu_types::ExperimentalFeatures::disabled(),
memory_hints: Default::default(),
trace,
};
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ impl ExampleContext {
required_features: (E::optional_features() & adapter.features())
| E::required_features(),
required_limits: needed_limits,
experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() },
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: match std::env::var_os("WGPU_TRACE") {
Some(path) => wgpu::Trace::Directory(path.into()),
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/hello_synchronization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ async fn run() {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::Performance,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/hello_triangle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
// Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
.using_resolution(adapter.limits()),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/hello_windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ async fn run(event_loop: EventLoop<()>, viewports: Vec<(Arc<Window>, wgpu::Color
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/hello_workgroups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ async fn run() {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/render_to_texture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ async fn run(_path: Option<String>) {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/repeated_compute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ impl WgpuContext {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::Performance,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/storage_texture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ async fn run(_path: Option<String>) {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/timestamp_queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ async fn run() {
label: None,
required_features: features,
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/features/src/uniform_values/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ impl WgpuContext {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
1 change: 1 addition & 0 deletions examples/standalone/01_hello_compute/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ fn main() {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
experimental_features: wgpu::ExperimentalFeatures::disabled(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
}))
Expand Down
1 change: 1 addition & 0 deletions player/tests/player/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl Test<'_> {
label: None,
required_features: self.features,
required_limits: wgt::Limits::default(),
experimental_features: unsafe { wgt::ExperimentalFeatures::enabled() },
memory_hints: wgt::MemoryHints::default(),
trace: wgt::Trace::Off,
},
Expand Down
1 change: 1 addition & 0 deletions tests/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ pub async fn initialize_device(
label: None,
required_features: features,
required_limits: limits,
experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() },
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
})
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/wgpu-gpu/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ async fn request_device_error_message() {
let expected = "TypeError";
} else {
// This message appears whenever wgpu-core is used as the implementation.
let expected = "Unsupported features were requested: Features {";
let expected = "Unsupported features were requested:";
}
}
assert!(device_error.contains(expected), "{device_error}");
Expand Down
70 changes: 70 additions & 0 deletions tests/tests/wgpu-validation/api/experimental.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
fn noop_adapter() -> wgpu::Adapter {
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
backends: wgpu::Backends::NOOP,
backend_options: wgpu::BackendOptions {
noop: wgpu::NoopBackendOptions { enable: true },
..Default::default()
},
..Default::default()
});

pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions::default()))
.expect("noop backend adapter absent when it should be")
}

#[test]
fn request_no_experimental_features() {
let adapter = noop_adapter();

let dq = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
// Not experimental
required_features: wgpu::Features::FLOAT32_FILTERABLE,
experimental_features: wgpu::ExperimentalFeatures::disabled(),
..Default::default()
}));

assert!(dq.is_ok());
}

#[test]
fn request_experimental_features() {
let adapter = noop_adapter();

let dq = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
// Experimental
required_features: wgpu::Features::EXPERIMENTAL_MESH_SHADER,
experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() },
..Default::default()
}));

assert!(dq.is_ok());
}

#[test]
fn request_experimental_features_when_not_enabled() {
let adapter = noop_adapter();

let dq = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
// Experimental
required_features: wgpu::Features::EXPERIMENTAL_MESH_SHADER,
experimental_features: wgpu::ExperimentalFeatures::disabled(),
..Default::default()
}));

assert!(dq.is_err());
}

#[test]
fn request_multiple_experimental_features_when_not_enabled() {
let adapter = noop_adapter();

let dq = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
// Experimental
required_features: wgpu::Features::EXPERIMENTAL_MESH_SHADER
| wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS,
experimental_features: wgpu::ExperimentalFeatures::disabled(),
..Default::default()
}));

assert!(dq.is_err());
}
1 change: 1 addition & 0 deletions tests/tests/wgpu-validation/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod binding_arrays;
mod buffer;
mod buffer_slice;
mod device;
mod experimental;
mod external_texture;
mod instance;
mod texture;
18 changes: 17 additions & 1 deletion wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,18 @@ impl Adapter {
));
}

// Check if experimental features are permitted to be enabled.
if desc
.required_features
.intersects(wgt::Features::all_experimental_mask())
&& !desc.experimental_features.is_enabled()
{
return Err(RequestDeviceError::ExperimentalFeaturesNotEnabled(
desc.required_features
.intersection(wgt::Features::all_experimental_mask()),
));
}

let caps = &self.raw.capabilities;
if Backends::PRIMARY.contains(Backends::from(self.backend()))
&& !caps.downlevel.is_webgpu_compliant()
Expand Down Expand Up @@ -857,8 +869,12 @@ pub enum RequestDeviceError {
LimitsExceeded(#[from] FailedLimit),
#[error("Failed to initialize Timestamp Normalizer")]
TimestampNormalizerInitFailed(#[from] TimestampNormalizerInitError),
#[error("Unsupported features were requested: {0:?}")]
#[error("Unsupported features were requested: {0}")]
UnsupportedFeature(wgt::Features),
#[error(
"Some experimental features, {0}, were requested, but experimental features are not enabled"
)]
ExperimentalFeaturesNotEnabled(wgt::Features),
}

#[derive(Clone, Debug, Error)]
Expand Down
22 changes: 22 additions & 0 deletions wgpu-types/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,19 @@ impl Features {
]))
}

/// Mask of all features which are experimental.
#[must_use]
pub const fn all_experimental_mask() -> Self {
Self::from_bits_truncate(FeatureBits([
FeaturesWGPU::EXPERIMENTAL_MESH_SHADER.bits()
| FeaturesWGPU::EXPERIMENTAL_MESH_SHADER_MULTIVIEW.bits()
| FeaturesWGPU::EXPERIMENTAL_RAY_QUERY.bits()
| FeaturesWGPU::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN.bits()
| FeaturesWGPU::EXPERIMENTAL_PASSTHROUGH_SHADERS.bits(),
FeaturesWebGPU::empty().bits(),
]))
}

/// Vertex formats allowed for creating and building BLASes
#[must_use]
pub fn allowed_vertex_formats_for_blas(&self) -> Vec<VertexFormat> {
Expand Down Expand Up @@ -1620,4 +1633,13 @@ mod tests {
)
);
}

#[test]
fn experimental_features_part_of_experimental_mask() {
for (name, feature) in Features::all().iter_names() {
let prefixed_with_experimental = name.starts_with("EXPERIMENTAL_");
let in_experimental_mask = Features::all_experimental_mask().contains(feature);
assert_eq!(in_experimental_mask, prefixed_with_experimental);
}
}
}
6 changes: 6 additions & 0 deletions wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ pub mod error;
mod features;
pub mod instance;
pub mod math;
mod tokens;
mod transfers;

pub use counters::*;
pub use features::*;
pub use instance::*;
pub use tokens::*;
pub use transfers::*;

/// Integral type used for [`Buffer`] offsets and sizes.
Expand Down Expand Up @@ -1462,6 +1464,9 @@ pub struct DeviceDescriptor<L> {
/// Exactly the specified limits, and no better or worse,
/// will be allowed in validation of API calls on the resulting device.
pub required_limits: Limits,
/// Specifies whether `self.required_features` is allowed to contain experimental features.
#[cfg_attr(feature = "serde", serde(skip))]
pub experimental_features: ExperimentalFeatures,
/// Hints for memory allocation strategies.
pub memory_hints: MemoryHints,
/// Whether API tracing for debugging is enabled,
Expand All @@ -1477,6 +1482,7 @@ impl<L> DeviceDescriptor<L> {
label: fun(&self.label),
required_features: self.required_features,
required_limits: self.required_limits.clone(),
experimental_features: self.experimental_features,
memory_hints: self.memory_hints.clone(),
trace: self.trace.clone(),
}
Expand Down
43 changes: 43 additions & 0 deletions wgpu-types/src/tokens.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/// Token of the user agreeing to access experimental features.
#[derive(Debug, Default, Copy, Clone)]
pub struct ExperimentalFeatures {
enabled: bool,
}

impl ExperimentalFeatures {
/// Uses of [`Features`] prefixed with "EXPERIMENTAL" are disallowed.
///
/// [`Features`]: ../wgpu/struct.Features.html
pub const fn disabled() -> Self {
Self { enabled: false }
}

/// Uses of [`Features`] prefixed with "EXPERIMENTAL" may result
/// in undefined behavior when used incorrectly. The exact bounds
/// of these issues varies by the feature. These instances are
/// inherently bugs in our implementation that we will eventually fix.
///
/// By giving access to still work-in-progress APIs, users can get
/// access to newer technology sooner, and we can work with users
/// to fix bugs quicker.
///
/// Look inside our repo at the [`api-specs`] for more information
/// on various experimental apis.
///
/// # Safety
///
/// - You acknowledge that there may be UB-containing bugs in these
/// apis and those may be hit by calling otherwise safe code.
/// - You agree to report any such bugs to us, if you find them.
///
/// [`Features`]: ../wgpu/struct.Features.html
/// [`api-specs`]: https://github.com/gfx-rs/wgpu/tree/trunk/docs/api-specs
pub const unsafe fn enabled() -> Self {
Self { enabled: true }
}

/// Returns true if the user has agreed to access experimental features.
pub const fn is_enabled(&self) -> bool {
self.enabled
}
}
2 changes: 1 addition & 1 deletion wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub use wgt::{
CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, CopyExternalImageDestInfo,
CoreCounters, DepthBiasState, DepthStencilState, DeviceLostReason, DeviceType,
DownlevelCapabilities, DownlevelFlags, DownlevelLimits, Dx12BackendOptions, Dx12Compiler,
DxcShaderModel, DynamicOffset, Extent3d, ExternalTextureFormat,
DxcShaderModel, DynamicOffset, ExperimentalFeatures, Extent3d, ExternalTextureFormat,
ExternalTextureTransferFunction, Face, Features, FeaturesWGPU, FeaturesWebGPU, FilterMode,
FrontFace, GlBackendOptions, GlFenceBehavior, Gles3MinorVersion, HalCounters,
ImageSubresourceRange, IndexFormat, InstanceDescriptor, InstanceFlags, InternalCounters,
Expand Down
Loading