mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-26 08:44:08 +00:00
Merge #1391
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:
commit
13f2ca571c
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -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).
|
||||
|
Loading…
Reference in New Issue
Block a user