mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #717
717: Implement Capability/Extension Split r=kvark a=cwfitzgerald ## Connections Follow up to a discussion we had on #wgpu:matrix.org. ## Description Splits capabilities and extensions so that extensions are things you ask for and possibly change behavior and capabilities are passively enabled when their extension (if any) are enabled. Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
@@ -21,6 +21,7 @@ use std::borrow::Borrow;
|
||||
pub enum BindGroupLayoutError {
|
||||
ConflictBinding(u32),
|
||||
MissingExtension(wgt::Extensions),
|
||||
MissingCapability(wgt::Capabilities),
|
||||
/// Arrays of bindings can't be 0 elements long
|
||||
ZeroCount,
|
||||
/// Arrays of bindings unsupported for this type of binding
|
||||
|
||||
@@ -190,6 +190,7 @@ pub struct Device<B: hal::Backend> {
|
||||
pub(crate) private_features: PrivateFeatures,
|
||||
limits: wgt::Limits,
|
||||
extensions: wgt::Extensions,
|
||||
capabilities: wgt::Capabilities,
|
||||
//TODO: move this behind another mutex. This would allow several methods to switch
|
||||
// to borrow Device immutably, such as `write_buffer`, `write_texture`, and `buffer_unmap`.
|
||||
pending_writes: queue::PendingWrites<B>,
|
||||
@@ -206,6 +207,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
hal_limits: hal::Limits,
|
||||
private_features: PrivateFeatures,
|
||||
desc: &wgt::DeviceDescriptor,
|
||||
capabilities: wgt::Capabilities,
|
||||
trace_path: Option<&std::path::Path>,
|
||||
) -> Self {
|
||||
// don't start submission index at zero
|
||||
@@ -264,6 +266,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
private_features,
|
||||
limits: desc.limits.clone(),
|
||||
extensions: desc.extensions.clone(),
|
||||
capabilities: capabilities.clone(),
|
||||
pending_writes: queue::PendingWrites::new(),
|
||||
}
|
||||
}
|
||||
@@ -637,7 +640,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let (device_guard, _) = hub.devices.read(&mut token);
|
||||
let device = &device_guard[device_id];
|
||||
|
||||
device.extensions.clone()
|
||||
device.extensions
|
||||
}
|
||||
|
||||
pub fn device_limits<B: GfxBackend>(&self, device_id: id::DeviceId) -> wgt::Limits {
|
||||
@@ -649,6 +652,15 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device.limits.clone()
|
||||
}
|
||||
|
||||
pub fn device_capabilities<B: GfxBackend>(&self, device_id: id::DeviceId) -> wgt::Capabilities {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (device_guard, _) = hub.devices.read(&mut token);
|
||||
let device = &device_guard[device_id];
|
||||
|
||||
device.capabilities
|
||||
}
|
||||
|
||||
pub fn device_create_buffer<B: GfxBackend>(
|
||||
&self,
|
||||
device_id: id::DeviceId,
|
||||
@@ -1193,11 +1205,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
match binding.ty {
|
||||
wgt::BindingType::SampledTexture { .. } => {
|
||||
if !device
|
||||
.extensions
|
||||
.contains(wgt::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY)
|
||||
.capabilities
|
||||
.contains(wgt::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY)
|
||||
{
|
||||
return Err(binding_model::BindGroupLayoutError::MissingExtension(
|
||||
wgt::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY,
|
||||
return Err(binding_model::BindGroupLayoutError::MissingCapability(
|
||||
wgt::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1573,7 +1585,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
}
|
||||
binding_model::BindingResource::TextureViewArray(ref bindings_array) => {
|
||||
assert!(device.extensions.contains(wgt::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY), "Extension SAMPLED_TEXTURE_BINDING_ARRAY must be enabled to use TextureViewArrays in a bind group");
|
||||
assert!(
|
||||
device.capabilities.contains(wgt::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY),
|
||||
"Capability SAMPLED_TEXTURE_BINDING_ARRAY must be supported to use TextureViewArrays in a bind group"
|
||||
);
|
||||
|
||||
if let Some(count) = decl.count {
|
||||
assert_eq!(
|
||||
|
||||
@@ -120,6 +120,7 @@ pub struct Adapter<B: hal::Backend> {
|
||||
pub(crate) raw: hal::adapter::Adapter<B>,
|
||||
extensions: wgt::Extensions,
|
||||
limits: wgt::Limits,
|
||||
capabilities: wgt::Capabilities,
|
||||
unsafe_extensions: wgt::UnsafeExtensions,
|
||||
life_guard: LifeGuard,
|
||||
}
|
||||
@@ -134,20 +135,11 @@ impl<B: hal::Backend> Adapter<B> {
|
||||
adapter_features.contains(hal::Features::SAMPLER_ANISOTROPY),
|
||||
);
|
||||
extensions.set(
|
||||
wgt::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY,
|
||||
adapter_features.contains(hal::Features::TEXTURE_DESCRIPTOR_ARRAY),
|
||||
);
|
||||
extensions.set(
|
||||
wgt::Extensions::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING,
|
||||
adapter_features.contains(hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING),
|
||||
);
|
||||
extensions.set(
|
||||
wgt::Extensions::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
adapter_features.contains(hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING),
|
||||
);
|
||||
extensions.set(
|
||||
wgt::Extensions::UNSIZED_BINDING_ARRAY,
|
||||
adapter_features.contains(hal::Features::UNSIZED_DESCRIPTOR_ARRAY),
|
||||
wgt::Extensions::BINDING_INDEXING,
|
||||
adapter_features.intersects(
|
||||
hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING
|
||||
| hal::Features::UNSIZED_DESCRIPTOR_ARRAY,
|
||||
),
|
||||
);
|
||||
if unsafe_extensions.allowed() {
|
||||
// Unsafe extensions go here
|
||||
@@ -161,10 +153,30 @@ impl<B: hal::Backend> Adapter<B> {
|
||||
_non_exhaustive: unsafe { wgt::NonExhaustive::new() },
|
||||
};
|
||||
|
||||
let mut capabilities = wgt::Capabilities::empty();
|
||||
|
||||
capabilities.set(
|
||||
wgt::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY,
|
||||
adapter_features.contains(hal::Features::TEXTURE_DESCRIPTOR_ARRAY),
|
||||
);
|
||||
capabilities.set(
|
||||
wgt::Capabilities::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING,
|
||||
adapter_features.contains(hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING),
|
||||
);
|
||||
capabilities.set(
|
||||
wgt::Capabilities::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
adapter_features.contains(hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING),
|
||||
);
|
||||
capabilities.set(
|
||||
wgt::Capabilities::UNSIZED_BINDING_ARRAY,
|
||||
adapter_features.contains(hal::Features::UNSIZED_DESCRIPTOR_ARRAY),
|
||||
);
|
||||
|
||||
Adapter {
|
||||
raw,
|
||||
extensions,
|
||||
limits,
|
||||
capabilities,
|
||||
unsafe_extensions,
|
||||
life_guard: LifeGuard::new(),
|
||||
}
|
||||
@@ -590,6 +602,15 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
adapter.limits.clone()
|
||||
}
|
||||
|
||||
pub fn adapter_capabilities<B: GfxBackend>(&self, adapter_id: AdapterId) -> wgt::Capabilities {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (adapter_guard, _) = hub.adapters.read(&mut token);
|
||||
let adapter = &adapter_guard[adapter_id];
|
||||
|
||||
adapter.capabilities
|
||||
}
|
||||
|
||||
pub fn adapter_destroy<B: GfxBackend>(&self, adapter_id: AdapterId) {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
@@ -624,20 +645,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let adapter = &adapter_guard[adapter_id];
|
||||
let phd = &adapter.raw.physical_device;
|
||||
|
||||
let available_features = adapter.raw.physical_device.features();
|
||||
|
||||
// Check features that are always needed
|
||||
let wishful_features = hal::Features::VERTEX_STORES_AND_ATOMICS
|
||||
| hal::Features::FRAGMENT_STORES_AND_ATOMICS
|
||||
| hal::Features::NDC_Y_UP;
|
||||
let mut enabled_features = available_features & wishful_features;
|
||||
if enabled_features != wishful_features {
|
||||
log::warn!(
|
||||
"Missing features: {:?}",
|
||||
wishful_features - enabled_features
|
||||
);
|
||||
}
|
||||
|
||||
// Verify all extensions were exposed by the adapter
|
||||
if !adapter.unsafe_extensions.allowed() {
|
||||
assert!(
|
||||
@@ -652,12 +659,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
desc.extensions - adapter.extensions
|
||||
);
|
||||
|
||||
// Check features needed by extensions
|
||||
enabled_features.set(
|
||||
hal::Features::SAMPLER_ANISOTROPY,
|
||||
desc.extensions
|
||||
.contains(wgt::Extensions::ANISOTROPIC_FILTERING),
|
||||
);
|
||||
// Verify extension preconditions
|
||||
if desc
|
||||
.extensions
|
||||
.contains(wgt::Extensions::MAPPABLE_PRIMARY_BUFFERS)
|
||||
@@ -665,27 +667,62 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
{
|
||||
log::warn!("Extension MAPPABLE_PRIMARY_BUFFERS enabled on a discrete gpu. This is a massive performance footgun and likely not what you wanted");
|
||||
}
|
||||
|
||||
let available_features = adapter.raw.physical_device.features();
|
||||
|
||||
// Check features that are always needed
|
||||
let wishful_features = hal::Features::VERTEX_STORES_AND_ATOMICS
|
||||
| hal::Features::FRAGMENT_STORES_AND_ATOMICS
|
||||
| hal::Features::NDC_Y_UP;
|
||||
let mut enabled_features = available_features & wishful_features;
|
||||
if enabled_features != wishful_features {
|
||||
log::warn!(
|
||||
"Missing features: {:?}",
|
||||
wishful_features - enabled_features
|
||||
);
|
||||
}
|
||||
|
||||
// Extensions
|
||||
enabled_features.set(
|
||||
hal::Features::SAMPLER_ANISOTROPY,
|
||||
desc.extensions
|
||||
.contains(wgt::Extensions::ANISOTROPIC_FILTERING),
|
||||
);
|
||||
|
||||
let mut enabled_capabilities = adapter.capabilities & wgt::Capabilities::ALL_BUILT_IN;
|
||||
|
||||
// Capabilities without extension gates
|
||||
enabled_features.set(
|
||||
hal::Features::TEXTURE_DESCRIPTOR_ARRAY,
|
||||
desc.extensions
|
||||
.contains(wgt::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY),
|
||||
adapter
|
||||
.capabilities
|
||||
.contains(wgt::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY),
|
||||
);
|
||||
enabled_features.set(
|
||||
hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
|
||||
desc.extensions
|
||||
.contains(wgt::Extensions::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING),
|
||||
);
|
||||
enabled_features.set(
|
||||
hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING,
|
||||
desc.extensions
|
||||
.contains(wgt::Extensions::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING),
|
||||
);
|
||||
enabled_features.set(
|
||||
hal::Features::UNSIZED_DESCRIPTOR_ARRAY,
|
||||
desc.extensions
|
||||
.contains(wgt::Extensions::UNSIZED_BINDING_ARRAY),
|
||||
adapter
|
||||
.capabilities
|
||||
.contains(wgt::Capabilities::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING),
|
||||
);
|
||||
|
||||
// Capabilities behind BINDING_INDEXING
|
||||
if desc.extensions.contains(wgt::Extensions::BINDING_INDEXING) {
|
||||
enabled_capabilities
|
||||
.insert(adapter.capabilities & wgt::Capabilities::ALL_BINDING_INDEXING);
|
||||
enabled_features.set(
|
||||
hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING,
|
||||
adapter
|
||||
.capabilities
|
||||
.contains(wgt::Capabilities::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING),
|
||||
);
|
||||
enabled_features.set(
|
||||
hal::Features::UNSIZED_DESCRIPTOR_ARRAY,
|
||||
adapter
|
||||
.capabilities
|
||||
.contains(wgt::Capabilities::UNSIZED_BINDING_ARRAY),
|
||||
);
|
||||
}
|
||||
|
||||
let family = adapter
|
||||
.raw
|
||||
.queue_families
|
||||
@@ -737,6 +774,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
limits,
|
||||
private_features,
|
||||
desc,
|
||||
enabled_capabilities,
|
||||
trace_path,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -142,6 +142,9 @@ bitflags::bitflags! {
|
||||
/// - Metal
|
||||
/// - Vulkan
|
||||
///
|
||||
/// Provided Capabilities:
|
||||
/// - None
|
||||
///
|
||||
/// This is a native only extension. Support is planned to be added to webgpu,
|
||||
/// but it is not yet implemented.
|
||||
///
|
||||
@@ -157,37 +160,12 @@ bitflags::bitflags! {
|
||||
/// Supported platforms:
|
||||
/// - All
|
||||
///
|
||||
/// Provided Capabilities:
|
||||
/// - None
|
||||
///
|
||||
/// This is a native only extension.
|
||||
const MAPPABLE_PRIMARY_BUFFERS = 0x0000_0000_0002_0000;
|
||||
/// Allows the user to create uniform arrays of sampled textures in shaders:
|
||||
///
|
||||
/// eg. `uniform texture2D textures[10]`.
|
||||
///
|
||||
/// This extension only allows them to exist and to be indexed by compile time constant
|
||||
/// values.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Metal (with MSL 2.0+ on macOS 10.13+)
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only extension.
|
||||
const SAMPLED_TEXTURE_BINDING_ARRAY = 0x0000_0000_0004_0000;
|
||||
/// Allows shaders to index sampled texture arrays with dynamically uniform values:
|
||||
///
|
||||
/// eg. `texture_array[uniform_value]`
|
||||
///
|
||||
/// This extension means the hardware will also support SAMPLED_TEXTURE_BINDING_ARRAY,
|
||||
/// but it still must be requested to use it.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Metal (with MSL 2.0+ on macOS 10.13+)
|
||||
/// - Vulkan (via feature shaderSampledImageArrayDynamicIndexing)
|
||||
///
|
||||
/// This is a native only extension.
|
||||
const SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING = 0x0000_0000_0008_0000;
|
||||
/// Allows shaders to index sampled texture arrays with dynamically non-uniform values:
|
||||
/// Allows shaders to index arrays of bindings with dynamically non-uniform values:
|
||||
///
|
||||
/// eg. `texture_array[vertex_data]`
|
||||
///
|
||||
@@ -197,30 +175,17 @@ bitflags::bitflags! {
|
||||
///
|
||||
/// HLSL does not need any extension.
|
||||
///
|
||||
/// This extension means the hardware will also support SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING
|
||||
/// and SAMPLED_TEXTURE_BINDING_ARRAY, but they still must be requested to use them.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Metal (with MSL 2.0+ on macOS 10.13+)
|
||||
/// - Vulkan 1.2+ (or via VK_EXT_descriptor_indexing)
|
||||
///
|
||||
/// This is a native only extension.
|
||||
const SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING = 0x0000_0000_0010_0000;
|
||||
/// Allows the user to create unsized uniform arrays of bindings:
|
||||
///
|
||||
/// eg. `uniform texture2D textures[]`.
|
||||
///
|
||||
/// This extension only allows them to exist and to be indexed by compile time constant
|
||||
/// values. However if this extension exists, SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING is
|
||||
/// _very_ likely to exist.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Vulkan 1.2+ (or via VK_EXT_descriptor_indexing)
|
||||
/// Provided Capabilities:
|
||||
/// - SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
|
||||
/// - UNSIZED_BINDING_ARRAY
|
||||
///
|
||||
/// This is a native only extension.
|
||||
const UNSIZED_BINDING_ARRAY = 0x0000_0000_0020_0000;
|
||||
const BINDING_INDEXING = 0x0000_0000_0004_0000;
|
||||
/// Extensions which are part of the upstream webgpu standard
|
||||
const ALL_WEBGPU = 0x0000_0000_0000_FFFF;
|
||||
/// Extensions that require activating the unsafe extension flag
|
||||
@@ -268,6 +233,81 @@ impl Default for Limits {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct Capabilities: u64 {
|
||||
/// Allows the user to create uniform arrays of sampled textures in shaders:
|
||||
///
|
||||
/// eg. `uniform texture2D textures[10]`.
|
||||
///
|
||||
/// This capability allows them to exist and to be indexed by compile time constant
|
||||
/// values.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Metal (with MSL 2.0+ on macOS 10.13+)
|
||||
/// - Vulkan
|
||||
const SAMPLED_TEXTURE_BINDING_ARRAY = 0x0000_0000_0000_0001;
|
||||
/// Allows shaders to index sampled texture arrays with dynamically uniform values:
|
||||
///
|
||||
/// eg. `texture_array[uniform_value]`
|
||||
///
|
||||
/// This capability means the hardware will also support SAMPLED_TEXTURE_BINDING_ARRAY.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Metal (with MSL 2.0+ on macOS 10.13+)
|
||||
/// - Vulkan's shaderSampledImageArrayDynamicIndexing feature
|
||||
const SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING = 0x0000_0000_0000_0002;
|
||||
/// Allows shaders to index sampled texture arrays with dynamically non-uniform values:
|
||||
///
|
||||
/// eg. `texture_array[vertex_data]`
|
||||
///
|
||||
/// In order to use this capability, the corresponding GLSL extension must be enabled like so:
|
||||
///
|
||||
/// `#extension GL_EXT_nonuniform_qualifier : require`
|
||||
///
|
||||
/// HLSL does not need any extension.
|
||||
///
|
||||
/// This capability means the hardware will also support SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING
|
||||
/// and SAMPLED_TEXTURE_BINDING_ARRAY.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Metal (with MSL 2.0+ on macOS 10.13+)
|
||||
/// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s shaderSampledImageArrayNonUniformIndexing feature)
|
||||
///
|
||||
/// Provided by the BINDING_INDEXING extension. This extension must be enabled for this capability
|
||||
/// to be anything but false.
|
||||
const SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING = 0x0000_0000_0000_0004;
|
||||
/// Allows the user to create unsized uniform arrays of bindings:
|
||||
///
|
||||
/// eg. `uniform texture2D textures[]`.
|
||||
///
|
||||
/// If this capability is supported, SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING is very likely
|
||||
/// to also be supported
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s runtimeDescriptorArray feature
|
||||
///
|
||||
/// Provided by the BINDING_INDEXING extension. This extension must be enabled for this capability
|
||||
/// to be anything but false.
|
||||
const UNSIZED_BINDING_ARRAY = 0x0000_0000_0000_0008;
|
||||
/// All capabilities that are not provided by an extension
|
||||
const ALL_BUILT_IN =
|
||||
Self::SAMPLED_TEXTURE_BINDING_ARRAY.bits |
|
||||
Self::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING.bits;
|
||||
/// All capabilities that are provided by the BINDING_INDEXING extension
|
||||
const ALL_BINDING_INDEXING =
|
||||
Self::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING.bits |
|
||||
Self::UNSIZED_BINDING_ARRAY.bits;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
|
||||
Reference in New Issue
Block a user