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::{
device::{
descriptor::{DescriptorSet, DescriptorTotalCount},
DeviceError, SHADER_STAGE_COUNT,
DeviceError, MissingFeatures, SHADER_STAGE_COUNT,
},
hub::Resource,
id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid},
@ -29,16 +29,26 @@ use std::{
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)]
pub enum CreateBindGroupLayoutError {
#[error(transparent)]
Device(#[from] DeviceError),
#[error("arrays of bindings unsupported for this type of binding")]
ArrayUnsupported,
#[error("conflicting binding at index {0}")]
ConflictBinding(u32),
#[error("required device feature is missing: {0:?}")]
MissingFeature(wgt::Features),
#[error("binding {binding} entry is invalid")]
Entry {
binding: u32,
#[source]
error: BindGroupLayoutEntryError,
},
#[error(transparent)]
TooManyBindings(BindingTypeMaxCountError),
}
@ -83,8 +93,6 @@ pub enum CreateBindGroupError {
MissingBufferUsage(#[from] MissingBufferUsageError),
#[error(transparent)]
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")]
SingleBindingExpected,
#[error("unable to create a bind group with a swap chain image")]
@ -419,8 +427,8 @@ pub enum CreatePipelineLayoutError {
wgt::PUSH_CONSTANT_ALIGNMENT
)]
MisalignedPushConstantRange { index: usize, bound: u32 },
#[error("device does not have required feature: {0:?}")]
MissingFeature(wgt::Features),
#[error(transparent)]
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")]
MoreThanOnePushConstantRangePerStage {
index: usize,

View File

@ -342,7 +342,6 @@ impl<B: GfxBackend> Device<B> {
spv::Capability::Image1D,
spv::Capability::SampledCubeArray,
spv::Capability::ImageCubeArray,
spv::Capability::ImageMSArray,
spv::Capability::StorageImageExtendedFormats,
]
.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 {
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);
let format_desc = desc.format.describe();
let required_features = format_desc.required_features;
if !self.features.contains(required_features) {
return Err(resource::CreateTextureError::MissingFeature(
required_features,
desc.format,
));
}
self.require_features(format_desc.required_features)
.map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?;
// Ensure `D24Plus` textures cannot be copied
match desc.format {
@ -917,17 +919,12 @@ impl<B: GfxBackend> Device<B> {
self_id: id::DeviceId,
desc: &resource::SamplerDescriptor,
) -> Result<resource::Sampler<B>, resource::CreateSamplerError> {
let clamp_to_border_enabled = self
.features
.contains(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER);
let clamp_to_border_found = desc
if desc
.address_modes
.iter()
.any(|am| am == &wgt::AddressMode::ClampToBorder);
if clamp_to_border_found && !clamp_to_border_enabled {
return Err(resource::CreateSamplerError::MissingFeature(
wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
));
.any(|am| am == &wgt::AddressMode::ClampToBorder)
{
self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER)?;
}
let actual_clamp = if let Some(clamp) = desc.anisotropy_clamp {
@ -1198,9 +1195,11 @@ impl<B: GfxBackend> Device<B> {
entry_map: binding_model::BindEntryMap,
) -> Result<binding_model::BindGroupLayout<B>, binding_model::CreateBindGroupLayoutError> {
let mut desc_count = descriptor::DescriptorTotalCount::default();
for binding in entry_map.values() {
for entry in entry_map.values() {
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 {
ty: wgt::BufferBindingType::Uniform,
has_dynamic_offset: false,
@ -1208,6 +1207,7 @@ impl<B: GfxBackend> Device<B> {
} => (
&mut desc_count.uniform_buffer,
Some(wgt::Features::BUFFER_BINDING_ARRAY),
false,
),
Bt::Buffer {
ty: wgt::BufferBindingType::Uniform,
@ -1216,44 +1216,65 @@ impl<B: GfxBackend> Device<B> {
} => (
&mut desc_count.uniform_buffer_dynamic,
Some(wgt::Features::BUFFER_BINDING_ARRAY),
false,
),
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { .. },
has_dynamic_offset: false,
ty: wgt::BufferBindingType::Storage { read_only },
has_dynamic_offset,
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),
!read_only,
),
Bt::Buffer {
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::Sampler { .. } => (&mut desc_count.sampler, None, false),
Bt::Texture { .. } => (
&mut desc_count.sampled_image,
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
Some(count) => {
let feature = array_feature
.ok_or(binding_model::CreateBindGroupLayoutError::ArrayUnsupported)?;
if !self.features.contains(feature) {
return Err(binding_model::CreateBindGroupLayoutError::MissingFeature(
feature,
));
}
required_features |= array_feature
.ok_or(binding_model::BindGroupLayoutEntryError::ArrayUnsupported)
.map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
binding: entry.binding,
error,
})?;
count.get()
}
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
@ -1478,11 +1499,6 @@ impl<B: GfxBackend> Device<B> {
SmallVec::from([buffer_desc])
}
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 {
let count = count.get() as usize;
let num_bindings = bindings_array.len();
@ -1631,13 +1647,9 @@ impl<B: GfxBackend> Device<B> {
if !view.format_features.flags.contains(
wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
) {
return Err(if self.features.contains(
wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
) {
Error::StorageReadWriteNotSupported(view.format)
} else {
Error::MissingFeatures(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES)
});
return Err(Error::StorageReadWriteNotSupported(
view.format,
));
}
resource::TextureUse::STORAGE_STORE
@ -1686,11 +1698,6 @@ impl<B: GfxBackend> Device<B> {
}
}
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 {
let count = count.get() as usize;
let num_bindings = bindings_array.len();
@ -1814,11 +1821,10 @@ impl<B: GfxBackend> Device<B> {
});
}
if !desc.push_constant_ranges.is_empty()
&& !self.features.contains(wgt::Features::PUSH_CONSTANTS)
{
return Err(Error::MissingFeature(wgt::Features::PUSH_CONSTANTS));
if !desc.push_constant_ranges.is_empty() {
self.require_features(wgt::Features::PUSH_CONSTANTS)?;
}
let mut used_stages = wgt::ShaderStage::empty();
for (index, pc) in desc.push_constant_ranges.iter().enumerate() {
if pc.stages.intersects(used_stages) {
@ -2169,14 +2175,7 @@ impl<B: GfxBackend> Device<B> {
| wgt::VertexFormat::Float64x3
| wgt::VertexFormat::Float64x4 = attribute.format
{
if !self
.features
.contains(wgt::Features::VERTEX_ATTRIBUTE_64BIT)
{
return Err(pipeline::CreateRenderPipelineError::MissingFeature(
wgt::Features::VERTEX_ATTRIBUTE_64BIT,
));
}
self.require_features(wgt::Features::VERTEX_ATTRIBUTE_64BIT)?;
}
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) {
return Err(pipeline::CreateRenderPipelineError::MissingFeature(
wgt::Features::DEPTH_CLAMPING,
));
if desc.primitive.clamp_depth {
self.require_features(wgt::Features::DEPTH_CLAMPING)?;
}
if desc.primitive.polygon_mode != wgt::PolygonMode::Fill
&& !self.features.contains(wgt::Features::NON_FILL_POLYGON_MODE)
{
return Err(pipeline::CreateRenderPipelineError::MissingFeature(
wgt::Features::NON_FILL_POLYGON_MODE,
));
if desc.primitive.polygon_mode != wgt::PolygonMode::Fill {
self.require_features(wgt::Features::NON_FILL_POLYGON_MODE)?;
}
if desc.primitive.conservative
&& !self
.features
.contains(wgt::Features::CONSERVATIVE_RASTERIZATION)
{
return Err(pipeline::CreateRenderPipelineError::MissingFeature(
wgt::Features::CONSERVATIVE_RASTERIZATION,
));
if desc.primitive.conservative {
self.require_features(wgt::Features::CONSERVATIVE_RASTERIZATION)?;
}
if desc.primitive.conservative && desc.primitive.polygon_mode != wgt::PolygonMode::Fill {
@ -2596,6 +2583,47 @@ impl<B: GfxBackend> Device<B> {
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> {
@ -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)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
@ -4017,50 +4049,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
});
}
match desc.ty {
wgt::QueryType::Timestamp => {
if !device.features.contains(wgt::Features::TIMESTAMP_QUERY) {
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 query_set = match device.create_query_set(device_id, desc) {
Ok(query_set) => query_set,
Err(err) => break err,
};
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)]
pub struct Adapter<B: hal::Backend> {
pub(crate) raw: hal::adapter::Adapter<B>,
@ -137,89 +218,13 @@ impl<B: GfxBackend> Adapter<B> {
| wgt::Features::MAPPABLE_PRIMARY_BUFFERS
| wgt::Features::PUSH_CONSTANTS
| wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
features.set(
wgt::Features::DEPTH_CLAMPING,
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),
);
for &(hi, lo) in FEATURE_MAP.iter() {
features.set(hi, adapter_features.contains(lo));
}
features.set(
wgt::Features::TIMESTAMP_QUERY,
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 {
anisotropic_filtering: adapter_features.contains(hal::Features::SAMPLER_ANISOTROPY),
@ -452,12 +457,12 @@ impl<B: GfxBackend> Adapter<B> {
// Check features that are always needed
let wishful_features = hal::Features::ROBUST_BUFFER_ACCESS
| hal::Features::VERTEX_STORES_AND_ATOMICS
| hal::Features::FRAGMENT_STORES_AND_ATOMICS
| hal::Features::NDC_Y_UP
| hal::Features::INDEPENDENT_BLENDING
| 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;
if enabled_features != wishful_features {
log::warn!(
@ -466,96 +471,10 @@ impl<B: GfxBackend> Adapter<B> {
);
}
// Features
enabled_features.set(
hal::Features::DEPTH_CLAMP,
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),
);
// Enable low-level features
for &(hi, lo) in FEATURE_MAP.iter() {
enabled_features.set(lo, desc.features.contains(hi));
}
let family = self
.raw

View File

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

View File

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

View File

@ -526,6 +526,15 @@ bitflags::bitflags! {
///
/// This is a native only feature.
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.
const ALL_WEBGPU = 0x0000_0000_0000_FFFF;
/// Features that are only available when targeting native (not web).