use self::{
allocator::DescriptorSetAllocator,
layout::DescriptorSetLayout,
pool::{DescriptorPool, DescriptorPoolAlloc},
sys::RawDescriptorSet,
};
pub use self::{
collection::DescriptorSetsCollection,
update::{
CopyDescriptorSet, DescriptorBufferInfo, DescriptorImageViewInfo, InvalidateDescriptorSet,
WriteDescriptorSet, WriteDescriptorSetElements,
},
};
use crate::{
acceleration_structure::AccelerationStructure,
buffer::view::BufferView,
descriptor_set::layout::{
DescriptorBindingFlags, DescriptorSetLayoutCreateFlags, DescriptorType,
},
device::{Device, DeviceOwned},
image::{sampler::Sampler, ImageLayout},
Validated, ValidationError, VulkanError, VulkanObject,
};
use foldhash::HashMap;
use parking_lot::{RwLock, RwLockReadGuard};
use smallvec::{smallvec, SmallVec};
use std::{
hash::{Hash, Hasher},
sync::Arc,
};
pub mod allocator;
mod collection;
pub mod layout;
pub mod pool;
pub mod sys;
mod update;
#[derive(Debug)]
pub struct DescriptorSet {
inner: RawDescriptorSet,
resources: RwLock<DescriptorSetResources>,
}
impl DescriptorSet {
pub fn new(
allocator: Arc<dyn DescriptorSetAllocator>,
layout: Arc<DescriptorSetLayout>,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
descriptor_copies: impl IntoIterator<Item = CopyDescriptorSet>,
) -> Result<Arc<DescriptorSet>, Validated<VulkanError>> {
Self::new_variable(allocator, layout, 0, descriptor_writes, descriptor_copies)
}
pub fn new_variable(
allocator: Arc<dyn DescriptorSetAllocator>,
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
descriptor_copies: impl IntoIterator<Item = CopyDescriptorSet>,
) -> Result<Arc<DescriptorSet>, Validated<VulkanError>> {
let mut set = DescriptorSet {
inner: RawDescriptorSet::new(allocator, &layout, variable_descriptor_count)?,
resources: RwLock::new(DescriptorSetResources::new(
&layout,
variable_descriptor_count,
)),
};
set.update(descriptor_writes, descriptor_copies)?;
Ok(Arc::new(set))
}
#[inline]
pub fn as_raw(&self) -> &RawDescriptorSet {
&self.inner
}
#[inline]
pub fn alloc(&self) -> &DescriptorPoolAlloc {
&self.inner.alloc().inner
}
#[inline]
pub fn pool(&self) -> &DescriptorPool {
self.inner.pool()
}
#[inline]
pub fn layout(&self) -> &Arc<DescriptorSetLayout> {
self.alloc().layout()
}
#[inline]
pub fn variable_descriptor_count(&self) -> u32 {
self.alloc().variable_descriptor_count()
}
pub fn offsets(
self: Arc<Self>,
dynamic_offsets: impl IntoIterator<Item = u32>,
) -> DescriptorSetWithOffsets {
DescriptorSetWithOffsets::new(self, dynamic_offsets)
}
#[inline]
pub fn resources(&self) -> RwLockReadGuard<'_, DescriptorSetResources> {
self.resources.read()
}
pub fn update(
&mut self,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
descriptor_copies: impl IntoIterator<Item = CopyDescriptorSet>,
) -> Result<(), Box<ValidationError>> {
let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
let descriptor_copies: SmallVec<[_; 8]> = descriptor_copies.into_iter().collect();
if descriptor_writes.is_empty() && descriptor_copies.is_empty() {
return Ok(());
}
self.inner
.validate_update(&descriptor_writes, &descriptor_copies)?;
unsafe {
Self::update_inner(
&self.inner,
self.resources.get_mut(),
&descriptor_writes,
&descriptor_copies,
)
};
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn update_unchecked(
&mut self,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
descriptor_copies: impl IntoIterator<Item = CopyDescriptorSet>,
) {
let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
let descriptor_copies: SmallVec<[_; 8]> = descriptor_copies.into_iter().collect();
if descriptor_writes.is_empty() && descriptor_copies.is_empty() {
return;
}
unsafe {
Self::update_inner(
&self.inner,
self.resources.get_mut(),
&descriptor_writes,
&descriptor_copies,
)
};
}
pub unsafe fn update_by_ref(
&self,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
descriptor_copies: impl IntoIterator<Item = CopyDescriptorSet>,
) -> Result<(), Box<ValidationError>> {
let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
let descriptor_copies: SmallVec<[_; 8]> = descriptor_copies.into_iter().collect();
if descriptor_writes.is_empty() && descriptor_copies.is_empty() {
return Ok(());
}
self.inner
.validate_update(&descriptor_writes, &descriptor_copies)?;
unsafe {
Self::update_inner(
&self.inner,
&mut self.resources.write(),
&descriptor_writes,
&descriptor_copies,
)
};
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn update_by_ref_unchecked(
&self,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
descriptor_copies: impl IntoIterator<Item = CopyDescriptorSet>,
) {
let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
let descriptor_copies: SmallVec<[_; 8]> = descriptor_copies.into_iter().collect();
if descriptor_writes.is_empty() && descriptor_copies.is_empty() {
return;
}
unsafe {
Self::update_inner(
&self.inner,
&mut self.resources.write(),
&descriptor_writes,
&descriptor_copies,
)
};
}
unsafe fn update_inner(
inner: &RawDescriptorSet,
resources: &mut DescriptorSetResources,
descriptor_writes: &[WriteDescriptorSet],
descriptor_copies: &[CopyDescriptorSet],
) {
unsafe { inner.update_unchecked(descriptor_writes, descriptor_copies) };
for write in descriptor_writes {
resources.write(write, inner.layout());
}
for copy in descriptor_copies {
resources.copy(copy);
}
}
pub fn invalidate(
&self,
descriptor_invalidates: &[InvalidateDescriptorSet],
) -> Result<(), Box<ValidationError>> {
self.validate_invalidate(descriptor_invalidates)?;
self.invalidate_unchecked(descriptor_invalidates);
Ok(())
}
pub fn invalidate_unchecked(&self, descriptor_invalidates: &[InvalidateDescriptorSet]) {
let mut resources = self.resources.write();
for invalidate in descriptor_invalidates {
resources.invalidate(invalidate);
}
}
pub(super) fn validate_invalidate(
&self,
descriptor_invalidates: &[InvalidateDescriptorSet],
) -> Result<(), Box<ValidationError>> {
for (index, write) in descriptor_invalidates.iter().enumerate() {
write
.validate(self.layout(), self.variable_descriptor_count())
.map_err(|err| err.add_context(format!("descriptor_writes[{}]", index)))?;
}
Ok(())
}
}
unsafe impl VulkanObject for DescriptorSet {
type Handle = ash::vk::DescriptorSet;
#[inline]
fn handle(&self) -> Self::Handle {
self.inner.handle()
}
}
unsafe impl DeviceOwned for DescriptorSet {
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
impl PartialEq for DescriptorSet {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl Eq for DescriptorSet {}
impl Hash for DescriptorSet {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
#[derive(Clone, Debug)]
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
.binding_flags
.intersects(DescriptorBindingFlags::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
.flags()
.intersects(DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR)
{
DescriptorBindingResources::None(smallvec![None; count])
} else {
DescriptorBindingResources::None(smallvec![Some(()); count])
}
}
DescriptorType::InlineUniformBlock => {
DescriptorBindingResources::InlineUniformBlock
}
DescriptorType::AccelerationStructure => {
DescriptorBindingResources::AccelerationStructure(smallvec![None; count])
}
};
(binding_num, binding_resources)
})
.collect();
Self { binding_resources }
}
#[inline]
pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> {
self.binding_resources.get(&binding)
}
#[inline]
pub(crate) fn write(&mut self, write: &WriteDescriptorSet, layout: &DescriptorSetLayout) {
let descriptor_type = layout
.bindings()
.get(&write.binding())
.expect("descriptor write has invalid binding number")
.descriptor_type;
self.binding_resources
.get_mut(&write.binding())
.expect("descriptor write has invalid binding number")
.write(write, descriptor_type)
}
#[inline]
pub(crate) fn copy(&mut self, copy: &CopyDescriptorSet) {
let resources = copy.src_set.resources();
let src = resources
.binding_resources
.get(©.src_binding)
.expect("descriptor copy has invalid src_binding number");
self.binding_resources
.get_mut(©.dst_binding)
.expect("descriptor copy has invalid dst_binding number")
.copy(
src,
copy.src_first_array_element,
copy.dst_first_array_element,
copy.descriptor_count,
);
}
#[inline]
pub(crate) fn invalidate(&mut self, invalidate: &InvalidateDescriptorSet) {
self.binding_resources
.get_mut(&invalidate.binding)
.expect("descriptor write has invalid binding number")
.invalidate(invalidate)
}
}
#[derive(Clone, Debug)]
pub enum DescriptorBindingResources {
None(Elements<()>),
Buffer(Elements<DescriptorBufferInfo>),
BufferView(Elements<Arc<BufferView>>),
ImageView(Elements<DescriptorImageViewInfo>),
ImageViewSampler(Elements<(DescriptorImageViewInfo, Arc<Sampler>)>),
Sampler(Elements<Arc<Sampler>>),
InlineUniformBlock,
AccelerationStructure(Elements<Arc<AccelerationStructure>>),
}
type Elements<T> = SmallVec<[Option<T>; 1]>;
impl DescriptorBindingResources {
pub(crate) fn write(&mut self, write: &WriteDescriptorSet, descriptor_type: DescriptorType) {
fn write_resources<T: Clone>(
first: usize,
resources: &mut [Option<T>],
elements: &[T],
element_func: impl Fn(&T) -> 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_func(element));
});
}
let default_image_layout = descriptor_type.default_image_layout();
let first = write.first_array_element() as usize;
match write.elements() {
WriteDescriptorSetElements::None(num_elements) => match self {
DescriptorBindingResources::None(resources) => {
resources
.get_mut(first..first + *num_elements as usize)
.expect("descriptor write for binding out of bounds")
.iter_mut()
.for_each(|resource| {
*resource = Some(());
});
}
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
WriteDescriptorSetElements::Buffer(elements) => match self {
DescriptorBindingResources::Buffer(resources) => {
write_resources(first, resources, elements, Clone::clone)
}
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
WriteDescriptorSetElements::BufferView(elements) => match self {
DescriptorBindingResources::BufferView(resources) => {
write_resources(first, resources, elements, Clone::clone)
}
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
WriteDescriptorSetElements::ImageView(elements) => match self {
DescriptorBindingResources::ImageView(resources) => {
write_resources(first, resources, elements, |element| {
let mut element = element.clone();
if element.image_layout == ImageLayout::Undefined {
element.image_layout = default_image_layout;
}
element
})
}
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
WriteDescriptorSetElements::ImageViewSampler(elements) => match self {
DescriptorBindingResources::ImageViewSampler(resources) => {
write_resources(first, resources, elements, |element| {
let mut element = element.clone();
if element.0.image_layout == ImageLayout::Undefined {
element.0.image_layout = default_image_layout;
}
element
})
}
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
WriteDescriptorSetElements::Sampler(elements) => match self {
DescriptorBindingResources::Sampler(resources) => {
write_resources(first, resources, elements, Clone::clone)
}
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
WriteDescriptorSetElements::InlineUniformBlock(_) => match self {
DescriptorBindingResources::InlineUniformBlock => (),
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
WriteDescriptorSetElements::AccelerationStructure(elements) => match self {
DescriptorBindingResources::AccelerationStructure(resources) => {
write_resources(first, resources, elements, Clone::clone)
}
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
},
}
}
pub(crate) fn copy(
&mut self,
src: &DescriptorBindingResources,
src_start: u32,
dst_start: u32,
count: u32,
) {
let src_start = src_start as usize;
let dst_start = dst_start as usize;
let count = count as usize;
match src {
DescriptorBindingResources::None(src) => match self {
DescriptorBindingResources::None(dst) => dst[dst_start..dst_start + count]
.clone_from_slice(&src[src_start..src_start + count]),
_ => panic!("descriptor copy has wrong resource type"),
},
DescriptorBindingResources::Buffer(src) => match self {
DescriptorBindingResources::Buffer(dst) => dst[dst_start..dst_start + count]
.clone_from_slice(&src[src_start..src_start + count]),
_ => panic!("descriptor copy has wrong resource type"),
},
DescriptorBindingResources::BufferView(src) => match self {
DescriptorBindingResources::BufferView(dst) => dst[dst_start..dst_start + count]
.clone_from_slice(&src[src_start..src_start + count]),
_ => panic!("descriptor copy has wrong resource type"),
},
DescriptorBindingResources::ImageView(src) => match self {
DescriptorBindingResources::ImageView(dst) => dst[dst_start..dst_start + count]
.clone_from_slice(&src[src_start..src_start + count]),
_ => panic!("descriptor copy has wrong resource type"),
},
DescriptorBindingResources::ImageViewSampler(src) => match self {
DescriptorBindingResources::ImageViewSampler(dst) => dst
[dst_start..dst_start + count]
.clone_from_slice(&src[src_start..src_start + count]),
_ => panic!("descriptor copy has wrong resource type"),
},
DescriptorBindingResources::Sampler(src) => match self {
DescriptorBindingResources::Sampler(dst) => dst[dst_start..dst_start + count]
.clone_from_slice(&src[src_start..src_start + count]),
_ => panic!("descriptor copy has wrong resource type"),
},
DescriptorBindingResources::InlineUniformBlock => match self {
DescriptorBindingResources::InlineUniformBlock => (),
_ => panic!("descriptor copy has wrong resource type"),
},
DescriptorBindingResources::AccelerationStructure(src) => match self {
DescriptorBindingResources::AccelerationStructure(dst) => dst
[dst_start..dst_start + count]
.clone_from_slice(&src[src_start..src_start + count]),
_ => panic!("descriptor copy has wrong resource type"),
},
}
}
pub(crate) fn invalidate(&mut self, invalidate: &InvalidateDescriptorSet) {
fn invalidate_resources<T: Clone>(
resources: &mut [Option<T>],
invalidate: &InvalidateDescriptorSet,
) {
let first = invalidate.first_array_element as usize;
resources
.get_mut(first..first + invalidate.descriptor_count as usize)
.expect("descriptor write for binding out of bounds")
.iter_mut()
.for_each(|resource| {
*resource = None;
});
}
match self {
DescriptorBindingResources::None(resources) => {
invalidate_resources(resources, invalidate)
}
DescriptorBindingResources::Buffer(resources) => {
invalidate_resources(resources, invalidate)
}
DescriptorBindingResources::BufferView(resources) => {
invalidate_resources(resources, invalidate)
}
DescriptorBindingResources::ImageView(resources) => {
invalidate_resources(resources, invalidate)
}
DescriptorBindingResources::ImageViewSampler(resources) => {
invalidate_resources(resources, invalidate)
}
DescriptorBindingResources::Sampler(resources) => {
invalidate_resources(resources, invalidate)
}
DescriptorBindingResources::InlineUniformBlock => (),
DescriptorBindingResources::AccelerationStructure(resources) => {
invalidate_resources(resources, invalidate)
}
}
}
}
#[derive(Clone)]
pub struct DescriptorSetWithOffsets {
descriptor_set: Arc<DescriptorSet>,
dynamic_offsets: SmallVec<[u32; 4]>,
}
impl DescriptorSetWithOffsets {
pub fn new(
descriptor_set: Arc<DescriptorSet>,
dynamic_offsets: impl IntoIterator<Item = u32>,
) -> Self {
Self {
descriptor_set,
dynamic_offsets: dynamic_offsets.into_iter().collect(),
}
}
#[inline]
pub fn as_ref(&self) -> (&Arc<DescriptorSet>, &[u32]) {
(&self.descriptor_set, &self.dynamic_offsets)
}
#[inline]
pub fn into_tuple(self) -> (Arc<DescriptorSet>, impl ExactSizeIterator<Item = u32>) {
(self.descriptor_set, self.dynamic_offsets.into_iter())
}
}
impl From<Arc<DescriptorSet>> for DescriptorSetWithOffsets {
#[inline]
fn from(descriptor_set: Arc<DescriptorSet>) -> Self {
DescriptorSetWithOffsets::new(descriptor_set, std::iter::empty())
}
}