Skip to content

Commit

Permalink
add DescriptorSet::invalidate()
Browse files Browse the repository at this point in the history
  • Loading branch information
Firestar99 committed Apr 20, 2024
1 parent 2052dde commit de2c4e3
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 2 deletions.
90 changes: 88 additions & 2 deletions vulkano/src/descriptor_set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ pub use self::{
use crate::{
acceleration_structure::AccelerationStructure,
buffer::view::BufferView,
descriptor_set::layout::{
DescriptorBindingFlags, DescriptorSetLayoutCreateFlags, DescriptorType,
descriptor_set::{
layout::{DescriptorBindingFlags, DescriptorSetLayoutCreateFlags, DescriptorType},
update::InvalidateDescriptorSet,
},
device::{Device, DeviceOwned},
image::{sampler::Sampler, ImageLayout},
Expand Down Expand Up @@ -295,6 +296,42 @@ impl DescriptorSet {
resources.copy(copy);
}
}

/// Invalidates descriptors within a descriptor set. Doesn't actually call into vulkan and only
/// invalidates the descriptors inside vulkano's resource tracking. Invalidated descriptors are
/// equivalent to uninitialized descriptors, in that binding a descriptor set to a particular
/// pipeline requires all shader-accessible descriptors to be valid.
///
/// The intended use-case is an update-after-bind or bindless system, where entries in an
/// arrayed binding have to be invalidated so that the backing resource will be freed, and
/// not stay forever referenced until overridden by some update.
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 {
Expand Down Expand Up @@ -444,6 +481,14 @@ impl DescriptorSetResources {
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)
}
}

/// The resources that are bound to a single descriptor set binding.
Expand Down Expand Up @@ -633,6 +678,47 @@ impl DescriptorBindingResources {
},
}
}

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)]
Expand Down
92 changes: 92 additions & 0 deletions vulkano/src/descriptor_set/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,8 @@ pub struct CopyDescriptorSet {
pub dst_binding: u32,

/// The first array element in the destination descriptor set to copy into.
///
/// The default value is 0.
pub dst_first_array_element: u32,

/// The number of descriptors (array elements) to copy.
Expand Down Expand Up @@ -1832,3 +1834,93 @@ impl CopyDescriptorSet {
Ok(())
}
}

/// Invalidates descriptors within a descriptor set. Doesn't actually call into vulkan and only
/// invalidates the descriptors inside vulkano's resource tracking. Invalidated descriptors are
/// equivalent to uninitialized descriptors, in that binding a descriptor set to a particular
/// pipeline requires all shader-accessible descriptors to be valid.
///
/// The intended use-case is an update-after-bind or bindless system, where entries in an arrayed
/// binding have to be invalidated so that the backing resource will be freed, and not stay forever
/// referenced until overridden by some update.
pub struct InvalidateDescriptorSet {
/// The binding number in the descriptor set to invalidate.
///
/// The default value is 0.
pub binding: u32,

/// The first array element in the descriptor set to invalidate.
///
/// The default value is 0.
pub first_array_element: u32,

/// The number of descriptors (array elements) to invalidate.
///
/// The default value is 1.
pub descriptor_count: u32,

pub _ne: crate::NonExhaustive,
}

impl InvalidateDescriptorSet {
pub fn invalidate(binding: u32) -> Self {
Self::invalidate_array(binding, 0, 1)
}

pub fn invalidate_array(binding: u32, first_array_element: u32, descriptor_count: u32) -> Self {
Self {
binding,
first_array_element,
descriptor_count,
_ne: crate::NonExhaustive(()),
}
}

pub(crate) fn validate(
&self,
layout: &DescriptorSetLayout,
variable_descriptor_count: u32,
) -> Result<(), Box<ValidationError>> {
let &Self {
binding,
first_array_element,
descriptor_count,
..
} = self;

let layout_binding = match layout.bindings().get(&binding) {
Some(layout_binding) => layout_binding,
None => {
return Err(Box::new(ValidationError {
context: "binding".into(),
problem: "does not exist in the descriptor set layout".into(),
vuids: &["VUID-VkWriteDescriptorSet-dstBinding-00315"],
..Default::default()
}));
}
};

debug_assert!(descriptor_count != 0);
let max_descriptor_count = if layout_binding
.binding_flags
.intersects(DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT)
{
variable_descriptor_count
} else {
layout_binding.descriptor_count
};

// VUID-VkWriteDescriptorSet-dstArrayElement-00321
if first_array_element + descriptor_count > max_descriptor_count {
return Err(Box::new(ValidationError {
problem: "`first_array_element` + the number of provided elements is greater than \
the number of descriptors in the descriptor set binding"
.into(),
vuids: &["VUID-VkWriteDescriptorSet-dstArrayElement-00321"],
..Default::default()
}));
}

Ok(())
}
}

0 comments on commit de2c4e3

Please sign in to comment.