1391: Simplify features r=cwfitzgerald a=kvark

**Connections**
Fixes #1390
Makes vertex writable storage optional (native-only for now)
Fixes the follow-up to #891 

**Description**
Refactors the code so that adding new features and maintaining current ones is much easier.
Refactors the way missing features are checked and reported, DRY way.

**Testing**
Not really tested

Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
bors[bot] 2021-05-17 19:03:59 +00:00 committed by GitHub
commit 13f2ca571c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 251 additions and 324 deletions

View File

@ -5,7 +5,7 @@
use crate::{ use crate::{
device::{ device::{
descriptor::{DescriptorSet, DescriptorTotalCount}, descriptor::{DescriptorSet, DescriptorTotalCount},
DeviceError, SHADER_STAGE_COUNT, DeviceError, MissingFeatures, SHADER_STAGE_COUNT,
}, },
hub::Resource, hub::Resource,
id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid}, id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid},
@ -29,16 +29,26 @@ use std::{
use thiserror::Error; use thiserror::Error;
#[derive(Clone, Debug, Error)]
pub enum BindGroupLayoutEntryError {
#[error("arrays of bindings unsupported for this type of binding")]
ArrayUnsupported,
#[error(transparent)]
MissingFeatures(#[from] MissingFeatures),
}
#[derive(Clone, Debug, Error)] #[derive(Clone, Debug, Error)]
pub enum CreateBindGroupLayoutError { pub enum CreateBindGroupLayoutError {
#[error(transparent)] #[error(transparent)]
Device(#[from] DeviceError), Device(#[from] DeviceError),
#[error("arrays of bindings unsupported for this type of binding")]
ArrayUnsupported,
#[error("conflicting binding at index {0}")] #[error("conflicting binding at index {0}")]
ConflictBinding(u32), ConflictBinding(u32),
#[error("required device feature is missing: {0:?}")] #[error("binding {binding} entry is invalid")]
MissingFeature(wgt::Features), Entry {
binding: u32,
#[source]
error: BindGroupLayoutEntryError,
},
#[error(transparent)] #[error(transparent)]
TooManyBindings(BindingTypeMaxCountError), TooManyBindings(BindingTypeMaxCountError),
} }
@ -83,8 +93,6 @@ pub enum CreateBindGroupError {
MissingBufferUsage(#[from] MissingBufferUsageError), MissingBufferUsage(#[from] MissingBufferUsageError),
#[error(transparent)] #[error(transparent)]
MissingTextureUsage(#[from] MissingTextureUsageError), MissingTextureUsage(#[from] MissingTextureUsageError),
#[error("required device features not enabled: {0:?}")]
MissingFeatures(wgt::Features),
#[error("binding declared as a single item, but bind group is using it as an array")] #[error("binding declared as a single item, but bind group is using it as an array")]
SingleBindingExpected, SingleBindingExpected,
#[error("unable to create a bind group with a swap chain image")] #[error("unable to create a bind group with a swap chain image")]
@ -419,8 +427,8 @@ pub enum CreatePipelineLayoutError {
wgt::PUSH_CONSTANT_ALIGNMENT wgt::PUSH_CONSTANT_ALIGNMENT
)] )]
MisalignedPushConstantRange { index: usize, bound: u32 }, MisalignedPushConstantRange { index: usize, bound: u32 },
#[error("device does not have required feature: {0:?}")] #[error(transparent)]
MissingFeature(wgt::Features), MissingFeatures(#[from] MissingFeatures),
#[error("push constant range (index {index}) provides for stage(s) {provided:?} but there exists another range that provides stage(s) {intersected:?}. Each stage may only be provided by one range")] #[error("push constant range (index {index}) provides for stage(s) {provided:?} but there exists another range that provides stage(s) {intersected:?}. Each stage may only be provided by one range")]
MoreThanOnePushConstantRangePerStage { MoreThanOnePushConstantRangePerStage {
index: usize, index: usize,

View File

@ -342,7 +342,6 @@ impl<B: GfxBackend> Device<B> {
spv::Capability::Image1D, spv::Capability::Image1D,
spv::Capability::SampledCubeArray, spv::Capability::SampledCubeArray,
spv::Capability::ImageCubeArray, spv::Capability::ImageCubeArray,
spv::Capability::ImageMSArray,
spv::Capability::StorageImageExtendedFormats, spv::Capability::StorageImageExtendedFormats,
] ]
.iter() .iter()
@ -393,6 +392,14 @@ impl<B: GfxBackend> Device<B> {
}) })
} }
pub(crate) fn require_features(&self, feature: wgt::Features) -> Result<(), MissingFeatures> {
if self.features.contains(feature) {
Ok(())
} else {
Err(MissingFeatures(feature))
}
}
pub(crate) fn last_completed_submission_index(&self) -> SubmissionIndex { pub(crate) fn last_completed_submission_index(&self) -> SubmissionIndex {
self.life_guard.submission_index.load(Ordering::Acquire) self.life_guard.submission_index.load(Ordering::Acquire)
} }
@ -616,13 +623,8 @@ impl<B: GfxBackend> Device<B> {
debug_assert_eq!(self_id.backend(), B::VARIANT); debug_assert_eq!(self_id.backend(), B::VARIANT);
let format_desc = desc.format.describe(); let format_desc = desc.format.describe();
let required_features = format_desc.required_features; self.require_features(format_desc.required_features)
if !self.features.contains(required_features) { .map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?;
return Err(resource::CreateTextureError::MissingFeature(
required_features,
desc.format,
));
}
// Ensure `D24Plus` textures cannot be copied // Ensure `D24Plus` textures cannot be copied
match desc.format { match desc.format {
@ -917,17 +919,12 @@ impl<B: GfxBackend> Device<B> {
self_id: id::DeviceId, self_id: id::DeviceId,
desc: &resource::SamplerDescriptor, desc: &resource::SamplerDescriptor,
) -> Result<resource::Sampler<B>, resource::CreateSamplerError> { ) -> Result<resource::Sampler<B>, resource::CreateSamplerError> {
let clamp_to_border_enabled = self if desc
.features
.contains(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER);
let clamp_to_border_found = desc
.address_modes .address_modes
.iter() .iter()
.any(|am| am == &wgt::AddressMode::ClampToBorder); .any(|am| am == &wgt::AddressMode::ClampToBorder)
if clamp_to_border_found && !clamp_to_border_enabled { {
return Err(resource::CreateSamplerError::MissingFeature( self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER)?;
wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
));
} }
let actual_clamp = if let Some(clamp) = desc.anisotropy_clamp { let actual_clamp = if let Some(clamp) = desc.anisotropy_clamp {
@ -1198,9 +1195,11 @@ impl<B: GfxBackend> Device<B> {
entry_map: binding_model::BindEntryMap, entry_map: binding_model::BindEntryMap,
) -> Result<binding_model::BindGroupLayout<B>, binding_model::CreateBindGroupLayoutError> { ) -> Result<binding_model::BindGroupLayout<B>, binding_model::CreateBindGroupLayoutError> {
let mut desc_count = descriptor::DescriptorTotalCount::default(); let mut desc_count = descriptor::DescriptorTotalCount::default();
for binding in entry_map.values() { for entry in entry_map.values() {
use wgt::BindingType as Bt; use wgt::BindingType as Bt;
let (counter, array_feature) = match binding.ty {
let mut required_features = wgt::Features::empty();
let (counter, array_feature, is_writable_storage) = match entry.ty {
Bt::Buffer { Bt::Buffer {
ty: wgt::BufferBindingType::Uniform, ty: wgt::BufferBindingType::Uniform,
has_dynamic_offset: false, has_dynamic_offset: false,
@ -1208,6 +1207,7 @@ impl<B: GfxBackend> Device<B> {
} => ( } => (
&mut desc_count.uniform_buffer, &mut desc_count.uniform_buffer,
Some(wgt::Features::BUFFER_BINDING_ARRAY), Some(wgt::Features::BUFFER_BINDING_ARRAY),
false,
), ),
Bt::Buffer { Bt::Buffer {
ty: wgt::BufferBindingType::Uniform, ty: wgt::BufferBindingType::Uniform,
@ -1216,44 +1216,65 @@ impl<B: GfxBackend> Device<B> {
} => ( } => (
&mut desc_count.uniform_buffer_dynamic, &mut desc_count.uniform_buffer_dynamic,
Some(wgt::Features::BUFFER_BINDING_ARRAY), Some(wgt::Features::BUFFER_BINDING_ARRAY),
false,
), ),
Bt::Buffer { Bt::Buffer {
ty: wgt::BufferBindingType::Storage { .. }, ty: wgt::BufferBindingType::Storage { read_only },
has_dynamic_offset: false, has_dynamic_offset,
min_binding_size: _, min_binding_size: _,
} => ( } => (
&mut desc_count.storage_buffer, if has_dynamic_offset {
&mut desc_count.storage_buffer_dynamic
} else {
&mut desc_count.storage_buffer
},
Some(wgt::Features::BUFFER_BINDING_ARRAY), Some(wgt::Features::BUFFER_BINDING_ARRAY),
!read_only,
), ),
Bt::Buffer { Bt::Sampler { .. } => (&mut desc_count.sampler, None, false),
ty: wgt::BufferBindingType::Storage { .. },
has_dynamic_offset: true,
min_binding_size: _,
} => (
&mut desc_count.storage_buffer_dynamic,
Some(wgt::Features::BUFFER_BINDING_ARRAY),
),
Bt::Sampler { .. } => (&mut desc_count.sampler, None),
Bt::Texture { .. } => ( Bt::Texture { .. } => (
&mut desc_count.sampled_image, &mut desc_count.sampled_image,
Some(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY), Some(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY),
false,
),
Bt::StorageTexture { access, .. } => (
&mut desc_count.storage_image,
None,
match access {
wgt::StorageTextureAccess::ReadOnly => false,
wgt::StorageTextureAccess::WriteOnly => true,
wgt::StorageTextureAccess::ReadWrite => {
required_features |=
wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
true
}
},
), ),
Bt::StorageTexture { .. } => (&mut desc_count.storage_image, None),
}; };
*counter += match binding.count {
*counter += match entry.count {
// Validate the count parameter // Validate the count parameter
Some(count) => { Some(count) => {
let feature = array_feature required_features |= array_feature
.ok_or(binding_model::CreateBindGroupLayoutError::ArrayUnsupported)?; .ok_or(binding_model::BindGroupLayoutEntryError::ArrayUnsupported)
if !self.features.contains(feature) { .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
return Err(binding_model::CreateBindGroupLayoutError::MissingFeature( binding: entry.binding,
feature, error,
)); })?;
}
count.get() count.get()
} }
None => 1, None => 1,
}; };
if is_writable_storage && entry.visibility.contains(wgt::ShaderStage::VERTEX) {
required_features |= wgt::Features::VERTEX_WRITABLE_STORAGE;
}
self.require_features(required_features)
.map_err(binding_model::BindGroupLayoutEntryError::MissingFeatures)
.map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
binding: entry.binding,
error,
})?;
} }
let raw_bindings = entry_map let raw_bindings = entry_map
@ -1478,11 +1499,6 @@ impl<B: GfxBackend> Device<B> {
SmallVec::from([buffer_desc]) SmallVec::from([buffer_desc])
} }
Br::BufferArray(ref bindings_array) => { Br::BufferArray(ref bindings_array) => {
let required_feats = wgt::Features::BUFFER_BINDING_ARRAY;
if !self.features.contains(required_feats) {
return Err(Error::MissingFeatures(required_feats));
}
if let Some(count) = decl.count { if let Some(count) = decl.count {
let count = count.get() as usize; let count = count.get() as usize;
let num_bindings = bindings_array.len(); let num_bindings = bindings_array.len();
@ -1631,13 +1647,9 @@ impl<B: GfxBackend> Device<B> {
if !view.format_features.flags.contains( if !view.format_features.flags.contains(
wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE, wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
) { ) {
return Err(if self.features.contains( return Err(Error::StorageReadWriteNotSupported(
wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, view.format,
) { ));
Error::StorageReadWriteNotSupported(view.format)
} else {
Error::MissingFeatures(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES)
});
} }
resource::TextureUse::STORAGE_STORE resource::TextureUse::STORAGE_STORE
@ -1686,11 +1698,6 @@ impl<B: GfxBackend> Device<B> {
} }
} }
Br::TextureViewArray(ref bindings_array) => { Br::TextureViewArray(ref bindings_array) => {
let required_feats = wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY;
if !self.features.contains(required_feats) {
return Err(Error::MissingFeatures(required_feats));
}
if let Some(count) = decl.count { if let Some(count) = decl.count {
let count = count.get() as usize; let count = count.get() as usize;
let num_bindings = bindings_array.len(); let num_bindings = bindings_array.len();
@ -1814,11 +1821,10 @@ impl<B: GfxBackend> Device<B> {
}); });
} }
if !desc.push_constant_ranges.is_empty() if !desc.push_constant_ranges.is_empty() {
&& !self.features.contains(wgt::Features::PUSH_CONSTANTS) self.require_features(wgt::Features::PUSH_CONSTANTS)?;
{
return Err(Error::MissingFeature(wgt::Features::PUSH_CONSTANTS));
} }
let mut used_stages = wgt::ShaderStage::empty(); let mut used_stages = wgt::ShaderStage::empty();
for (index, pc) in desc.push_constant_ranges.iter().enumerate() { for (index, pc) in desc.push_constant_ranges.iter().enumerate() {
if pc.stages.intersects(used_stages) { if pc.stages.intersects(used_stages) {
@ -2169,14 +2175,7 @@ impl<B: GfxBackend> Device<B> {
| wgt::VertexFormat::Float64x3 | wgt::VertexFormat::Float64x3
| wgt::VertexFormat::Float64x4 = attribute.format | wgt::VertexFormat::Float64x4 = attribute.format
{ {
if !self self.require_features(wgt::Features::VERTEX_ATTRIBUTE_64BIT)?;
.features
.contains(wgt::Features::VERTEX_ATTRIBUTE_64BIT)
{
return Err(pipeline::CreateRenderPipelineError::MissingFeature(
wgt::Features::VERTEX_ATTRIBUTE_64BIT,
));
}
} }
attributes.alloc().init(hal::pso::AttributeDesc { attributes.alloc().init(hal::pso::AttributeDesc {
@ -2221,27 +2220,15 @@ impl<B: GfxBackend> Device<B> {
); );
} }
if desc.primitive.clamp_depth && !self.features.contains(wgt::Features::DEPTH_CLAMPING) { if desc.primitive.clamp_depth {
return Err(pipeline::CreateRenderPipelineError::MissingFeature( self.require_features(wgt::Features::DEPTH_CLAMPING)?;
wgt::Features::DEPTH_CLAMPING,
));
} }
if desc.primitive.polygon_mode != wgt::PolygonMode::Fill if desc.primitive.polygon_mode != wgt::PolygonMode::Fill {
&& !self.features.contains(wgt::Features::NON_FILL_POLYGON_MODE) self.require_features(wgt::Features::NON_FILL_POLYGON_MODE)?;
{
return Err(pipeline::CreateRenderPipelineError::MissingFeature(
wgt::Features::NON_FILL_POLYGON_MODE,
));
} }
if desc.primitive.conservative if desc.primitive.conservative {
&& !self self.require_features(wgt::Features::CONSERVATIVE_RASTERIZATION)?;
.features
.contains(wgt::Features::CONSERVATIVE_RASTERIZATION)
{
return Err(pipeline::CreateRenderPipelineError::MissingFeature(
wgt::Features::CONSERVATIVE_RASTERIZATION,
));
} }
if desc.primitive.conservative && desc.primitive.polygon_mode != wgt::PolygonMode::Fill { if desc.primitive.conservative && desc.primitive.polygon_mode != wgt::PolygonMode::Fill {
@ -2596,6 +2583,47 @@ impl<B: GfxBackend> Device<B> {
Ok(()) Ok(())
} }
} }
fn create_query_set(
&self,
self_id: id::DeviceId,
desc: &wgt::QuerySetDescriptor,
) -> Result<resource::QuerySet<B>, resource::CreateQuerySetError> {
use resource::CreateQuerySetError as Error;
match desc.ty {
wgt::QueryType::Timestamp => {
self.require_features(wgt::Features::TIMESTAMP_QUERY)?;
}
wgt::QueryType::PipelineStatistics(..) => {
self.require_features(wgt::Features::PIPELINE_STATISTICS_QUERY)?;
}
}
if desc.count == 0 {
return Err(Error::ZeroCount);
}
if desc.count >= wgt::QUERY_SET_MAX_QUERIES {
return Err(Error::TooManyQueries {
count: desc.count,
maximum: wgt::QUERY_SET_MAX_QUERIES,
});
}
let (hal_type, elements) = conv::map_query_type(&desc.ty);
Ok(resource::QuerySet {
raw: unsafe { self.raw.create_query_pool(hal_type, desc.count).unwrap() },
device_id: Stored {
value: id::Valid(self_id),
ref_count: self.life_guard.add_ref(),
},
life_guard: LifeGuard::new(""),
desc: desc.clone(),
elements,
})
}
} }
impl<B: hal::Backend> Device<B> { impl<B: hal::Backend> Device<B> {
@ -2703,6 +2731,10 @@ impl DeviceError {
} }
} }
#[derive(Clone, Debug, Error)]
#[error("Features {0:?} are required but not enabled on the device")]
pub struct MissingFeatures(pub wgt::Features);
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))]
@ -4017,50 +4049,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}); });
} }
match desc.ty { let query_set = match device.create_query_set(device_id, desc) {
wgt::QueryType::Timestamp => { Ok(query_set) => query_set,
if !device.features.contains(wgt::Features::TIMESTAMP_QUERY) { Err(err) => break err,
break resource::CreateQuerySetError::MissingFeature(
wgt::Features::TIMESTAMP_QUERY,
);
}
}
wgt::QueryType::PipelineStatistics(..) => {
if !device
.features
.contains(wgt::Features::PIPELINE_STATISTICS_QUERY)
{
break resource::CreateQuerySetError::MissingFeature(
wgt::Features::PIPELINE_STATISTICS_QUERY,
);
}
}
}
if desc.count == 0 {
break resource::CreateQuerySetError::ZeroCount;
}
if desc.count >= wgt::QUERY_SET_MAX_QUERIES {
break resource::CreateQuerySetError::TooManyQueries {
count: desc.count,
maximum: wgt::QUERY_SET_MAX_QUERIES,
};
}
let query_set = {
let (hal_type, elements) = conv::map_query_type(&desc.ty);
resource::QuerySet {
raw: unsafe { device.raw.create_query_pool(hal_type, desc.count).unwrap() },
device_id: Stored {
value: id::Valid(device_id),
ref_count: device.life_guard.add_ref(),
},
life_guard: LifeGuard::new(""),
desc: desc.clone(),
elements,
}
}; };
let ref_count = query_set.life_guard.add_ref(); let ref_count = query_set.life_guard.add_ref();

View File

@ -116,6 +116,87 @@ impl crate::hub::Resource for Surface {
} }
} }
const FEATURE_MAP: &[(wgt::Features, hal::Features)] = &[
(wgt::Features::DEPTH_CLAMPING, hal::Features::DEPTH_CLAMP),
(
wgt::Features::TEXTURE_COMPRESSION_BC,
hal::Features::FORMAT_BC,
),
(
wgt::Features::TEXTURE_COMPRESSION_ETC2,
hal::Features::FORMAT_ETC2,
),
(
wgt::Features::TEXTURE_COMPRESSION_ASTC_LDR,
hal::Features::FORMAT_ASTC_LDR,
),
(
wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY,
hal::Features::TEXTURE_DESCRIPTOR_ARRAY,
),
(
wgt::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING,
hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
),
(
wgt::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING,
),
(
wgt::Features::UNSIZED_BINDING_ARRAY,
hal::Features::UNSIZED_DESCRIPTOR_ARRAY,
),
(
wgt::Features::MULTI_DRAW_INDIRECT,
hal::Features::MULTI_DRAW_INDIRECT,
),
(
wgt::Features::MULTI_DRAW_INDIRECT_COUNT,
hal::Features::DRAW_INDIRECT_COUNT,
),
(
wgt::Features::NON_FILL_POLYGON_MODE,
hal::Features::NON_FILL_POLYGON_MODE,
),
(
wgt::Features::PIPELINE_STATISTICS_QUERY,
hal::Features::PIPELINE_STATISTICS_QUERY,
),
(wgt::Features::SHADER_FLOAT64, hal::Features::SHADER_FLOAT64),
(
wgt::Features::CONSERVATIVE_RASTERIZATION,
hal::Features::CONSERVATIVE_RASTERIZATION,
),
(
wgt::Features::BUFFER_BINDING_ARRAY,
hal::Features::BUFFER_DESCRIPTOR_ARRAY,
),
(
wgt::Features::UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING,
hal::Features::SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING,
),
(
wgt::Features::UNIFORM_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
hal::Features::UNIFORM_BUFFER_DESCRIPTOR_INDEXING,
),
(
wgt::Features::STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING,
hal::Features::SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING,
),
(
wgt::Features::STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
hal::Features::STORAGE_BUFFER_DESCRIPTOR_INDEXING,
),
(
wgt::Features::VERTEX_WRITABLE_STORAGE,
hal::Features::VERTEX_STORES_AND_ATOMICS,
),
(
wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
hal::Features::SAMPLER_BORDER_COLOR,
),
];
#[derive(Debug)] #[derive(Debug)]
pub struct Adapter<B: hal::Backend> { pub struct Adapter<B: hal::Backend> {
pub(crate) raw: hal::adapter::Adapter<B>, pub(crate) raw: hal::adapter::Adapter<B>,
@ -137,89 +218,13 @@ impl<B: GfxBackend> Adapter<B> {
| wgt::Features::MAPPABLE_PRIMARY_BUFFERS | wgt::Features::MAPPABLE_PRIMARY_BUFFERS
| wgt::Features::PUSH_CONSTANTS | wgt::Features::PUSH_CONSTANTS
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES; | wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
features.set( for &(hi, lo) in FEATURE_MAP.iter() {
wgt::Features::DEPTH_CLAMPING, features.set(hi, adapter_features.contains(lo));
adapter_features.contains(hal::Features::DEPTH_CLAMP), }
);
features.set(
wgt::Features::TEXTURE_COMPRESSION_BC,
adapter_features.contains(hal::Features::FORMAT_BC),
);
features.set(
wgt::Features::TEXTURE_COMPRESSION_ETC2,
adapter_features.contains(hal::Features::FORMAT_ETC2),
);
features.set(
wgt::Features::TEXTURE_COMPRESSION_ASTC_LDR,
adapter_features.contains(hal::Features::FORMAT_ASTC_LDR),
);
features.set(
wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY,
adapter_features.contains(hal::Features::TEXTURE_DESCRIPTOR_ARRAY),
);
features.set(
wgt::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING,
adapter_features.contains(hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING),
);
features.set(
wgt::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
adapter_features.contains(hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING),
);
features.set(
wgt::Features::UNSIZED_BINDING_ARRAY,
adapter_features.contains(hal::Features::UNSIZED_DESCRIPTOR_ARRAY),
);
features.set(
wgt::Features::MULTI_DRAW_INDIRECT,
adapter_features.contains(hal::Features::MULTI_DRAW_INDIRECT),
);
features.set(
wgt::Features::MULTI_DRAW_INDIRECT_COUNT,
adapter_features.contains(hal::Features::DRAW_INDIRECT_COUNT),
);
features.set(
wgt::Features::NON_FILL_POLYGON_MODE,
adapter_features.contains(hal::Features::NON_FILL_POLYGON_MODE),
);
features.set( features.set(
wgt::Features::TIMESTAMP_QUERY, wgt::Features::TIMESTAMP_QUERY,
properties.limits.timestamp_compute_and_graphics, properties.limits.timestamp_compute_and_graphics,
); );
features.set(
wgt::Features::PIPELINE_STATISTICS_QUERY,
adapter_features.contains(hal::Features::PIPELINE_STATISTICS_QUERY),
);
features.set(
wgt::Features::SHADER_FLOAT64,
adapter_features.contains(hal::Features::SHADER_FLOAT64),
);
features.set(
wgt::Features::CONSERVATIVE_RASTERIZATION,
adapter_features.contains(hal::Features::CONSERVATIVE_RASTERIZATION),
);
features.set(
wgt::Features::BUFFER_BINDING_ARRAY,
adapter_features.contains(hal::Features::BUFFER_DESCRIPTOR_ARRAY),
);
features.set(
wgt::Features::UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING,
adapter_features.contains(hal::Features::SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING),
);
features.set(
wgt::Features::UNIFORM_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
adapter_features.contains(hal::Features::UNIFORM_BUFFER_DESCRIPTOR_INDEXING),
);
features.set(
wgt::Features::STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING,
adapter_features.contains(hal::Features::SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING),
);
features.set(
wgt::Features::STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
adapter_features.contains(hal::Features::STORAGE_BUFFER_DESCRIPTOR_INDEXING),
);
#[cfg(not(target_os = "ios"))]
//TODO: https://github.com/gfx-rs/gfx/issues/3346
features.set(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true);
let private_features = PrivateFeatures { let private_features = PrivateFeatures {
anisotropic_filtering: adapter_features.contains(hal::Features::SAMPLER_ANISOTROPY), anisotropic_filtering: adapter_features.contains(hal::Features::SAMPLER_ANISOTROPY),
@ -452,12 +457,12 @@ impl<B: GfxBackend> Adapter<B> {
// Check features that are always needed // Check features that are always needed
let wishful_features = hal::Features::ROBUST_BUFFER_ACCESS let wishful_features = hal::Features::ROBUST_BUFFER_ACCESS
| hal::Features::VERTEX_STORES_AND_ATOMICS
| hal::Features::FRAGMENT_STORES_AND_ATOMICS | hal::Features::FRAGMENT_STORES_AND_ATOMICS
| hal::Features::NDC_Y_UP | hal::Features::NDC_Y_UP
| hal::Features::INDEPENDENT_BLENDING | hal::Features::INDEPENDENT_BLENDING
| hal::Features::SAMPLER_ANISOTROPY | hal::Features::SAMPLER_ANISOTROPY
| hal::Features::IMAGE_CUBE_ARRAY; | hal::Features::IMAGE_CUBE_ARRAY
| hal::Features::SAMPLE_RATE_SHADING;
let mut enabled_features = available_features & wishful_features; let mut enabled_features = available_features & wishful_features;
if enabled_features != wishful_features { if enabled_features != wishful_features {
log::warn!( log::warn!(
@ -466,96 +471,10 @@ impl<B: GfxBackend> Adapter<B> {
); );
} }
// Features // Enable low-level features
enabled_features.set( for &(hi, lo) in FEATURE_MAP.iter() {
hal::Features::DEPTH_CLAMP, enabled_features.set(lo, desc.features.contains(hi));
desc.features.contains(wgt::Features::DEPTH_CLAMPING), }
);
enabled_features.set(
hal::Features::FORMAT_BC,
desc.features
.contains(wgt::Features::TEXTURE_COMPRESSION_BC),
);
enabled_features.set(
hal::Features::FORMAT_ETC2,
desc.features
.contains(wgt::Features::TEXTURE_COMPRESSION_ETC2),
);
enabled_features.set(
hal::Features::FORMAT_ASTC_LDR,
desc.features
.contains(wgt::Features::TEXTURE_COMPRESSION_ASTC_LDR),
);
enabled_features.set(
hal::Features::TEXTURE_DESCRIPTOR_ARRAY,
desc.features
.contains(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY),
);
enabled_features.set(
hal::Features::SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING,
desc.features
.contains(wgt::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING),
);
enabled_features.set(
hal::Features::SAMPLED_TEXTURE_DESCRIPTOR_INDEXING,
desc.features
.contains(wgt::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING),
);
enabled_features.set(
hal::Features::UNSIZED_DESCRIPTOR_ARRAY,
desc.features.contains(wgt::Features::UNSIZED_BINDING_ARRAY),
);
enabled_features.set(
hal::Features::MULTI_DRAW_INDIRECT,
desc.features.contains(wgt::Features::MULTI_DRAW_INDIRECT),
);
enabled_features.set(
hal::Features::DRAW_INDIRECT_COUNT,
desc.features
.contains(wgt::Features::MULTI_DRAW_INDIRECT_COUNT),
);
enabled_features.set(
hal::Features::NON_FILL_POLYGON_MODE,
desc.features.contains(wgt::Features::NON_FILL_POLYGON_MODE),
);
enabled_features.set(
hal::Features::PIPELINE_STATISTICS_QUERY,
desc.features
.contains(wgt::Features::PIPELINE_STATISTICS_QUERY),
);
enabled_features.set(
hal::Features::SHADER_FLOAT64,
desc.features.contains(wgt::Features::SHADER_FLOAT64),
);
enabled_features.set(
hal::Features::CONSERVATIVE_RASTERIZATION,
desc.features
.contains(wgt::Features::CONSERVATIVE_RASTERIZATION),
);
enabled_features.set(
hal::Features::BUFFER_DESCRIPTOR_ARRAY,
desc.features.contains(wgt::Features::BUFFER_BINDING_ARRAY),
);
enabled_features.set(
hal::Features::SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING,
desc.features
.contains(wgt::Features::UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING),
);
enabled_features.set(
hal::Features::UNIFORM_BUFFER_DESCRIPTOR_INDEXING,
desc.features
.contains(wgt::Features::UNIFORM_BUFFER_ARRAY_NON_UNIFORM_INDEXING),
);
enabled_features.set(
hal::Features::SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING,
desc.features
.contains(wgt::Features::STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING),
);
enabled_features.set(
hal::Features::STORAGE_BUFFER_DESCRIPTOR_INDEXING,
desc.features
.contains(wgt::Features::STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING),
);
let family = self let family = self
.raw .raw

View File

@ -4,7 +4,7 @@
use crate::{ use crate::{
binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError}, binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError},
device::{DeviceError, RenderPassContext}, device::{DeviceError, MissingFeatures, RenderPassContext},
hub::Resource, hub::Resource,
id::{DeviceId, PipelineLayoutId, ShaderModuleId}, id::{DeviceId, PipelineLayoutId, ShaderModuleId},
validation, Label, LifeGuard, Stored, DOWNLEVEL_ERROR_WARNING_MESSAGE, validation, Label, LifeGuard, Stored, DOWNLEVEL_ERROR_WARNING_MESSAGE,
@ -62,8 +62,8 @@ pub enum CreateShaderModuleError {
Device(#[from] DeviceError), Device(#[from] DeviceError),
#[error(transparent)] #[error(transparent)]
Validation(#[from] naga::valid::ValidationError), Validation(#[from] naga::valid::ValidationError),
#[error("missing required device features {0:?}")] #[error(transparent)]
MissingFeature(wgt::Features), MissingFeatures(#[from] MissingFeatures),
} }
/// Describes a programmable pipeline stage. /// Describes a programmable pipeline stage.
@ -246,8 +246,8 @@ pub enum CreateRenderPipelineError {
}, },
#[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")] #[error("Conservative Rasterization is only supported for wgt::PolygonMode::Fill")]
ConservativeRasterizationNonFillPolygonMode, ConservativeRasterizationNonFillPolygonMode,
#[error("missing required device features {0:?}")] #[error(transparent)]
MissingFeature(wgt::Features), MissingFeatures(#[from] MissingFeatures),
#[error("error matching {stage:?} shader requirements against the pipeline")] #[error("error matching {stage:?} shader requirements against the pipeline")]
Stage { Stage {
stage: wgt::ShaderStage, stage: wgt::ShaderStage,

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{ use crate::{
device::{alloc::MemoryBlock, DeviceError, HostMap}, device::{alloc::MemoryBlock, DeviceError, HostMap, MissingFeatures},
hub::Resource, hub::Resource,
id::{DeviceId, SwapChainId, TextureId}, id::{DeviceId, SwapChainId, TextureId},
memory_init_tracker::MemoryInitTracker, memory_init_tracker::MemoryInitTracker,
@ -266,8 +266,8 @@ pub enum CreateTextureError {
InvalidMipLevelCount(u32), InvalidMipLevelCount(u32),
#[error("The texture usages {0:?} are not allowed on a texture of type {1:?}")] #[error("The texture usages {0:?} are not allowed on a texture of type {1:?}")]
InvalidUsages(wgt::TextureUsage, wgt::TextureFormat), InvalidUsages(wgt::TextureUsage, wgt::TextureFormat),
#[error("Feature {0:?} must be enabled to create a texture of type {1:?}")] #[error("Texture format {0:?} can't be used")]
MissingFeature(wgt::Features, wgt::TextureFormat), MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures),
} }
impl<B: hal::Backend> Resource for Texture<B> { impl<B: hal::Backend> Resource for Texture<B> {
@ -458,9 +458,9 @@ pub enum CreateSamplerError {
InvalidClamp(u8), InvalidClamp(u8),
#[error("cannot create any more samplers")] #[error("cannot create any more samplers")]
TooManyObjects, TooManyObjects,
/// AddressMode::ClampToBorder requires feature ADDRESS_MODE_CLAMP_TO_BORDER /// AddressMode::ClampToBorder requires feature ADDRESS_MODE_CLAMP_TO_BORDER.
#[error("Feature {0:?} must be enabled")] #[error(transparent)]
MissingFeature(wgt::Features), MissingFeatures(#[from] MissingFeatures),
} }
impl<B: hal::Backend> Resource for Sampler<B> { impl<B: hal::Backend> Resource for Sampler<B> {
@ -484,8 +484,8 @@ pub enum CreateQuerySetError {
ZeroCount, ZeroCount,
#[error("{count} is too many queries for a single QuerySet. QuerySets cannot be made more than {maximum} queries.")] #[error("{count} is too many queries for a single QuerySet. QuerySets cannot be made more than {maximum} queries.")]
TooManyQueries { count: u32, maximum: u32 }, TooManyQueries { count: u32, maximum: u32 },
#[error("Feature {0:?} must be enabled")] #[error(transparent)]
MissingFeature(wgt::Features), MissingFeatures(#[from] MissingFeatures),
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -526,6 +526,15 @@ bitflags::bitflags! {
/// ///
/// This is a native only feature. /// This is a native only feature.
const STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING = 0x0000_0010_0000_0000; const STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING = 0x0000_0010_0000_0000;
/// Enables bindings of writable storage buffers and textures visible to vertex shaders.
///
/// Note: some (tiled-based) platforms do not support vertex shaders with any side-effects.
///
/// Supported Platforms:
/// - All
///
/// This is a native-only feature.
const VERTEX_WRITABLE_STORAGE = 0x0000_0020_0000_0000;
/// Features which are part of the upstream WebGPU standard. /// Features which are part of the upstream WebGPU standard.
const ALL_WEBGPU = 0x0000_0000_0000_FFFF; const ALL_WEBGPU = 0x0000_0000_0000_FFFF;
/// Features that are only available when targeting native (not web). /// Features that are only available when targeting native (not web).