pub(crate) use self::update::{check_descriptor_write, DescriptorWriteInfo};
pub use self::{
collection::DescriptorSetsCollection,
persistent::PersistentDescriptorSet,
update::{DescriptorSetUpdateError, WriteDescriptorSet, WriteDescriptorSetElements},
};
use self::{layout::DescriptorSetLayout, sys::UnsafeDescriptorSet};
use crate::{
buffer::{view::BufferViewAbstract, BufferAccess},
descriptor_set::layout::DescriptorType,
device::DeviceOwned,
image::view::ImageViewAbstract,
sampler::Sampler,
OomError, VulkanObject,
};
use ahash::HashMap;
use smallvec::{smallvec, SmallVec};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
ptr,
sync::Arc,
};
pub mod allocator;
mod collection;
pub mod layout;
pub mod persistent;
pub mod pool;
pub mod sys;
mod update;
pub unsafe trait DescriptorSet: DeviceOwned + Send + Sync {
fn inner(&self) -> &UnsafeDescriptorSet;
fn layout(&self) -> &Arc<DescriptorSetLayout>;
fn offsets(
self: Arc<Self>,
dynamic_offsets: impl IntoIterator<Item = u32>,
) -> DescriptorSetWithOffsets
where
Self: Sized + 'static,
{
DescriptorSetWithOffsets::new(self, dynamic_offsets)
}
fn resources(&self) -> &DescriptorSetResources;
}
impl PartialEq for dyn DescriptorSet {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner()
}
}
impl Eq for dyn DescriptorSet {}
impl Hash for dyn DescriptorSet {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);
}
}
pub(crate) struct DescriptorSetInner {
layout: Arc<DescriptorSetLayout>,
resources: DescriptorSetResources,
}
impl DescriptorSetInner {
pub(crate) fn new(
handle: ash::vk::DescriptorSet,
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> Result<Self, DescriptorSetUpdateError> {
assert!(
!layout.push_descriptor(),
"the provided descriptor set layout is for push descriptors, and cannot be used to \
build a descriptor set object",
);
let max_count = layout.variable_descriptor_count();
assert!(
variable_descriptor_count <= max_count,
"the provided variable_descriptor_count ({}) is greater than the maximum number of \
variable count descriptors in the layout ({})",
variable_descriptor_count,
max_count,
);
let mut resources = DescriptorSetResources::new(&layout, variable_descriptor_count);
let descriptor_writes = descriptor_writes.into_iter();
let (lower_size_bound, _) = descriptor_writes.size_hint();
let mut descriptor_write_info: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
let mut write_descriptor_set: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
for write in descriptor_writes {
let layout_binding =
check_descriptor_write(&write, &layout, variable_descriptor_count)?;
resources.update(&write);
descriptor_write_info.push(write.to_vulkan_info(layout_binding.descriptor_type));
write_descriptor_set.push(write.to_vulkan(handle, layout_binding.descriptor_type));
}
if !write_descriptor_set.is_empty() {
for (info, write) in descriptor_write_info
.iter()
.zip(write_descriptor_set.iter_mut())
{
match info {
DescriptorWriteInfo::Image(info) => {
write.descriptor_count = info.len() as u32;
write.p_image_info = info.as_ptr();
}
DescriptorWriteInfo::Buffer(info) => {
write.descriptor_count = info.len() as u32;
write.p_buffer_info = info.as_ptr();
}
DescriptorWriteInfo::BufferView(info) => {
write.descriptor_count = info.len() as u32;
write.p_texel_buffer_view = info.as_ptr();
}
}
}
}
unsafe {
let fns = layout.device().fns();
(fns.v1_0.update_descriptor_sets)(
layout.device().handle(),
write_descriptor_set.len() as u32,
write_descriptor_set.as_ptr(),
0,
ptr::null(),
);
}
Ok(DescriptorSetInner { layout, resources })
}
pub(crate) fn layout(&self) -> &Arc<DescriptorSetLayout> {
&self.layout
}
pub(crate) fn resources(&self) -> &DescriptorSetResources {
&self.resources
}
}
#[derive(Clone)]
pub struct DescriptorSetResources {
binding_resources: HashMap<u32, DescriptorBindingResources>,
}
impl DescriptorSetResources {
#[inline]
pub fn new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self {
assert!(variable_descriptor_count <= layout.variable_descriptor_count());
let binding_resources = layout
.bindings()
.iter()
.map(|(&binding_num, binding)| {
let count = if binding.variable_descriptor_count {
variable_descriptor_count
} else {
binding.descriptor_count
} as usize;
let binding_resources = match binding.descriptor_type {
DescriptorType::UniformBuffer
| DescriptorType::StorageBuffer
| DescriptorType::UniformBufferDynamic
| DescriptorType::StorageBufferDynamic => {
DescriptorBindingResources::Buffer(smallvec![None; count])
}
DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer => {
DescriptorBindingResources::BufferView(smallvec![None; count])
}
DescriptorType::SampledImage
| DescriptorType::StorageImage
| DescriptorType::InputAttachment => {
DescriptorBindingResources::ImageView(smallvec![None; count])
}
DescriptorType::CombinedImageSampler => {
if binding.immutable_samplers.is_empty() {
DescriptorBindingResources::ImageViewSampler(smallvec![None; count])
} else {
DescriptorBindingResources::ImageView(smallvec![None; count])
}
}
DescriptorType::Sampler => {
if binding.immutable_samplers.is_empty() {
DescriptorBindingResources::Sampler(smallvec![None; count])
} else if layout.push_descriptor() {
DescriptorBindingResources::None(smallvec![None; count])
} else {
DescriptorBindingResources::None(smallvec![Some(()); count])
}
}
};
(binding_num, binding_resources)
})
.collect();
Self { binding_resources }
}
#[inline]
pub fn update(&mut self, write: &WriteDescriptorSet) {
self.binding_resources
.get_mut(&write.binding())
.expect("descriptor write has invalid binding number")
.update(write)
}
#[inline]
pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> {
self.binding_resources.get(&binding)
}
}
#[derive(Clone)]
pub enum DescriptorBindingResources {
None(Elements<()>),
Buffer(Elements<Arc<dyn BufferAccess>>),
BufferView(Elements<Arc<dyn BufferViewAbstract>>),
ImageView(Elements<Arc<dyn ImageViewAbstract>>),
ImageViewSampler(Elements<(Arc<dyn ImageViewAbstract>, Arc<Sampler>)>),
Sampler(Elements<Arc<Sampler>>),
}
type Elements<T> = SmallVec<[Option<T>; 1]>;
impl DescriptorBindingResources {
#[inline]
pub fn update(&mut self, write: &WriteDescriptorSet) {
fn write_resources<T: Clone>(first: usize, resources: &mut [Option<T>], elements: &[T]) {
resources
.get_mut(first..first + elements.len())
.expect("descriptor write for binding out of bounds")
.iter_mut()
.zip(elements)
.for_each(|(resource, element)| {
*resource = Some(element.clone());
});
}
let first = write.first_array_element() as usize;
match (self, write.elements()) {
(
DescriptorBindingResources::None(resources),
WriteDescriptorSetElements::None(num_elements),
) => {
resources
.get_mut(first..first + *num_elements as usize)
.expect("descriptor write for binding out of bounds")
.iter_mut()
.for_each(|resource| {
*resource = Some(());
});
}
(
DescriptorBindingResources::Buffer(resources),
WriteDescriptorSetElements::Buffer(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::BufferView(resources),
WriteDescriptorSetElements::BufferView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageView(resources),
WriteDescriptorSetElements::ImageView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageViewSampler(resources),
WriteDescriptorSetElements::ImageViewSampler(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::Sampler(resources),
WriteDescriptorSetElements::Sampler(elements),
) => write_resources(first, resources, elements),
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
}
}
}
#[derive(Clone)]
pub struct DescriptorSetWithOffsets {
descriptor_set: Arc<dyn DescriptorSet>,
dynamic_offsets: SmallVec<[u32; 4]>,
}
impl DescriptorSetWithOffsets {
pub fn new(
descriptor_set: Arc<dyn DescriptorSet>,
dynamic_offsets: impl IntoIterator<Item = u32>,
) -> Self {
let dynamic_offsets: SmallVec<_> = dynamic_offsets.into_iter().collect();
let layout = descriptor_set.layout();
let properties = layout.device().physical_device().properties();
let min_uniform_off_align = properties.min_uniform_buffer_offset_alignment as u32;
let min_storage_off_align = properties.min_storage_buffer_offset_alignment as u32;
let mut dynamic_offset_index = 0;
for binding in layout.bindings().values() {
match binding.descriptor_type {
DescriptorType::StorageBufferDynamic => {
if dynamic_offsets.len() > dynamic_offset_index {
assert!(
dynamic_offsets[dynamic_offset_index] % min_storage_off_align == 0,
"Dynamic storage buffer offset must be a multiple of \
min_storage_buffer_offset_alignment: got {}, expected a multiple of {}",
dynamic_offsets[dynamic_offset_index],
min_storage_off_align,
);
}
dynamic_offset_index += 1;
}
DescriptorType::UniformBufferDynamic => {
if dynamic_offsets.len() > dynamic_offset_index {
assert!(
dynamic_offsets[dynamic_offset_index] % min_uniform_off_align == 0,
"Dynamic uniform buffer offset must be a multiple of \
min_uniform_buffer_offset_alignment: got {}, expected a multiple of {}",
dynamic_offsets[dynamic_offset_index],
min_uniform_off_align,
);
}
dynamic_offset_index += 1;
}
_ => (),
}
}
assert!(
dynamic_offsets.len() >= dynamic_offset_index,
"Too few dynamic offsets: got {}, expected {}",
dynamic_offsets.len(),
dynamic_offset_index,
);
assert!(
dynamic_offsets.len() <= dynamic_offset_index,
"Too many dynamic offsets: got {}, expected {}",
dynamic_offsets.len(),
dynamic_offset_index,
);
DescriptorSetWithOffsets {
descriptor_set,
dynamic_offsets,
}
}
#[inline]
pub fn as_ref(&self) -> (&Arc<dyn DescriptorSet>, &[u32]) {
(&self.descriptor_set, &self.dynamic_offsets)
}
#[inline]
pub fn into_tuple(self) -> (Arc<dyn DescriptorSet>, impl ExactSizeIterator<Item = u32>) {
(self.descriptor_set, self.dynamic_offsets.into_iter())
}
}
impl<S> From<Arc<S>> for DescriptorSetWithOffsets
where
S: DescriptorSet + 'static,
{
fn from(descriptor_set: Arc<S>) -> Self {
DescriptorSetWithOffsets::new(descriptor_set, std::iter::empty())
}
}
#[derive(Clone, Copy, Debug)]
pub enum DescriptorSetCreationError {
DescriptorSetUpdateError(DescriptorSetUpdateError),
OomError(OomError),
}
impl Error for DescriptorSetCreationError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::DescriptorSetUpdateError(err) => Some(err),
Self::OomError(err) => Some(err),
}
}
}
impl Display for DescriptorSetCreationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::DescriptorSetUpdateError(_) => {
write!(f, "an error occurred while updating the descriptor set")
}
Self::OomError(_) => write!(f, "out of memory"),
}
}
}
impl From<DescriptorSetUpdateError> for DescriptorSetCreationError {
fn from(err: DescriptorSetUpdateError) -> Self {
Self::DescriptorSetUpdateError(err)
}
}
impl From<OomError> for DescriptorSetCreationError {
fn from(err: OomError) -> Self {
Self::OomError(err)
}
}