mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 14:55:05 +00:00
Support descriptor arrays shorter than binding length
This commit is contained in:
parent
8fa3ca731b
commit
b679342d9e
@ -65,8 +65,16 @@ pub enum CreateBindGroupError {
|
||||
InvalidTextureView(TextureViewId),
|
||||
#[error("sampler {0:?} is invalid")]
|
||||
InvalidSampler(SamplerId),
|
||||
#[error("binding count declared with {expected} items, but {actual} items were provided")]
|
||||
#[error(
|
||||
"binding count declared with at most {expected} items, but {actual} items were provided"
|
||||
)]
|
||||
BindingArrayPartialLengthMismatch { actual: usize, expected: usize },
|
||||
#[error(
|
||||
"binding count declared with exactly {expected} items, but {actual} items were provided"
|
||||
)]
|
||||
BindingArrayLengthMismatch { actual: usize, expected: usize },
|
||||
#[error("array binding provided zero elements")]
|
||||
BindingArrayZeroLength,
|
||||
#[error("bound buffer range {range:?} does not fit in buffer of size {size}")]
|
||||
BindingRangeTooLarge {
|
||||
buffer: BufferId,
|
||||
|
@ -152,3 +152,12 @@ pub fn check_texture_dimension_size(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bind_group_layout_flags(features: wgt::Features) -> hal::BindGroupLayoutFlags {
|
||||
let mut flags = hal::BindGroupLayoutFlags::empty();
|
||||
flags.set(
|
||||
hal::BindGroupLayoutFlags::PARTIALLY_BOUND,
|
||||
features.contains(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY),
|
||||
);
|
||||
flags
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use smallvec::SmallVec;
|
||||
use thiserror::Error;
|
||||
use wgt::{BufferAddress, TextureFormat, TextureViewDimension};
|
||||
|
||||
use std::{borrow::Cow, iter, marker::PhantomData, mem, ops::Range, ptr};
|
||||
use std::{borrow::Cow, iter, marker::PhantomData, mem, num::NonZeroU32, ops::Range, ptr};
|
||||
|
||||
mod life;
|
||||
pub mod queue;
|
||||
@ -1186,10 +1186,13 @@ impl<A: HalApi> Device<A> {
|
||||
})?;
|
||||
}
|
||||
|
||||
let bgl_flags = conv::bind_group_layout_flags(self.features);
|
||||
|
||||
let mut hal_bindings = entry_map.values().cloned().collect::<Vec<_>>();
|
||||
hal_bindings.sort_by_key(|b| b.binding);
|
||||
let hal_desc = hal::BindGroupLayoutDescriptor {
|
||||
label,
|
||||
flags: bgl_flags,
|
||||
entries: &hal_bindings,
|
||||
};
|
||||
let raw = unsafe {
|
||||
@ -1390,7 +1393,7 @@ impl<A: HalApi> Device<A> {
|
||||
.entries
|
||||
.get(&binding)
|
||||
.ok_or(Error::MissingBindingDeclaration(binding))?;
|
||||
let res_index = match entry.resource {
|
||||
let (res_index, count) = match entry.resource {
|
||||
Br::Buffer(ref bb) => {
|
||||
let bb = Self::create_buffer_binding(
|
||||
bb,
|
||||
@ -1405,21 +1408,11 @@ impl<A: HalApi> Device<A> {
|
||||
|
||||
let res_index = hal_buffers.len();
|
||||
hal_buffers.push(bb);
|
||||
res_index
|
||||
(res_index, 1)
|
||||
}
|
||||
Br::BufferArray(ref bindings_array) => {
|
||||
if let Some(count) = decl.count {
|
||||
let count = count.get() as usize;
|
||||
let num_bindings = bindings_array.len();
|
||||
if count != num_bindings {
|
||||
return Err(Error::BindingArrayLengthMismatch {
|
||||
actual: num_bindings,
|
||||
expected: count,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(Error::SingleBindingExpected);
|
||||
}
|
||||
let num_bindings = bindings_array.len();
|
||||
Self::check_array_binding(self.features, decl.count, num_bindings)?;
|
||||
|
||||
let res_index = hal_buffers.len();
|
||||
for bb in bindings_array.iter() {
|
||||
@ -1435,7 +1428,7 @@ impl<A: HalApi> Device<A> {
|
||||
)?;
|
||||
hal_buffers.push(bb);
|
||||
}
|
||||
res_index
|
||||
(res_index, num_bindings)
|
||||
}
|
||||
Br::Sampler(id) => {
|
||||
match decl.ty {
|
||||
@ -1467,7 +1460,7 @@ impl<A: HalApi> Device<A> {
|
||||
|
||||
let res_index = hal_samplers.len();
|
||||
hal_samplers.push(&sampler.raw);
|
||||
res_index
|
||||
(res_index, 1)
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::WrongBindingType {
|
||||
@ -1508,21 +1501,11 @@ impl<A: HalApi> Device<A> {
|
||||
view: &view.raw,
|
||||
usage: internal_use,
|
||||
});
|
||||
res_index
|
||||
(res_index, 1)
|
||||
}
|
||||
Br::TextureViewArray(ref bindings_array) => {
|
||||
if let Some(count) = decl.count {
|
||||
let count = count.get() as usize;
|
||||
let num_bindings = bindings_array.len();
|
||||
if count != num_bindings {
|
||||
return Err(Error::BindingArrayLengthMismatch {
|
||||
actual: num_bindings,
|
||||
expected: count,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(Error::SingleBindingExpected);
|
||||
}
|
||||
let num_bindings = bindings_array.len();
|
||||
Self::check_array_binding(self.features, decl.count, num_bindings)?;
|
||||
|
||||
let res_index = hal_textures.len();
|
||||
for &id in bindings_array.iter() {
|
||||
@ -1554,13 +1537,14 @@ impl<A: HalApi> Device<A> {
|
||||
});
|
||||
}
|
||||
|
||||
res_index
|
||||
(res_index, num_bindings)
|
||||
}
|
||||
};
|
||||
|
||||
hal_entries.push(hal::BindGroupEntry {
|
||||
binding,
|
||||
resource_index: res_index as u32,
|
||||
count: count as u32,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1599,6 +1583,39 @@ impl<A: HalApi> Device<A> {
|
||||
})
|
||||
}
|
||||
|
||||
fn check_array_binding(
|
||||
features: wgt::Features,
|
||||
count: Option<NonZeroU32>,
|
||||
num_bindings: usize,
|
||||
) -> Result<(), super::binding_model::CreateBindGroupError> {
|
||||
use super::binding_model::CreateBindGroupError as Error;
|
||||
|
||||
if let Some(count) = count {
|
||||
let count = count.get() as usize;
|
||||
if count < num_bindings {
|
||||
return Err(Error::BindingArrayPartialLengthMismatch {
|
||||
actual: num_bindings,
|
||||
expected: count,
|
||||
});
|
||||
}
|
||||
if count != num_bindings
|
||||
&& !features.contains(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY)
|
||||
{
|
||||
return Err(Error::BindingArrayLengthMismatch {
|
||||
actual: num_bindings,
|
||||
expected: count,
|
||||
});
|
||||
}
|
||||
if num_bindings == 0 {
|
||||
return Err(Error::BindingArrayZeroLength);
|
||||
}
|
||||
} else {
|
||||
return Err(Error::SingleBindingExpected);
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn texture_use_parameters(
|
||||
binding: u32,
|
||||
decl: &wgt::BindGroupLayoutEntry,
|
||||
|
@ -334,10 +334,12 @@ impl<A: HalApi> Adapter<A> {
|
||||
desc: &DeviceDescriptor,
|
||||
trace_path: Option<&std::path::Path>,
|
||||
) -> Result<Device<A>, RequestDeviceError> {
|
||||
let open = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err {
|
||||
hal::DeviceError::Lost => RequestDeviceError::DeviceLost,
|
||||
hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory,
|
||||
})?;
|
||||
let open = unsafe { self.raw.adapter.open(desc.features, &desc.limits) }.map_err(
|
||||
|err| match err {
|
||||
hal::DeviceError::Lost => RequestDeviceError::DeviceLost,
|
||||
hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory,
|
||||
},
|
||||
)?;
|
||||
|
||||
self.create_device_from_hal(self_id, open, desc, trace_path)
|
||||
}
|
||||
|
@ -102,8 +102,11 @@ impl<A: hal::Api> Example<A> {
|
||||
);
|
||||
(exposed.adapter, exposed.capabilities)
|
||||
};
|
||||
let hal::OpenDevice { device, mut queue } =
|
||||
unsafe { adapter.open(wgt::Features::empty()).unwrap() };
|
||||
let hal::OpenDevice { device, mut queue } = unsafe {
|
||||
adapter
|
||||
.open(wgt::Features::empty(), &wgt::Limits::default())
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let window_size: (u32, u32) = window.inner_size().into();
|
||||
let surface_config = hal::SurfaceConfiguration {
|
||||
@ -149,6 +152,7 @@ impl<A: hal::Api> Example<A> {
|
||||
|
||||
let global_bgl_desc = hal::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
flags: hal::BindGroupLayoutFlags::empty(),
|
||||
entries: &[
|
||||
wgt::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
@ -186,6 +190,8 @@ impl<A: hal::Api> Example<A> {
|
||||
unsafe { device.create_bind_group_layout(&global_bgl_desc).unwrap() };
|
||||
|
||||
let local_bgl_desc = hal::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
flags: hal::BindGroupLayoutFlags::empty(),
|
||||
entries: &[wgt::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgt::ShaderStages::VERTEX,
|
||||
@ -196,7 +202,6 @@ impl<A: hal::Api> Example<A> {
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
label: None,
|
||||
};
|
||||
let local_group_layout =
|
||||
unsafe { device.create_bind_group_layout(&local_bgl_desc).unwrap() };
|
||||
@ -420,14 +425,17 @@ impl<A: hal::Api> Example<A> {
|
||||
hal::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource_index: 0,
|
||||
count: 1,
|
||||
},
|
||||
hal::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource_index: 0,
|
||||
count: 1,
|
||||
},
|
||||
hal::BindGroupEntry {
|
||||
binding: 2,
|
||||
resource_index: 0,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -449,6 +457,7 @@ impl<A: hal::Api> Example<A> {
|
||||
entries: &[hal::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource_index: 0,
|
||||
count: 1,
|
||||
}],
|
||||
};
|
||||
unsafe { device.create_bind_group(&local_group_desc).unwrap() }
|
||||
|
@ -262,6 +262,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
unsafe fn open(
|
||||
&self,
|
||||
features: wgt::Features,
|
||||
_limits: &wgt::Limits,
|
||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||
let queue = self
|
||||
.device
|
||||
|
@ -74,7 +74,11 @@ impl crate::Surface<Api> for Context {
|
||||
}
|
||||
|
||||
impl crate::Adapter<Api> for Context {
|
||||
unsafe fn open(&self, features: wgt::Features) -> DeviceResult<crate::OpenDevice<Api>> {
|
||||
unsafe fn open(
|
||||
&self,
|
||||
features: wgt::Features,
|
||||
_limits: &wgt::Limits,
|
||||
) -> DeviceResult<crate::OpenDevice<Api>> {
|
||||
Err(crate::DeviceError::Lost)
|
||||
}
|
||||
unsafe fn texture_format_capabilities(
|
||||
|
@ -419,6 +419,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
unsafe fn open(
|
||||
&self,
|
||||
features: wgt::Features,
|
||||
_limits: &wgt::Limits,
|
||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||
let gl = &self.shared.context.lock();
|
||||
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);
|
||||
|
@ -188,7 +188,11 @@ pub trait Surface<A: Api>: Send + Sync {
|
||||
}
|
||||
|
||||
pub trait Adapter<A: Api>: Send + Sync {
|
||||
unsafe fn open(&self, features: wgt::Features) -> Result<OpenDevice<A>, DeviceError>;
|
||||
unsafe fn open(
|
||||
&self,
|
||||
features: wgt::Features,
|
||||
limits: &wgt::Limits,
|
||||
) -> Result<OpenDevice<A>, DeviceError>;
|
||||
|
||||
/// Return the set of supported capabilities for a texture format.
|
||||
unsafe fn texture_format_capabilities(
|
||||
@ -524,6 +528,14 @@ bitflags!(
|
||||
}
|
||||
);
|
||||
|
||||
bitflags!(
|
||||
/// Pipeline layout creation flags.
|
||||
pub struct BindGroupLayoutFlags: u32 {
|
||||
/// Allows for bind group binding arrays to be shorter than the array in the BGL.
|
||||
const PARTIALLY_BOUND = 1 << 0;
|
||||
}
|
||||
);
|
||||
|
||||
bitflags!(
|
||||
/// Texture format capability flags.
|
||||
pub struct TextureFormatCapabilities: u32 {
|
||||
@ -798,6 +810,7 @@ pub struct SamplerDescriptor<'a> {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BindGroupLayoutDescriptor<'a> {
|
||||
pub label: Label<'a>,
|
||||
pub flags: BindGroupLayoutFlags,
|
||||
pub entries: &'a [wgt::BindGroupLayoutEntry],
|
||||
}
|
||||
|
||||
@ -847,6 +860,7 @@ impl<A: Api> Clone for TextureBinding<'_, A> {
|
||||
pub struct BindGroupEntry {
|
||||
pub binding: u32,
|
||||
pub resource_index: u32,
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
/// BindGroup descriptor.
|
||||
|
@ -19,6 +19,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
unsafe fn open(
|
||||
&self,
|
||||
features: wgt::Features,
|
||||
_limits: &wgt::Limits,
|
||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||
let queue = self
|
||||
.shared
|
||||
|
@ -7,15 +7,17 @@ use std::{ffi::CStr, mem, ptr, sync::Arc};
|
||||
|
||||
//TODO: const fn?
|
||||
fn indexing_features() -> wgt::Features {
|
||||
wgt::Features::BUFFER_BINDING_ARRAY | wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgt::Features::UNSIZED_BINDING_ARRAY
|
||||
}
|
||||
|
||||
/// Aggregate of the `vk::PhysicalDevice*Features` structs used by `gfx`.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PhysicalDeviceFeatures {
|
||||
core: vk::PhysicalDeviceFeatures,
|
||||
vulkan_1_2: Option<vk::PhysicalDeviceVulkan12Features>,
|
||||
descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT>,
|
||||
pub(super) vulkan_1_2: Option<vk::PhysicalDeviceVulkan12Features>,
|
||||
pub(super) descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT>,
|
||||
imageless_framebuffer: Option<vk::PhysicalDeviceImagelessFramebufferFeaturesKHR>,
|
||||
timeline_semaphore: Option<vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR>,
|
||||
image_robustness: Option<vk::PhysicalDeviceImageRobustnessFeaturesEXT>,
|
||||
@ -54,7 +56,29 @@ impl PhysicalDeviceFeatures {
|
||||
requested_features: wgt::Features,
|
||||
downlevel_flags: wgt::DownlevelFlags,
|
||||
private_caps: &super::PrivateCapabilities,
|
||||
uab_types: super::UpdateAfterBindTypes,
|
||||
) -> Self {
|
||||
let needs_sampled_image_non_uniform = requested_features.contains(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
);
|
||||
let needs_storage_buffer_non_uniform = requested_features.contains(
|
||||
wgt::Features::BUFFER_BINDING_ARRAY
|
||||
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
);
|
||||
let needs_uniform_buffer_non_uniform = requested_features.contains(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
);
|
||||
let needs_storage_image_non_uniform = requested_features.contains(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
);
|
||||
let needs_partially_bound =
|
||||
requested_features.intersects(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY);
|
||||
|
||||
Self {
|
||||
// vk::PhysicalDeviceFeatures is a struct composed of Bool32's while
|
||||
// Features is a bitfield so we need to map everything manually
|
||||
@ -132,32 +156,30 @@ impl PhysicalDeviceFeatures {
|
||||
)
|
||||
.descriptor_indexing(requested_features.intersects(indexing_features()))
|
||||
.shader_sampled_image_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_sampled_image_non_uniform,
|
||||
)
|
||||
.shader_storage_image_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_storage_image_non_uniform,
|
||||
)
|
||||
//.shader_storage_buffer_array_non_uniform_indexing(
|
||||
.shader_uniform_buffer_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::BUFFER_BINDING_ARRAY
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_uniform_buffer_non_uniform,
|
||||
)
|
||||
.shader_storage_buffer_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::BUFFER_BINDING_ARRAY
|
||||
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_storage_buffer_non_uniform,
|
||||
)
|
||||
.descriptor_binding_sampled_image_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::SAMPLED_TEXTURE),
|
||||
)
|
||||
.descriptor_binding_storage_image_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::STORAGE_TEXTURE),
|
||||
)
|
||||
.descriptor_binding_uniform_buffer_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::UNIFORM_BUFFER),
|
||||
)
|
||||
.descriptor_binding_storage_buffer_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::STORAGE_BUFFER),
|
||||
)
|
||||
.descriptor_binding_partially_bound(needs_partially_bound)
|
||||
.runtime_descriptor_array(
|
||||
requested_features.contains(wgt::Features::UNSIZED_BINDING_ARRAY),
|
||||
)
|
||||
@ -175,32 +197,30 @@ impl PhysicalDeviceFeatures {
|
||||
Some(
|
||||
vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::builder()
|
||||
.shader_sampled_image_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_sampled_image_non_uniform,
|
||||
)
|
||||
.shader_storage_image_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_storage_image_non_uniform,
|
||||
)
|
||||
//.shader_storage_buffer_array_non_uniform_indexing(
|
||||
.shader_uniform_buffer_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::BUFFER_BINDING_ARRAY
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_uniform_buffer_non_uniform,
|
||||
)
|
||||
.shader_storage_buffer_array_non_uniform_indexing(
|
||||
requested_features.contains(
|
||||
wgt::Features::BUFFER_BINDING_ARRAY
|
||||
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
needs_storage_buffer_non_uniform,
|
||||
)
|
||||
.descriptor_binding_sampled_image_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::SAMPLED_TEXTURE),
|
||||
)
|
||||
.descriptor_binding_storage_image_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::STORAGE_TEXTURE),
|
||||
)
|
||||
.descriptor_binding_uniform_buffer_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::UNIFORM_BUFFER),
|
||||
)
|
||||
.descriptor_binding_storage_buffer_update_after_bind(
|
||||
uab_types.contains(super::UpdateAfterBindTypes::STORAGE_BUFFER),
|
||||
)
|
||||
.descriptor_binding_partially_bound(needs_partially_bound)
|
||||
.runtime_descriptor_array(
|
||||
requested_features.contains(wgt::Features::UNSIZED_BINDING_ARRAY),
|
||||
)
|
||||
@ -380,6 +400,9 @@ impl PhysicalDeviceFeatures {
|
||||
if vulkan_1_2.runtime_descriptor_array != 0 {
|
||||
features |= F::UNSIZED_BINDING_ARRAY;
|
||||
}
|
||||
if vulkan_1_2.descriptor_binding_partially_bound != 0 {
|
||||
features |= F::PARTIALLY_BOUND_BINDING_ARRAY;
|
||||
}
|
||||
//if vulkan_1_2.sampler_mirror_clamp_to_edge != 0 {
|
||||
//if vulkan_1_2.sampler_filter_minmax != 0 {
|
||||
if vulkan_1_2.draw_indirect_count != 0 {
|
||||
@ -419,6 +442,9 @@ impl PhysicalDeviceFeatures {
|
||||
) {
|
||||
features.insert(F::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING);
|
||||
}
|
||||
if descriptor_indexing.descriptor_binding_partially_bound != 0 {
|
||||
features |= F::PARTIALLY_BOUND_BINDING_ARRAY;
|
||||
}
|
||||
if descriptor_indexing.runtime_descriptor_array != 0 {
|
||||
features |= F::UNSIZED_BINDING_ARRAY;
|
||||
}
|
||||
@ -438,11 +464,18 @@ impl PhysicalDeviceFeatures {
|
||||
}
|
||||
|
||||
/// Information gathered about a physical device capabilities.
|
||||
#[derive(Default)]
|
||||
pub struct PhysicalDeviceCapabilities {
|
||||
supported_extensions: Vec<vk::ExtensionProperties>,
|
||||
properties: vk::PhysicalDeviceProperties,
|
||||
vulkan_1_2: Option<vk::PhysicalDeviceVulkan12Properties>,
|
||||
descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingPropertiesEXT>,
|
||||
}
|
||||
|
||||
// This is safe because the structs have `p_next: *mut c_void`, which we null out/never read.
|
||||
unsafe impl Send for PhysicalDeviceCapabilities {}
|
||||
unsafe impl Sync for PhysicalDeviceCapabilities {}
|
||||
|
||||
impl PhysicalDeviceCapabilities {
|
||||
fn supports_extension(&self, extension: &CStr) -> bool {
|
||||
self.supported_extensions
|
||||
@ -498,8 +531,63 @@ impl PhysicalDeviceCapabilities {
|
||||
extensions
|
||||
}
|
||||
|
||||
fn to_wgpu_limits(&self) -> wgt::Limits {
|
||||
fn to_wgpu_limits(&self, features: &PhysicalDeviceFeatures) -> wgt::Limits {
|
||||
let limits = &self.properties.limits;
|
||||
|
||||
let uab_types = super::UpdateAfterBindTypes::from_features(features);
|
||||
|
||||
let max_sampled_textures =
|
||||
if uab_types.contains(super::UpdateAfterBindTypes::SAMPLED_TEXTURE) {
|
||||
if let Some(di) = self.descriptor_indexing {
|
||||
di.max_per_stage_descriptor_update_after_bind_sampled_images
|
||||
} else if let Some(vk_1_2) = self.vulkan_1_2 {
|
||||
vk_1_2.max_per_stage_descriptor_update_after_bind_sampled_images
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_sampled_images
|
||||
}
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_sampled_images
|
||||
};
|
||||
|
||||
let max_storage_textures =
|
||||
if uab_types.contains(super::UpdateAfterBindTypes::STORAGE_TEXTURE) {
|
||||
if let Some(di) = self.descriptor_indexing {
|
||||
di.max_per_stage_descriptor_update_after_bind_storage_images
|
||||
} else if let Some(vk_1_2) = self.vulkan_1_2 {
|
||||
vk_1_2.max_per_stage_descriptor_update_after_bind_storage_images
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_storage_images
|
||||
}
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_storage_images
|
||||
};
|
||||
|
||||
let max_uniform_buffers = if uab_types.contains(super::UpdateAfterBindTypes::UNIFORM_BUFFER)
|
||||
{
|
||||
if let Some(di) = self.descriptor_indexing {
|
||||
di.max_per_stage_descriptor_update_after_bind_uniform_buffers
|
||||
} else if let Some(vk_1_2) = self.vulkan_1_2 {
|
||||
vk_1_2.max_per_stage_descriptor_update_after_bind_uniform_buffers
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_uniform_buffers
|
||||
}
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_uniform_buffers
|
||||
};
|
||||
|
||||
let max_storage_buffers = if uab_types.contains(super::UpdateAfterBindTypes::STORAGE_BUFFER)
|
||||
{
|
||||
if let Some(di) = self.descriptor_indexing {
|
||||
di.max_per_stage_descriptor_update_after_bind_storage_buffers
|
||||
} else if let Some(vk_1_2) = self.vulkan_1_2 {
|
||||
vk_1_2.max_per_stage_descriptor_update_after_bind_storage_buffers
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_storage_buffers
|
||||
}
|
||||
} else {
|
||||
limits.max_per_stage_descriptor_storage_buffers
|
||||
};
|
||||
|
||||
wgt::Limits {
|
||||
max_texture_dimension_1d: limits.max_image_dimension1_d,
|
||||
max_texture_dimension_2d: limits.max_image_dimension2_d,
|
||||
@ -512,11 +600,11 @@ impl PhysicalDeviceCapabilities {
|
||||
.max_descriptor_set_uniform_buffers_dynamic,
|
||||
max_dynamic_storage_buffers_per_pipeline_layout: limits
|
||||
.max_descriptor_set_storage_buffers_dynamic,
|
||||
max_sampled_textures_per_shader_stage: limits.max_per_stage_descriptor_sampled_images,
|
||||
max_sampled_textures_per_shader_stage: max_sampled_textures,
|
||||
max_samplers_per_shader_stage: limits.max_per_stage_descriptor_samplers,
|
||||
max_storage_buffers_per_shader_stage: limits.max_per_stage_descriptor_storage_buffers,
|
||||
max_storage_textures_per_shader_stage: limits.max_per_stage_descriptor_storage_images,
|
||||
max_uniform_buffers_per_shader_stage: limits.max_per_stage_descriptor_uniform_buffers,
|
||||
max_storage_buffers_per_shader_stage: max_storage_buffers,
|
||||
max_storage_textures_per_shader_stage: max_storage_textures,
|
||||
max_uniform_buffers_per_shader_stage: max_uniform_buffers,
|
||||
max_uniform_buffer_binding_size: limits.max_uniform_buffer_range,
|
||||
max_storage_buffer_binding_size: limits.max_storage_buffer_range,
|
||||
max_vertex_buffers: limits
|
||||
@ -547,11 +635,46 @@ impl super::InstanceShared {
|
||||
&self,
|
||||
phd: vk::PhysicalDevice,
|
||||
) -> (PhysicalDeviceCapabilities, PhysicalDeviceFeatures) {
|
||||
let capabilities = unsafe {
|
||||
PhysicalDeviceCapabilities {
|
||||
supported_extensions: self.raw.enumerate_device_extension_properties(phd).unwrap(),
|
||||
properties: self.raw.get_physical_device_properties(phd),
|
||||
}
|
||||
let capabilities = {
|
||||
let mut capabilities = PhysicalDeviceCapabilities::default();
|
||||
capabilities.supported_extensions =
|
||||
unsafe { self.raw.enumerate_device_extension_properties(phd).unwrap() };
|
||||
capabilities.properties = if let Some(ref get_device_properties) =
|
||||
self.get_physical_device_properties
|
||||
{
|
||||
let core = vk::PhysicalDeviceProperties::builder().build();
|
||||
let mut properites2 = vk::PhysicalDeviceProperties2::builder()
|
||||
.properties(core)
|
||||
.build();
|
||||
|
||||
if capabilities.properties.api_version >= vk::API_VERSION_1_2 {
|
||||
capabilities.vulkan_1_2 =
|
||||
Some(vk::PhysicalDeviceVulkan12Properties::builder().build());
|
||||
|
||||
let mut_ref = capabilities.vulkan_1_2.as_mut().unwrap();
|
||||
mut_ref.p_next =
|
||||
mem::replace(&mut properites2.p_next, mut_ref as *mut _ as *mut _);
|
||||
}
|
||||
|
||||
if capabilities.supports_extension(vk::ExtDescriptorIndexingFn::name()) {
|
||||
capabilities.descriptor_indexing =
|
||||
Some(vk::PhysicalDeviceDescriptorIndexingPropertiesEXT::builder().build());
|
||||
|
||||
let mut_ref = capabilities.descriptor_indexing.as_mut().unwrap();
|
||||
mut_ref.p_next =
|
||||
mem::replace(&mut properites2.p_next, mut_ref as *mut _ as *mut _);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
get_device_properties
|
||||
.get_physical_device_properties2_khr(phd, &mut properites2);
|
||||
}
|
||||
properites2.properties
|
||||
} else {
|
||||
unsafe { self.raw.get_physical_device_properties(phd) }
|
||||
};
|
||||
|
||||
capabilities
|
||||
};
|
||||
|
||||
let mut features = PhysicalDeviceFeatures::default();
|
||||
@ -645,6 +768,8 @@ impl super::Instance {
|
||||
&self,
|
||||
phd: vk::PhysicalDevice,
|
||||
) -> Option<crate::ExposedAdapter<super::Api>> {
|
||||
use crate::auxil::db;
|
||||
|
||||
let (phd_capabilities, phd_features) = self.shared.inspect(phd);
|
||||
|
||||
let info = wgt::AdapterInfo {
|
||||
@ -670,7 +795,6 @@ impl super::Instance {
|
||||
let (available_features, downlevel_flags) = phd_features.to_wgpu(&phd_capabilities);
|
||||
let mut workarounds = super::Workarounds::empty();
|
||||
{
|
||||
use crate::auxil::db;
|
||||
// see https://github.com/gfx-rs/gfx/issues/1930
|
||||
let _is_windows_intel_dual_src_bug = cfg!(windows)
|
||||
&& phd_capabilities.properties.vendor_id == db::intel::VENDOR
|
||||
@ -752,7 +876,7 @@ impl super::Instance {
|
||||
};
|
||||
|
||||
let capabilities = crate::Capabilities {
|
||||
limits: phd_capabilities.to_wgpu_limits(),
|
||||
limits: phd_capabilities.to_wgpu_limits(&phd_features),
|
||||
alignments: phd_capabilities.to_hal_alignments(),
|
||||
downlevel: wgt::DownlevelCapabilities {
|
||||
flags: downlevel_flags,
|
||||
@ -809,6 +933,7 @@ impl super::Adapter {
|
||||
&self,
|
||||
enabled_extensions: &[&'static CStr],
|
||||
features: wgt::Features,
|
||||
uab_types: super::UpdateAfterBindTypes,
|
||||
) -> PhysicalDeviceFeatures {
|
||||
PhysicalDeviceFeatures::from_extensions_and_requested_features(
|
||||
self.phd_capabilities.properties.api_version,
|
||||
@ -816,6 +941,7 @@ impl super::Adapter {
|
||||
features,
|
||||
self.downlevel_flags,
|
||||
&self.private_caps,
|
||||
uab_types,
|
||||
)
|
||||
}
|
||||
|
||||
@ -824,11 +950,13 @@ impl super::Adapter {
|
||||
/// - `raw_device` must be created from this adapter.
|
||||
/// - `raw_device` must be created using `family_index`, `enabled_extensions` and `physical_device_features()`
|
||||
/// - `enabled_extensions` must be a superset of `required_device_extensions()`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub unsafe fn device_from_raw(
|
||||
&self,
|
||||
raw_device: ash::Device,
|
||||
handle_is_owned: bool,
|
||||
enabled_extensions: &[&'static CStr],
|
||||
uab_types: super::UpdateAfterBindTypes,
|
||||
family_index: u32,
|
||||
queue_index: u32,
|
||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||
@ -934,10 +1062,11 @@ impl super::Adapter {
|
||||
timeline_semaphore: timeline_semaphore_fn,
|
||||
},
|
||||
vendor_id: self.phd_capabilities.properties.vendor_id,
|
||||
timestamp_period: self.phd_capabilities.properties.limits.timestamp_period,
|
||||
uab_types,
|
||||
downlevel_flags: self.downlevel_flags,
|
||||
private_caps: self.private_caps.clone(),
|
||||
workarounds: self.workarounds,
|
||||
timestamp_period: self.phd_capabilities.properties.limits.timestamp_period,
|
||||
render_passes: Mutex::new(Default::default()),
|
||||
framebuffers: Mutex::new(Default::default()),
|
||||
});
|
||||
@ -979,7 +1108,15 @@ impl super::Adapter {
|
||||
};
|
||||
gpu_alloc::GpuAllocator::new(config, properties)
|
||||
};
|
||||
let desc_allocator = gpu_descriptor::DescriptorAllocator::new(0);
|
||||
let desc_allocator = gpu_descriptor::DescriptorAllocator::new(
|
||||
if let Some(vk_12) = self.phd_capabilities.vulkan_1_2 {
|
||||
vk_12.max_update_after_bind_descriptors_in_all_pools
|
||||
} else if let Some(di) = self.phd_capabilities.descriptor_indexing {
|
||||
di.max_update_after_bind_descriptors_in_all_pools
|
||||
} else {
|
||||
0
|
||||
},
|
||||
);
|
||||
|
||||
let device = super::Device {
|
||||
shared,
|
||||
@ -999,9 +1136,14 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
unsafe fn open(
|
||||
&self,
|
||||
features: wgt::Features,
|
||||
limits: &wgt::Limits,
|
||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||
let phd_limits = &self.phd_capabilities.properties.limits;
|
||||
let uab_types = super::UpdateAfterBindTypes::from_limits(limits, phd_limits);
|
||||
|
||||
let enabled_extensions = self.required_device_extensions(features);
|
||||
let mut enabled_phd_features = self.physical_device_features(&enabled_extensions, features);
|
||||
let mut enabled_phd_features =
|
||||
self.physical_device_features(&enabled_extensions, features, uab_types);
|
||||
|
||||
let family_index = 0; //TODO
|
||||
let family_info = vk::DeviceQueueCreateInfo::builder()
|
||||
@ -1030,6 +1172,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
raw_device,
|
||||
true,
|
||||
&enabled_extensions,
|
||||
uab_types,
|
||||
family_info.queue_family_index,
|
||||
0,
|
||||
)
|
||||
|
@ -377,7 +377,12 @@ impl
|
||||
})
|
||||
.collect::<ArrayVec<_, 8>>();
|
||||
|
||||
let mut vk_flags = vk::DescriptorPoolCreateFlags::empty();
|
||||
let mut vk_flags =
|
||||
if flags.contains(gpu_descriptor::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND) {
|
||||
vk::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND
|
||||
} else {
|
||||
vk::DescriptorPoolCreateFlags::empty()
|
||||
};
|
||||
if flags.contains(gpu_descriptor::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET) {
|
||||
vk_flags |= vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET;
|
||||
}
|
||||
@ -1029,9 +1034,69 @@ impl crate::Device<super::Api> for super::Device {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let vk_info = vk::DescriptorSetLayoutCreateInfo::builder()
|
||||
.flags(vk::DescriptorSetLayoutCreateFlags::empty())
|
||||
.bindings(&vk_bindings);
|
||||
let vk_info = vk::DescriptorSetLayoutCreateInfo::builder().bindings(&vk_bindings);
|
||||
|
||||
let mut binding_flag_info;
|
||||
let binding_flag_vec;
|
||||
let mut requires_update_after_bind = false;
|
||||
|
||||
let partially_bound = desc
|
||||
.flags
|
||||
.contains(crate::BindGroupLayoutFlags::PARTIALLY_BOUND);
|
||||
|
||||
let vk_info = if !self.shared.uab_types.is_empty() || partially_bound {
|
||||
binding_flag_vec = desc
|
||||
.entries
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
let mut flags = vk::DescriptorBindingFlags::empty();
|
||||
|
||||
if partially_bound && entry.count.is_some() {
|
||||
flags |= vk::DescriptorBindingFlags::PARTIALLY_BOUND;
|
||||
}
|
||||
|
||||
let uab_type = match entry.ty {
|
||||
wgt::BindingType::Buffer {
|
||||
ty: wgt::BufferBindingType::Uniform,
|
||||
..
|
||||
} => super::UpdateAfterBindTypes::UNIFORM_BUFFER,
|
||||
wgt::BindingType::Buffer {
|
||||
ty: wgt::BufferBindingType::Storage { .. },
|
||||
..
|
||||
} => super::UpdateAfterBindTypes::STORAGE_BUFFER,
|
||||
wgt::BindingType::Texture { .. } => {
|
||||
super::UpdateAfterBindTypes::SAMPLED_TEXTURE
|
||||
}
|
||||
wgt::BindingType::StorageTexture { .. } => {
|
||||
super::UpdateAfterBindTypes::STORAGE_TEXTURE
|
||||
}
|
||||
_ => super::UpdateAfterBindTypes::empty(),
|
||||
};
|
||||
|
||||
if !uab_type.is_empty() && self.shared.uab_types.contains(uab_type) {
|
||||
flags |= vk::DescriptorBindingFlags::UPDATE_AFTER_BIND;
|
||||
requires_update_after_bind = true;
|
||||
}
|
||||
|
||||
flags
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
binding_flag_info = vk::DescriptorSetLayoutBindingFlagsCreateInfo::builder()
|
||||
.binding_flags(&binding_flag_vec);
|
||||
|
||||
vk_info.push_next(&mut binding_flag_info)
|
||||
} else {
|
||||
vk_info
|
||||
};
|
||||
|
||||
let dsl_create_flags = if requires_update_after_bind {
|
||||
vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL
|
||||
} else {
|
||||
vk::DescriptorSetLayoutCreateFlags::empty()
|
||||
};
|
||||
|
||||
let vk_info = vk_info.flags(dsl_create_flags);
|
||||
|
||||
let raw = self
|
||||
.shared
|
||||
@ -1047,6 +1112,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
raw,
|
||||
desc_count,
|
||||
types: types.into_boxed_slice(),
|
||||
requires_update_after_bind,
|
||||
})
|
||||
}
|
||||
unsafe fn destroy_bind_group_layout(&self, bg_layout: super::BindGroupLayout) {
|
||||
@ -1102,7 +1168,11 @@ impl crate::Device<super::Api> for super::Device {
|
||||
let mut vk_sets = self.desc_allocator.lock().allocate(
|
||||
&*self.shared,
|
||||
&desc.layout.raw,
|
||||
gpu_descriptor::DescriptorSetLayoutCreateFlags::empty(),
|
||||
if desc.layout.requires_update_after_bind {
|
||||
gpu_descriptor::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND
|
||||
} else {
|
||||
gpu_descriptor::DescriptorSetLayoutCreateFlags::empty()
|
||||
},
|
||||
&desc.layout.desc_count,
|
||||
1,
|
||||
)?;
|
||||
@ -1139,7 +1209,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
vk::DescriptorType::SAMPLED_IMAGE | vk::DescriptorType::STORAGE_IMAGE => {
|
||||
let index = image_infos.len();
|
||||
let start = entry.resource_index;
|
||||
let end = start + size;
|
||||
let end = start + entry.count;
|
||||
image_infos.extend(desc.textures[start as usize..end as usize].iter().map(
|
||||
|binding| {
|
||||
let layout =
|
||||
@ -1158,7 +1228,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
| vk::DescriptorType::STORAGE_BUFFER_DYNAMIC => {
|
||||
let index = buffer_infos.len();
|
||||
let start = entry.resource_index;
|
||||
let end = start + size;
|
||||
let end = start + entry.count;
|
||||
buffer_infos.extend(desc.buffers[start as usize..end as usize].iter().map(
|
||||
|binding| {
|
||||
vk::DescriptorBufferInfo::builder()
|
||||
|
@ -227,6 +227,82 @@ struct FramebufferKey {
|
||||
sample_count: u32,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
pub struct UpdateAfterBindTypes: u8 {
|
||||
const UNIFORM_BUFFER = 0x1;
|
||||
const STORAGE_BUFFER = 0x2;
|
||||
const SAMPLED_TEXTURE = 0x4;
|
||||
const STORAGE_TEXTURE = 0x8;
|
||||
}
|
||||
}
|
||||
|
||||
impl UpdateAfterBindTypes {
|
||||
fn from_limits(limits: &wgt::Limits, phd_limits: &vk::PhysicalDeviceLimits) -> Self {
|
||||
let mut uab_types = UpdateAfterBindTypes::empty();
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::UNIFORM_BUFFER,
|
||||
limits.max_uniform_buffers_per_shader_stage
|
||||
> phd_limits.max_per_stage_descriptor_uniform_buffers,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::STORAGE_BUFFER,
|
||||
limits.max_storage_buffers_per_shader_stage
|
||||
> phd_limits.max_per_stage_descriptor_storage_buffers,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::SAMPLED_TEXTURE,
|
||||
limits.max_sampled_textures_per_shader_stage
|
||||
> phd_limits.max_per_stage_descriptor_sampled_images,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::STORAGE_TEXTURE,
|
||||
limits.max_storage_textures_per_shader_stage
|
||||
> phd_limits.max_per_stage_descriptor_storage_images,
|
||||
);
|
||||
uab_types
|
||||
}
|
||||
|
||||
fn from_features(features: &adapter::PhysicalDeviceFeatures) -> Self {
|
||||
let mut uab_types = UpdateAfterBindTypes::empty();
|
||||
if let Some(vk_12) = features.vulkan_1_2 {
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::UNIFORM_BUFFER,
|
||||
vk_12.descriptor_binding_uniform_buffer_update_after_bind != 0,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::STORAGE_BUFFER,
|
||||
vk_12.descriptor_binding_storage_buffer_update_after_bind != 0,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::SAMPLED_TEXTURE,
|
||||
vk_12.descriptor_binding_sampled_image_update_after_bind != 0,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::STORAGE_TEXTURE,
|
||||
vk_12.descriptor_binding_storage_image_update_after_bind != 0,
|
||||
);
|
||||
} else if let Some(di) = features.descriptor_indexing {
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::UNIFORM_BUFFER,
|
||||
di.descriptor_binding_uniform_buffer_update_after_bind != 0,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::STORAGE_BUFFER,
|
||||
di.descriptor_binding_storage_buffer_update_after_bind != 0,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::SAMPLED_TEXTURE,
|
||||
di.descriptor_binding_sampled_image_update_after_bind != 0,
|
||||
);
|
||||
uab_types.set(
|
||||
UpdateAfterBindTypes::STORAGE_TEXTURE,
|
||||
di.descriptor_binding_storage_image_update_after_bind != 0,
|
||||
);
|
||||
}
|
||||
uab_types
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceShared {
|
||||
raw: ash::Device,
|
||||
handle_is_owned: bool,
|
||||
@ -234,6 +310,7 @@ struct DeviceShared {
|
||||
extension_fns: DeviceExtensionFunctions,
|
||||
vendor_id: u32,
|
||||
timestamp_period: f32,
|
||||
uab_types: UpdateAfterBindTypes,
|
||||
downlevel_flags: wgt::DownlevelFlags,
|
||||
private_caps: PrivateCapabilities,
|
||||
workarounds: Workarounds,
|
||||
@ -314,6 +391,7 @@ pub struct BindGroupLayout {
|
||||
raw: vk::DescriptorSetLayout,
|
||||
desc_count: gpu_descriptor::DescriptorTotalCount,
|
||||
types: Box<[(vk::DescriptorType, u32)]>,
|
||||
requires_update_after_bind: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -330,6 +330,10 @@ bitflags::bitflags! {
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING = 1 << 21;
|
||||
/// Allows the user to create bind groups continaing arrays with less bindings than the BindGroupLayout.
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const PARTIALLY_BOUND_BINDING_ARRAY = 1 << 22;
|
||||
/// Allows the user to create unsized uniform arrays of bindings:
|
||||
///
|
||||
/// eg. `uniform texture2D textures[]`.
|
||||
@ -339,7 +343,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s runtimeDescriptorArray feature
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const UNSIZED_BINDING_ARRAY = 1 << 22;
|
||||
const UNSIZED_BINDING_ARRAY = 1 << 23;
|
||||
/// Allows the user to call [`RenderPass::multi_draw_indirect`] and [`RenderPass::multi_draw_indexed_indirect`].
|
||||
///
|
||||
/// Allows multiple indirect calls to be dispatched from a single buffer.
|
||||
@ -349,7 +353,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const MULTI_DRAW_INDIRECT = 1 << 23;
|
||||
const MULTI_DRAW_INDIRECT = 1 << 24;
|
||||
/// Allows the user to call [`RenderPass::multi_draw_indirect_count`] and [`RenderPass::multi_draw_indexed_indirect_count`].
|
||||
///
|
||||
/// This allows the use of a buffer containing the actual number of draw calls.
|
||||
@ -359,7 +363,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan 1.2+ (or VK_KHR_draw_indirect_count)
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const MULTI_DRAW_INDIRECT_COUNT = 1 << 24;
|
||||
const MULTI_DRAW_INDIRECT_COUNT = 1 << 25;
|
||||
/// Allows the use of push constants: small, fast bits of memory that can be updated
|
||||
/// inside a [`RenderPass`].
|
||||
///
|
||||
@ -376,7 +380,7 @@ bitflags::bitflags! {
|
||||
/// - OpenGL (emulated with uniforms)
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const PUSH_CONSTANTS = 1 << 25;
|
||||
const PUSH_CONSTANTS = 1 << 26;
|
||||
/// Allows the use of [`AddressMode::ClampToBorder`].
|
||||
///
|
||||
/// Supported platforms:
|
||||
@ -387,7 +391,7 @@ bitflags::bitflags! {
|
||||
/// - OpenGL
|
||||
///
|
||||
/// This is a web and native feature.
|
||||
const ADDRESS_MODE_CLAMP_TO_BORDER = 1 << 26;
|
||||
const ADDRESS_MODE_CLAMP_TO_BORDER = 1 << 27;
|
||||
/// Allows the user to set [`PolygonMode::Line`] in [`PrimitiveState::polygon_mode`]
|
||||
///
|
||||
/// This allows drawing polygons/triangles as lines (wireframe) instead of filled
|
||||
@ -398,7 +402,7 @@ bitflags::bitflags! {
|
||||
/// - Metal
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const POLYGON_MODE_LINE= 1 << 27;
|
||||
const POLYGON_MODE_LINE= 1 << 28;
|
||||
/// Allows the user to set [`PolygonMode::Point`] in [`PrimitiveState::polygon_mode`]
|
||||
///
|
||||
/// This allows only drawing the vertices of polygons/triangles instead of filled
|
||||
@ -408,7 +412,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const POLYGON_MODE_POINT = 1 << 28;
|
||||
const POLYGON_MODE_POINT = 1 << 29;
|
||||
/// Enables ETC family of compressed textures. All ETC textures use 4x4 pixel blocks.
|
||||
/// ETC2 RGB and RGBA1 are 8 bytes per block. RTC2 RGBA8 and EAC are 16 bytes per block.
|
||||
///
|
||||
@ -423,7 +427,7 @@ bitflags::bitflags! {
|
||||
/// - Mobile (some)
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const TEXTURE_COMPRESSION_ETC2 = 1 << 29;
|
||||
const TEXTURE_COMPRESSION_ETC2 = 1 << 30;
|
||||
/// Enables ASTC family of compressed textures. ASTC textures use pixel blocks varying from 4x4 to 12x12.
|
||||
/// Blocks are always 16 bytes.
|
||||
///
|
||||
@ -438,7 +442,7 @@ bitflags::bitflags! {
|
||||
/// - Mobile (some)
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const TEXTURE_COMPRESSION_ASTC_LDR = 1 << 30;
|
||||
const TEXTURE_COMPRESSION_ASTC_LDR = 1 << 31;
|
||||
/// Enables device specific texture format features.
|
||||
///
|
||||
/// See `TextureFormatFeatures` for a listing of the features in question.
|
||||
@ -450,7 +454,7 @@ bitflags::bitflags! {
|
||||
/// This extension does not enable additional formats.
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES = 1 << 31;
|
||||
const TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES = 1 << 32;
|
||||
/// Enables 64-bit floating point types in SPIR-V shaders.
|
||||
///
|
||||
/// Note: even when supported by GPU hardware, 64-bit floating point operations are
|
||||
@ -460,7 +464,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const SHADER_FLOAT64 = 1 << 32;
|
||||
const SHADER_FLOAT64 = 1 << 33;
|
||||
/// Enables using 64-bit types for vertex attributes.
|
||||
///
|
||||
/// Requires SHADER_FLOAT64.
|
||||
@ -468,7 +472,7 @@ bitflags::bitflags! {
|
||||
/// Supported Platforms: N/A
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const VERTEX_ATTRIBUTE_64BIT = 1 << 33;
|
||||
const VERTEX_ATTRIBUTE_64BIT = 1 << 34;
|
||||
/// Allows the user to set a overestimation-conservative-rasterization in [`PrimitiveState::conservative`]
|
||||
///
|
||||
/// Processing of degenerate triangles/lines is hardware specific.
|
||||
@ -478,7 +482,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const CONSERVATIVE_RASTERIZATION = 1 << 34;
|
||||
const CONSERVATIVE_RASTERIZATION = 1 << 35;
|
||||
/// 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.
|
||||
@ -487,14 +491,14 @@ bitflags::bitflags! {
|
||||
/// - All
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const VERTEX_WRITABLE_STORAGE = 1 << 35;
|
||||
const VERTEX_WRITABLE_STORAGE = 1 << 36;
|
||||
/// Enables clear to zero for buffers & textures.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - All
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const CLEAR_COMMANDS = 1 << 36;
|
||||
const CLEAR_COMMANDS = 1 << 37;
|
||||
/// Enables creating shader modules from SPIR-V binary data (unsafe).
|
||||
///
|
||||
/// SPIR-V data is not parsed or interpreted in any way; you can use
|
||||
@ -506,7 +510,7 @@ bitflags::bitflags! {
|
||||
/// Vulkan implementation.
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const SPIRV_SHADER_PASSTHROUGH = 1 << 37;
|
||||
const SPIRV_SHADER_PASSTHROUGH = 1 << 38;
|
||||
/// Enables `builtin(primitive_index)` in fragment shaders.
|
||||
///
|
||||
/// Note: enables geometry processing for pipelines using the builtin.
|
||||
@ -517,7 +521,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const SHADER_PRIMITIVE_INDEX = 1 << 38;
|
||||
const SHADER_PRIMITIVE_INDEX = 1 << 39;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user