Rework DescriptorSetResources and DescriptorWrite (#1732)

* Rework `DescriptorSetResources` and `DescriptorWrite`

* Small fix

* Simplification in DescriptorWrite
This commit is contained in:
Rua 2021-10-26 18:11:43 +02:00 committed by GitHub
parent f7f5e42190
commit 520d15532b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 775 additions and 822 deletions

View File

@ -88,7 +88,7 @@ pub use self::traits::BufferInner;
pub use self::traits::TypedBufferAccess;
pub use self::usage::BufferUsage;
pub use self::view::BufferView;
pub use self::view::BufferViewRef;
pub use self::view::BufferViewAbstract;
pub mod cpu_access;
pub mod cpu_pool;

View File

@ -236,34 +236,42 @@ where
}
}
pub unsafe trait BufferViewRef {
type BufferAccess: BufferAccess;
pub unsafe trait BufferViewAbstract: Send + Sync {
/// Returns the inner handle used by this buffer view.
fn inner(&self) -> ash::vk::BufferView;
fn view(&self) -> &BufferView<Self::BufferAccess>;
/// Returns the wrapped buffer that this buffer view was created from.
fn buffer(&self) -> &dyn BufferAccess;
}
unsafe impl<B> BufferViewRef for BufferView<B>
unsafe impl<B> BufferViewAbstract for BufferView<B>
where
B: BufferAccess,
{
type BufferAccess = B;
#[inline]
fn inner(&self) -> ash::vk::BufferView {
self.handle
}
#[inline]
fn view(&self) -> &BufferView<B> {
self
fn buffer(&self) -> &dyn BufferAccess {
&self.buffer
}
}
unsafe impl<T, B> BufferViewRef for T
unsafe impl<T> BufferViewAbstract for T
where
T: SafeDeref<Target = BufferView<B>>,
B: BufferAccess,
T: SafeDeref + Send + Sync,
T::Target: BufferViewAbstract,
{
type BufferAccess = B;
#[inline]
fn inner(&self) -> ash::vk::BufferView {
(**self).inner()
}
#[inline]
fn view(&self) -> &BufferView<B> {
&**self
fn buffer(&self) -> &dyn BufferAccess {
(**self).buffer()
}
}

View File

@ -1172,32 +1172,32 @@ impl<'a> SetOrPush<'a> {
#[inline]
pub fn num_buffers(&self) -> usize {
match self {
Self::Set(set, offsets) => set.num_buffers(),
Self::Push(writes) => writes.resources().num_buffers(),
Self::Set(set, offsets) => set.resources().num_buffers(),
Self::Push(writes) => writes.num_buffers(),
}
}
#[inline]
pub fn buffer(&self, num: usize) -> Option<(&'a dyn BufferAccess, u32)> {
match *self {
Self::Set(set, offsets) => set.buffer(num),
Self::Push(writes) => writes.resources().buffer(num),
Self::Set(set, offsets) => set.resources().buffer(num),
Self::Push(writes) => writes.buffer(num),
}
}
#[inline]
pub fn num_images(&self) -> usize {
match self {
Self::Set(set, offsets) => set.num_images(),
Self::Push(writes) => writes.resources().num_images(),
Self::Set(set, offsets) => set.resources().num_images(),
Self::Push(writes) => writes.num_images(),
}
}
#[inline]
pub fn image(&self, num: usize) -> Option<(&'a dyn ImageViewAbstract, u32)> {
match *self {
Self::Set(set, offsets) => set.image(num),
Self::Push(writes) => writes.resources().image(num),
Self::Set(set, offsets) => set.resources().image(num),
Self::Push(writes) => writes.image(num),
}
}
}

View File

@ -18,6 +18,7 @@ use crate::command_buffer::CommandBufferUsage;
use crate::command_buffer::SecondaryCommandBuffer;
use crate::command_buffer::SubpassContents;
use crate::descriptor_set::sys::DescriptorWrite;
use crate::descriptor_set::sys::DescriptorWriteInfo;
use crate::descriptor_set::sys::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
@ -1372,21 +1373,51 @@ impl UnsafeCommandBufferBuilder {
return;
}
let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes
.into_iter()
.map(|write| {
let descriptor = pipeline_layout.descriptor_set_layouts()[set_num as usize]
.descriptor(write.binding_num)
.unwrap();
let descriptor_type = descriptor.ty.ty();
(
write.to_vulkan_info(descriptor_type),
write.to_vulkan(ash::vk::DescriptorSet::null(), descriptor_type),
)
})
.unzip();
// Set the info pointers separately.
for (info, write) in infos.iter().zip(writes.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();
}
}
debug_assert!(write.descriptor_count != 0);
}
let fns = self.device().fns();
let cmd = self.internal_object();
let raw_writes: SmallVec<[_; 8]> = descriptor_writes
.iter()
.map(|write| write.to_vulkan(ash::vk::DescriptorSet::null()))
.collect();
fns.khr_push_descriptor.cmd_push_descriptor_set_khr(
cmd,
pipeline_bind_point.into(),
pipeline_layout.internal_object(),
set_num,
raw_writes.len() as u32,
raw_writes.as_ptr(),
writes.len() as u32,
writes.as_ptr(),
);
}

View File

@ -7,14 +7,12 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::resources::DescriptorSetResources;
use super::DescriptorSetError;
use super::MissingBufferUsage;
use super::MissingImageUsage;
use crate::buffer::{BufferAccess, BufferView};
use crate::descriptor_set::layout::{DescriptorDesc, DescriptorDescImage, DescriptorDescTy};
use crate::descriptor_set::sys::DescriptorWrite;
use crate::descriptor_set::DescriptorSetLayout;
use crate::descriptor_set::sys::{DescriptorWrite, DescriptorWriteElements};
use crate::descriptor_set::{
DescriptorSetError, DescriptorSetLayout, MissingBufferUsage, MissingImageUsage,
};
use crate::device::{Device, DeviceOwned};
use crate::image::view::ImageViewType;
use crate::image::{ImageViewAbstract, SampleCount};
@ -33,8 +31,7 @@ pub struct DescriptorSetBuilder {
in_array: bool,
descriptors: Vec<BuilderDescriptor>,
cur_binding: u32,
resources: DescriptorSetResources,
desc_writes: Vec<DescriptorWrite>,
writes: Vec<DescriptorWrite>,
poisoned: bool,
}
@ -47,32 +44,10 @@ impl DescriptorSetBuilder {
pub fn start(layout: Arc<DescriptorSetLayout>) -> Self {
let mut descriptors = Vec::with_capacity(layout.num_bindings() as usize);
let mut desc_writes_capacity = 0;
let mut t_num_bufs = 0;
let mut t_num_imgs = 0;
let mut t_num_samplers = 0;
for binding_i in 0..layout.num_bindings() {
if let Some(desc) = layout.descriptor(binding_i) {
let descriptor_count = desc.descriptor_count as usize;
let (num_bufs, num_imgs, num_samplers) = match desc.ty {
DescriptorDescTy::Sampler { .. } => (0, 0, 1),
DescriptorDescTy::CombinedImageSampler { .. } => (0, 1, 1),
DescriptorDescTy::SampledImage { .. } => (0, 1, 0),
DescriptorDescTy::InputAttachment { .. } => (0, 1, 0),
DescriptorDescTy::StorageImage { .. } => (0, 1, 0),
DescriptorDescTy::UniformTexelBuffer { .. } => (1, 0, 0),
DescriptorDescTy::StorageTexelBuffer { .. } => (1, 0, 0),
DescriptorDescTy::UniformBuffer => (1, 0, 0),
DescriptorDescTy::StorageBuffer => (1, 0, 0),
DescriptorDescTy::UniformBufferDynamic => (1, 0, 0),
DescriptorDescTy::StorageBufferDynamic => (1, 0, 0),
};
t_num_bufs += num_bufs * descriptor_count;
t_num_imgs += num_imgs * descriptor_count;
t_num_samplers += num_samplers * descriptor_count;
desc_writes_capacity += descriptor_count;
desc_writes_capacity += desc.descriptor_count as usize;
descriptors.push(BuilderDescriptor {
desc: Some(desc),
array_element: 0,
@ -90,8 +65,7 @@ impl DescriptorSetBuilder {
in_array: false,
cur_binding: 0,
descriptors,
resources: DescriptorSetResources::new(t_num_bufs, t_num_imgs, t_num_samplers),
desc_writes: Vec::with_capacity(desc_writes_capacity),
writes: Vec::with_capacity(desc_writes_capacity),
poisoned: false,
}
}
@ -108,10 +82,38 @@ impl DescriptorSetBuilder {
obtained: self.cur_binding,
})
} else {
let mut buffers = Vec::new();
let mut images = Vec::new();
for (write_index, write) in self.writes.iter().enumerate() {
let first_array_element = write.first_array_element() as usize;
match write.elements() {
DescriptorWriteElements::Buffer(elements) => buffers.extend(
(first_array_element..first_array_element + elements.len())
.map(|element_index| (write_index, element_index)),
),
DescriptorWriteElements::BufferView(elements) => buffers.extend(
(first_array_element..first_array_element + elements.len())
.map(|element_index| (write_index, element_index)),
),
DescriptorWriteElements::ImageView(elements) => images.extend(
(first_array_element..first_array_element + elements.len())
.map(|element_index| (write_index, element_index)),
),
DescriptorWriteElements::ImageViewSampler(elements) => images.extend(
(first_array_element..first_array_element + elements.len())
.map(|element_index| (write_index, element_index)),
),
DescriptorWriteElements::Sampler(elements) => (),
}
}
Ok(DescriptorSetBuilderOutput {
layout: self.layout,
writes: self.desc_writes,
resources: self.resources,
writes: self.writes,
buffers,
images,
})
}
}
@ -242,7 +244,7 @@ impl DescriptorSetBuilder {
// enabled so this assert should never fail in practice, but we put it anyway
// in case we forget to adjust this code
builder.desc_writes.push(match inner_desc.ty {
match inner_desc.ty {
DescriptorDescTy::StorageBuffer | DescriptorDescTy::StorageBufferDynamic => {
assert!(
builder
@ -257,14 +259,6 @@ impl DescriptorSetBuilder {
MissingBufferUsage::StorageBuffer,
));
}
unsafe {
DescriptorWrite::storage_buffer(
builder.cur_binding,
descriptor.array_element,
[&buffer],
)
}
}
DescriptorDescTy::UniformBuffer => {
assert!(
@ -280,14 +274,6 @@ impl DescriptorSetBuilder {
MissingBufferUsage::UniformBuffer,
));
}
unsafe {
DescriptorWrite::uniform_buffer(
builder.cur_binding,
descriptor.array_element,
[&buffer],
)
}
}
DescriptorDescTy::UniformBufferDynamic => {
assert!(
@ -303,19 +289,18 @@ impl DescriptorSetBuilder {
MissingBufferUsage::UniformBuffer,
));
}
unsafe {
DescriptorWrite::dynamic_uniform_buffer(
builder.cur_binding,
descriptor.array_element,
[&buffer],
)
}
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
}
unsafe {
builder.writes.push(DescriptorWrite::buffer(
builder.cur_binding,
descriptor.array_element,
[buffer],
));
}
builder.resources.add_buffer(builder.cur_binding, buffer);
descriptor.array_element += 1;
if leave_array {
@ -352,7 +337,7 @@ impl DescriptorSetBuilder {
None => return Err(DescriptorSetError::WrongDescriptorType),
};
builder.desc_writes.push(match inner_desc.ty {
match inner_desc.ty {
DescriptorDescTy::StorageTexelBuffer { .. } => {
// TODO: storage_texel_buffer_atomic
@ -361,12 +346,6 @@ impl DescriptorSetBuilder {
MissingBufferUsage::StorageTexelBuffer,
));
}
DescriptorWrite::storage_texel_buffer(
builder.cur_binding,
descriptor.array_element,
[&*view],
)
}
DescriptorDescTy::UniformTexelBuffer { .. } => {
if !view.uniform_texel_buffer() {
@ -374,17 +353,18 @@ impl DescriptorSetBuilder {
MissingBufferUsage::UniformTexelBuffer,
));
}
DescriptorWrite::uniform_texel_buffer(
builder.cur_binding,
descriptor.array_element,
[&*view],
)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
}
unsafe {
builder.writes.push(DescriptorWrite::buffer_view(
builder.cur_binding,
descriptor.array_element,
[view as Arc<_>],
));
}
builder.resources.add_buffer_view(builder.cur_binding, view);
descriptor.array_element += 1;
if leave_array {
@ -420,7 +400,7 @@ impl DescriptorSetBuilder {
None => return Err(DescriptorSetError::WrongDescriptorType),
};
builder.desc_writes.push(match &inner_desc.ty {
match &inner_desc.ty {
DescriptorDescTy::CombinedImageSampler {
image_desc,
immutable_samplers,
@ -438,12 +418,6 @@ impl DescriptorSetBuilder {
}
image_match_desc(&image_view, image_desc)?;
DescriptorWrite::combined_image_sampler(
builder.cur_binding,
descriptor.array_element,
[(None, &image_view)],
)
}
DescriptorDescTy::SampledImage { ref image_desc, .. } => {
if !image_view.image().inner().image.usage().sampled {
@ -453,12 +427,6 @@ impl DescriptorSetBuilder {
}
image_match_desc(&image_view, image_desc)?;
DescriptorWrite::sampled_image(
builder.cur_binding,
descriptor.array_element,
[&image_view],
)
}
DescriptorDescTy::StorageImage { ref image_desc, .. } => {
if !image_view.image().inner().image.usage().storage {
@ -472,12 +440,6 @@ impl DescriptorSetBuilder {
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetError::NotIdentitySwizzled);
}
DescriptorWrite::storage_image(
builder.cur_binding,
descriptor.array_element,
[&image_view],
)
}
DescriptorDescTy::InputAttachment { multisampled } => {
if !image_view.image().inner().image.usage().input_attachment {
@ -503,18 +465,19 @@ impl DescriptorSetBuilder {
if image_view.ty().is_arrayed() {
return Err(DescriptorSetError::UnexpectedArrayed);
}
DescriptorWrite::input_attachment(
builder.cur_binding,
descriptor.array_element,
[&image_view],
)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
}
unsafe {
builder.writes.push(DescriptorWrite::image_view(
builder.cur_binding,
descriptor.array_element,
[image_view],
));
}
descriptor.array_element += 1;
builder.resources.add_image(builder.cur_binding, image_view);
if leave_array {
builder.leave_array()?;
@ -567,7 +530,7 @@ impl DescriptorSetBuilder {
None => return Err(DescriptorSetError::WrongDescriptorType),
};
builder.desc_writes.push(match &inner_desc.ty {
match &inner_desc.ty {
DescriptorDescTy::CombinedImageSampler {
image_desc,
immutable_samplers,
@ -577,19 +540,19 @@ impl DescriptorSetBuilder {
}
image_match_desc(&image_view, image_desc)?;
DescriptorWrite::combined_image_sampler(
builder.cur_binding,
descriptor.array_element,
[(Some(&sampler), &image_view)],
)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
}
unsafe {
builder.writes.push(DescriptorWrite::image_view_sampler(
builder.cur_binding,
descriptor.array_element,
[(image_view, sampler)],
));
}
descriptor.array_element += 1;
builder.resources.add_image(builder.cur_binding, image_view);
builder.resources.add_sampler(builder.cur_binding, sampler);
if leave_array {
builder.leave_array()?;
@ -619,23 +582,24 @@ impl DescriptorSetBuilder {
None => return Err(DescriptorSetError::WrongDescriptorType),
};
builder.desc_writes.push(match &inner_desc.ty {
match &inner_desc.ty {
DescriptorDescTy::Sampler { immutable_samplers } => {
if !immutable_samplers.is_empty() {
return Err(DescriptorSetError::SamplerIsImmutable);
}
DescriptorWrite::sampler(
builder.cur_binding,
descriptor.array_element,
[&sampler],
)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
}
unsafe {
builder.writes.push(DescriptorWrite::sampler(
builder.cur_binding,
descriptor.array_element,
[sampler],
));
}
descriptor.array_element += 1;
builder.resources.add_sampler(builder.cur_binding, sampler);
if leave_array {
builder.leave_array()?;
@ -658,7 +622,8 @@ unsafe impl DeviceOwned for DescriptorSetBuilder {
pub struct DescriptorSetBuilderOutput {
layout: Arc<DescriptorSetLayout>,
writes: Vec<DescriptorWrite>,
resources: DescriptorSetResources,
buffers: Vec<(usize, usize)>,
images: Vec<(usize, usize)>,
}
impl DescriptorSetBuilderOutput {
@ -668,29 +633,50 @@ impl DescriptorSetBuilderOutput {
&self.layout
}
/// Returns the resources used by the output.
#[inline]
pub fn resources(&self) -> &DescriptorSetResources {
&self.resources
}
/// Returns the descriptor writes.
#[inline]
pub fn writes(&self) -> &[DescriptorWrite] {
&self.writes
}
}
impl From<DescriptorSetBuilderOutput>
for (
Arc<DescriptorSetLayout>,
Vec<DescriptorWrite>,
DescriptorSetResources,
)
{
#[inline]
fn from(output: DescriptorSetBuilderOutput) -> Self {
(output.layout, output.writes, output.resources)
pub(crate) fn num_buffers(&self) -> usize {
self.buffers.len()
}
pub(crate) fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.buffers
.get(index)
.map(|&(write_index, element_index)| {
let write = &self.writes[write_index];
let buffer = match write.elements() {
DescriptorWriteElements::Buffer(elements) => elements[element_index].as_ref(),
DescriptorWriteElements::BufferView(elements) => {
elements[element_index].buffer()
}
_ => unreachable!(),
};
let binding_num = write.binding_num;
(buffer, binding_num)
})
}
pub(crate) fn num_images(&self) -> usize {
self.images.len()
}
pub(crate) fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
self.images.get(index).map(|&(write_index, element_index)| {
let write = &self.writes[write_index];
let image = match write.elements() {
DescriptorWriteElements::ImageView(elements) => elements[element_index].as_ref(),
DescriptorWriteElements::ImageViewSampler(elements) => {
elements[element_index].0.as_ref()
}
_ => unreachable!(),
};
let binding_num = write.binding_num;
(image, binding_num)
})
}
}

View File

@ -781,7 +781,7 @@ impl DescriptorDescTy {
}
#[inline]
pub(super) fn immutable_samplers(&self) -> &[Arc<Sampler>] {
pub(crate) fn immutable_samplers(&self) -> &[Arc<Sampler>] {
match self {
Self::Sampler {
immutable_samplers, ..

View File

@ -77,13 +77,13 @@ pub use self::builder::DescriptorSetBuilder;
pub use self::collection::DescriptorSetsCollection;
use self::layout::DescriptorSetLayout;
pub use self::persistent::PersistentDescriptorSet;
pub use self::resources::{DescriptorBindingResources, DescriptorSetResources};
pub use self::single_layout_pool::SingleLayoutDescSetPool;
use self::sys::UnsafeDescriptorSet;
use crate::buffer::BufferAccess;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::device::DeviceOwned;
use crate::format::Format;
use crate::image::view::ImageViewAbstract;
use crate::image::view::ImageViewType;
use crate::OomError;
use crate::SafeDeref;
@ -123,23 +123,8 @@ pub unsafe trait DescriptorSet: DeviceOwned + Send + Sync {
DescriptorSetWithOffsets::new(self, dynamic_offsets)
}
/// Returns the number of buffers within this descriptor set.
fn num_buffers(&self) -> usize;
/// Returns the `index`th buffer of this descriptor set, or `None` if out of range. Also
/// returns the index of the descriptor that uses this buffer.
///
/// The valid range is between 0 and `num_buffers()`.
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>;
/// Returns the number of images within this descriptor set.
fn num_images(&self) -> usize;
/// Returns the `index`th image of this descriptor set, or `None` if out of range. Also returns
/// the index of the descriptor that uses this image.
///
/// The valid range is between 0 and `num_images()`.
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>;
/// Returns the resources bound to this descriptor set.
fn resources(&self) -> &DescriptorSetResources;
}
unsafe impl<T> DescriptorSet for T
@ -158,23 +143,8 @@ where
}
#[inline]
fn num_buffers(&self) -> usize {
(**self).num_buffers()
}
#[inline]
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
(**self).buffer(index)
}
#[inline]
fn num_images(&self) -> usize {
(**self).num_images()
}
#[inline]
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
(**self).image(index)
fn resources(&self) -> &DescriptorSetResources {
(**self).resources()
}
}

View File

@ -21,24 +21,19 @@
//! # Example
//! TODO:
use super::builder::DescriptorSetBuilder;
use super::resources::DescriptorSetResources;
use super::DescriptorSetError;
use crate::buffer::BufferView;
use crate::descriptor_set::builder::DescriptorSetBuilder;
use crate::descriptor_set::pool::standard::StdDescriptorPoolAlloc;
use crate::descriptor_set::pool::DescriptorPool;
use crate::descriptor_set::pool::DescriptorPoolAlloc;
use crate::descriptor_set::BufferAccess;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::DescriptorSetLayout;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::descriptor_set::pool::{DescriptorPool, DescriptorPoolAlloc};
use crate::descriptor_set::resources::DescriptorSetResources;
use crate::descriptor_set::{
BufferAccess, DescriptorSet, DescriptorSetError, DescriptorSetLayout, UnsafeDescriptorSet,
};
use crate::device::{Device, DeviceOwned};
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::VulkanObject;
use std::hash::Hash;
use std::hash::Hasher;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
/// A simple, immutable descriptor set that is expected to be long-lived.
@ -77,27 +72,15 @@ where
}
#[inline]
fn num_buffers(&self) -> usize {
self.resources.num_buffers()
}
#[inline]
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.resources.buffer(index)
}
#[inline]
fn num_images(&self) -> usize {
self.resources.num_images()
}
#[inline]
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
self.resources.image(index)
fn resources(&self) -> &DescriptorSetResources {
&self.resources
}
}
unsafe impl<P> DeviceOwned for PersistentDescriptorSet<P> {
unsafe impl<P> DeviceOwned for PersistentDescriptorSet<P>
where
P: DescriptorPoolAlloc,
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.layout.device()
@ -245,17 +228,19 @@ impl PersistentDescriptorSetBuilder {
where
P: ?Sized + DescriptorPool,
{
let (layout, writes, resources) = self.inner.build()?.into();
let writes = self.inner.build()?;
let set = unsafe {
let mut set = pool.alloc(&layout)?;
set.inner_mut().write(pool.device(), &writes);
let mut set = pool.alloc(writes.layout())?;
set.inner_mut().write(writes.layout(), writes.writes());
set
};
let mut resources = DescriptorSetResources::new(writes.layout());
resources.update(writes.writes());
Ok(PersistentDescriptorSet {
inner: set,
resources,
layout,
layout: writes.layout().clone(),
})
}
}

View File

@ -148,7 +148,6 @@ impl UnsafeDescriptorPool {
/// - You must ensure that the allocated descriptor sets are no longer in use when the pool
/// is destroyed, as destroying the pool is equivalent to freeing all the sets.
///
#[inline]
pub unsafe fn alloc<'l, I>(
&mut self,
layouts: I,
@ -172,16 +171,6 @@ impl UnsafeDescriptorPool {
layout.internal_object()
})
.collect();
self.alloc_impl(&layouts, &variable_descriptor_counts)
}
// Actual implementation of `alloc`. Separated so that it is not inlined.
unsafe fn alloc_impl(
&mut self,
layouts: &SmallVec<[ash::vk::DescriptorSetLayout; 8]>,
variable_descriptor_counts: &SmallVec<[u32; 8]>,
) -> Result<impl ExactSizeIterator<Item = UnsafeDescriptorSet>, DescriptorPoolAllocError> {
let num = layouts.len();
let output = if num == 0 {
@ -242,7 +231,9 @@ impl UnsafeDescriptorPool {
output
};
Ok(output.into_iter().map(|s| UnsafeDescriptorSet { set: s }))
Ok(output
.into_iter()
.map(|handle| UnsafeDescriptorSet::new(handle)))
}
/// Frees some descriptor sets.
@ -435,7 +426,7 @@ mod tests {
let mut pool = UnsafeDescriptorPool::new(device, &desc, 10, false).unwrap();
unsafe {
let sets = pool.alloc(iter::once(&set_layout)).unwrap();
let sets = pool.alloc([&set_layout]).unwrap();
assert_eq!(sets.count(), 1);
}
}
@ -469,7 +460,7 @@ mod tests {
let mut pool = UnsafeDescriptorPool::new(device2, &desc, 10, false).unwrap();
unsafe {
let _ = pool.alloc(iter::once(&set_layout));
let _ = pool.alloc([&set_layout]);
}
}
);

View File

@ -7,116 +7,225 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::BufferInner;
use crate::buffer::BufferView;
use crate::buffer::BufferViewAbstract;
use crate::descriptor_set::layout::{DescriptorSetLayout, DescriptorType};
use crate::descriptor_set::sys::{DescriptorWrite, DescriptorWriteElements};
use crate::descriptor_set::BufferAccess;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::sync::AccessError;
use crate::DeviceSize;
use fnv::FnvHashMap;
use smallvec::{smallvec, SmallVec};
use std::sync::Arc;
/// The resources that are bound to a descriptor set.
#[derive(Clone)]
pub struct DescriptorSetResources {
buffers: Vec<(Arc<dyn BufferAccess + 'static>, u32)>,
images: Vec<(Arc<dyn ImageViewAbstract + 'static>, u32)>,
samplers: Vec<(Arc<Sampler>, u32)>,
}
struct BufferViewResource<B>(Arc<BufferView<B>>)
where
B: BufferAccess;
unsafe impl<B> DeviceOwned for BufferViewResource<B>
where
B: BufferAccess,
{
fn device(&self) -> &Arc<Device> {
self.0.device()
}
}
unsafe impl<B> BufferAccess for BufferViewResource<B>
where
B: BufferAccess,
{
fn inner(&self) -> BufferInner<'_> {
self.0.buffer().inner()
}
fn size(&self) -> DeviceSize {
self.0.buffer().size()
}
fn conflict_key(&self) -> (u64, u64) {
self.0.buffer().conflict_key()
}
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
self.0.buffer().try_gpu_lock(exclusive_access, queue)
}
unsafe fn increase_gpu_lock(&self) {
self.0.buffer().increase_gpu_lock()
}
unsafe fn unlock(&self) {
self.0.buffer().unlock()
}
descriptors: FnvHashMap<u32, DescriptorBindingResources>,
buffers: Vec<(u32, usize)>,
images: Vec<(u32, usize)>,
}
impl DescriptorSetResources {
pub fn new(buffer_capacity: usize, image_capacity: usize, sampler_capacity: usize) -> Self {
/// Creates a new `DescriptorSetResources` matching the provided descriptor set layout, and
/// all descriptors set to `None`.
pub fn new(layout: &DescriptorSetLayout) -> Self {
let descriptors = layout
.desc()
.bindings()
.iter()
.enumerate()
.filter_map(|(b, d)| d.as_ref().map(|d| (b as u32, d)))
.map(|(binding_num, binding_desc)| {
let count = binding_desc.descriptor_count as usize;
let binding_resources = match binding_desc.ty.ty() {
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_desc.ty.immutable_samplers().is_empty() {
DescriptorBindingResources::ImageViewSampler(smallvec![None; count])
} else {
DescriptorBindingResources::ImageView(smallvec![None; count])
}
}
DescriptorType::Sampler => {
if binding_desc.ty.immutable_samplers().is_empty() {
DescriptorBindingResources::Sampler(smallvec![None; count])
} else {
DescriptorBindingResources::None
}
}
};
(binding_num, binding_resources)
})
.collect();
Self {
buffers: Vec::with_capacity(buffer_capacity),
images: Vec::with_capacity(image_capacity),
samplers: Vec::with_capacity(sampler_capacity),
descriptors,
buffers: Vec::new(),
images: Vec::new(),
}
}
pub fn num_buffers(&self) -> usize {
/// Applies descriptor writes to the resources.
///
/// # Panics
///
/// - Panics if the binding number of a write does not exist in the resources.
/// - See also [`DescriptorBindingResources::update`].
pub fn update<'a>(&mut self, writes: impl IntoIterator<Item = &'a DescriptorWrite>) {
for write in writes {
self.descriptors
.get_mut(&write.binding_num)
.expect("descriptor write has invalid binding number")
.update(write)
}
self.buffers.clear();
self.images.clear();
for (&binding, resources) in self.descriptors.iter() {
match resources {
DescriptorBindingResources::None => (),
DescriptorBindingResources::Buffer(resources) => {
self.buffers.extend(resources.iter().enumerate().filter_map(
|(index, resource)| resource.as_ref().map(|_| (binding, index)),
))
}
DescriptorBindingResources::BufferView(resources) => {
self.buffers.extend(resources.iter().enumerate().filter_map(
|(index, resource)| resource.as_ref().map(|_| (binding, index)),
))
}
DescriptorBindingResources::ImageView(resources) => {
self.images.extend(resources.iter().enumerate().filter_map(
|(index, resource)| resource.as_ref().map(|_| (binding, index)),
))
}
DescriptorBindingResources::ImageViewSampler(resources) => {
self.images.extend(resources.iter().enumerate().filter_map(
|(index, resource)| resource.as_ref().map(|_| (binding, index)),
))
}
DescriptorBindingResources::Sampler(_) => (),
}
}
}
/// Returns a reference to the bound resources for `binding`. Returns `None` if the binding
/// doesn't exist.
#[inline]
pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> {
self.descriptors.get(&binding)
}
pub(crate) fn num_buffers(&self) -> usize {
self.buffers.len()
}
pub fn num_images(&self) -> usize {
pub(crate) fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.buffers
.get(index)
.and_then(|&(binding, index)| match &self.descriptors[&binding] {
DescriptorBindingResources::Buffer(resources) => {
resources[index].as_ref().map(|r| (r.as_ref(), binding))
}
DescriptorBindingResources::BufferView(resources) => {
resources[index].as_ref().map(|r| (r.buffer(), binding))
}
_ => unreachable!(),
})
}
pub(crate) fn num_images(&self) -> usize {
self.images.len()
}
pub fn num_samplers(&self) -> usize {
self.samplers.len()
}
pub fn add_buffer(&mut self, desc_index: u32, buffer: Arc<dyn BufferAccess + 'static>) {
self.buffers.push((buffer, desc_index));
}
pub fn add_buffer_view<B>(&mut self, desc_index: u32, view: Arc<BufferView<B>>)
where
B: BufferAccess + 'static,
{
self.buffers
.push((Arc::new(BufferViewResource(view)), desc_index));
}
pub fn add_image(&mut self, desc_index: u32, image: Arc<dyn ImageViewAbstract + 'static>) {
self.images.push((image, desc_index));
}
pub fn add_sampler(&mut self, desc_index: u32, sampler: Arc<Sampler>) {
self.samplers.push((sampler, desc_index))
}
pub fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.buffers
.get(index)
.map(|(buf, bind)| (&**buf as _, *bind))
}
pub fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
pub(crate) fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
self.images
.get(index)
.map(|(img, bind)| (&**img as _, *bind))
.and_then(|&(binding, index)| match &self.descriptors[&binding] {
DescriptorBindingResources::ImageView(resources) => {
resources[index].as_ref().map(|r| (r.as_ref(), binding))
}
DescriptorBindingResources::ImageViewSampler(resources) => {
resources[index].as_ref().map(|r| (r.0.as_ref(), binding))
}
_ => unreachable!(),
})
}
}
/// The resources that are bound to a single descriptor set binding.
#[derive(Clone)]
pub enum DescriptorBindingResources {
None,
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 {
/// Applies a descriptor write to the resources.
///
/// # Panics
///
/// - Panics if the resource types do not match.
/// - Panics if the write goes out of bounds.
pub fn update(&mut self, write: &DescriptorWrite) {
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::Buffer(resources),
DescriptorWriteElements::Buffer(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::BufferView(resources),
DescriptorWriteElements::BufferView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageView(resources),
DescriptorWriteElements::ImageView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageViewSampler(resources),
DescriptorWriteElements::ImageViewSampler(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::Sampler(resources),
DescriptorWriteElements::Sampler(elements),
) => write_resources(first, resources, elements),
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding_num,
),
}
}
}

View File

@ -7,26 +7,21 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::builder::DescriptorSetBuilder;
use super::resources::DescriptorSetResources;
use super::DescriptorSetError;
use crate::buffer::BufferView;
use crate::descriptor_set::builder::DescriptorSetBuilder;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorPoolAlloc;
use crate::descriptor_set::pool::DescriptorPoolAllocError;
use crate::descriptor_set::pool::UnsafeDescriptorPool;
use crate::descriptor_set::BufferAccess;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::descriptor_set::pool::{
DescriptorPoolAlloc, DescriptorPoolAllocError, UnsafeDescriptorPool,
};
use crate::descriptor_set::{BufferAccess, DescriptorSet, DescriptorSetError, UnsafeDescriptorSet};
use crate::device::{Device, DeviceOwned};
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::OomError;
use crate::VulkanObject;
use crossbeam_queue::SegQueue;
use std::hash::Hash;
use std::hash::Hasher;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
/// `SingleLayoutDescSetPool` is a convenience wrapper provided by Vulkano not to be confused with
@ -191,23 +186,8 @@ unsafe impl DescriptorSet for SingleLayoutDescSet {
}
#[inline]
fn num_buffers(&self) -> usize {
self.resources.num_buffers()
}
#[inline]
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.resources.buffer(index)
}
#[inline]
fn num_images(&self) -> usize {
self.resources.num_images()
}
#[inline]
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
self.resources.image(index)
fn resources(&self) -> &DescriptorSetResources {
&self.resources
}
}
@ -339,16 +319,18 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
/// Builds a `SingleLayoutDescSet` from the builder.
pub fn build(self) -> Result<SingleLayoutDescSet, DescriptorSetError> {
let (layout, writes, resources) = self.inner.build()?.into();
let writes = self.inner.build()?;
let mut alloc = self.pool.next_alloc()?;
unsafe {
alloc.inner_mut().write(&self.pool.device, &writes);
alloc.inner_mut().write(writes.layout(), writes.writes());
}
let mut resources = DescriptorSetResources::new(writes.layout());
resources.update(writes.writes());
Ok(SingleLayoutDescSet {
inner: alloc,
resources,
layout,
layout: writes.layout().clone(),
})
}
}

View File

@ -9,11 +9,8 @@
//! Low-level descriptor set.
use crate::buffer::BufferAccess;
use crate::buffer::BufferInner;
use crate::buffer::BufferView;
use crate::descriptor_set::layout::DescriptorType;
use crate::device::Device;
use crate::buffer::{BufferAccess, BufferInner, BufferViewAbstract};
use crate::descriptor_set::layout::{DescriptorSetLayout, DescriptorType};
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::sampler::Sampler;
@ -30,52 +27,83 @@ use std::sync::Arc;
/// doesn't hold the pool or the device it is associated to.
/// Instead it is an object meant to be used with the `UnsafeDescriptorPool`.
pub struct UnsafeDescriptorSet {
pub(super) set: ash::vk::DescriptorSet,
handle: ash::vk::DescriptorSet,
}
impl UnsafeDescriptorSet {
// TODO: add copying from other descriptor sets
// add a `copy` method that just takes a copy, and an `update` method that takes both
// writes and copies and that actually performs the operation
pub(crate) fn new(handle: ash::vk::DescriptorSet) -> Self {
Self { handle }
}
/// Modifies a descriptor set. Doesn't check that the writes or copies are correct, and
/// doesn't check whether the descriptor set is in use.
///
/// **Important**: You must ensure that the `DescriptorSetLayout` object is alive before
/// updating a descriptor set.
///
/// # Safety
///
/// - The `Device` must be the device the pool of this set was created with.
/// - The `DescriptorSetLayout` object this set was created with must be alive.
/// - Doesn't verify that the things you write in the descriptor set match its layout.
/// - Doesn't keep the resources alive. You have to do that yourself.
/// - Updating a descriptor set obeys synchronization rules that aren't checked here. Once a
/// command buffer contains a pointer/reference to a descriptor set, it is illegal to write
/// to it.
///
pub unsafe fn write(&mut self, device: &Device, writes: &[DescriptorWrite]) {
let fns = device.fns();
pub unsafe fn write<'a>(
&mut self,
layout: &DescriptorSetLayout,
writes: impl IntoIterator<Item = &'a DescriptorWrite>,
) {
let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = writes
.into_iter()
.map(|write| {
let descriptor_type = layout.descriptor(write.binding_num).unwrap().ty.ty();
let raw_writes: SmallVec<[_; 8]> = writes
.iter()
.map(|write| write.to_vulkan(self.set))
.collect();
(
write.to_vulkan_info(descriptor_type),
write.to_vulkan(self.handle, descriptor_type),
)
})
.unzip();
// It is forbidden to call `vkUpdateDescriptorSets` with 0 writes, so we need to perform
// this emptiness check.
if raw_writes.is_empty() {
if writes.is_empty() {
return;
}
// Set the info pointers separately.
for (info, write) in infos.iter().zip(writes.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();
}
}
debug_assert!(write.descriptor_count != 0);
}
let fns = layout.device().fns();
fns.v1_0.update_descriptor_sets(
device.internal_object(),
raw_writes.len() as u32,
raw_writes.as_ptr(),
layout.device().internal_object(),
writes.len() as u32,
writes.as_ptr(),
0,
ptr::null(),
);
}
// TODO: add copying from other descriptor sets
// add a `copy` method that just takes a copy, and an `update` method that takes both
// writes and copies and that actually performs the operation
}
unsafe impl VulkanObject for UnsafeDescriptorSet {
@ -83,13 +111,13 @@ unsafe impl VulkanObject for UnsafeDescriptorSet {
#[inline]
fn internal_object(&self) -> ash::vk::DescriptorSet {
self.set
self.handle
}
}
impl fmt::Debug for UnsafeDescriptorSet {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan descriptor set {:?}>", self.set)
write!(fmt, "<Vulkan descriptor set {:?}>", self.handle)
}
}
@ -98,442 +126,288 @@ impl fmt::Debug for UnsafeDescriptorSet {
/// Use the various constructors to build a `DescriptorWrite`. While it is safe to build a
/// `DescriptorWrite`, it is unsafe to actually use it to write to a descriptor set.
pub struct DescriptorWrite {
binding: u32,
pub(crate) binding_num: u32,
first_array_element: u32,
descriptor_type: DescriptorType,
info: DescriptorWriteInfo,
elements: DescriptorWriteElements,
}
impl DescriptorWrite {
#[inline]
pub unsafe fn buffer(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn BufferAccess>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::Buffer(elements),
}
}
#[inline]
pub unsafe fn buffer_view(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn BufferViewAbstract>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::BufferView(elements),
}
}
#[inline]
pub unsafe fn image_view(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn ImageViewAbstract>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::ImageView(elements),
}
}
#[inline]
pub unsafe fn image_view_sampler(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = (Arc<dyn ImageViewAbstract>, Arc<Sampler>)>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::ImageViewSampler(elements),
}
}
#[inline]
pub unsafe fn sampler(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<Sampler>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::Sampler(elements),
}
}
/// Returns the binding number that is updated by this descriptor write.
#[inline]
pub fn binding_num(&self) -> u32 {
self.binding_num
}
/// Returns the first array element in the binding that is updated by this descriptor write.
#[inline]
pub fn first_array_element(&self) -> u32 {
self.first_array_element
}
/// Returns a reference to the elements held by this descriptor write.
#[inline]
pub fn elements(&self) -> &DescriptorWriteElements {
&self.elements
}
pub(crate) fn to_vulkan_info(&self, descriptor_type: DescriptorType) -> DescriptorWriteInfo {
match &self.elements {
DescriptorWriteElements::Buffer(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::UniformBuffer
| DescriptorType::StorageBuffer
| DescriptorType::UniformBufferDynamic
| DescriptorType::StorageBufferDynamic
));
DescriptorWriteInfo::Buffer(
elements
.iter()
.map(|buffer| {
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_storage_buffer_offset_alignment,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_storage_buffer_range
as DeviceSize
);
ash::vk::DescriptorBufferInfo {
buffer: buffer.internal_object(),
offset,
range: size,
}
})
.collect(),
)
}
DescriptorWriteElements::BufferView(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer
));
DescriptorWriteInfo::BufferView(
elements
.iter()
.map(|buffer_view| buffer_view.inner())
.collect(),
)
}
DescriptorWriteElements::ImageView(elements) => {
// Note: combined image sampler can occur with immutable samplers
debug_assert!(matches!(
descriptor_type,
DescriptorType::CombinedImageSampler
| DescriptorType::SampledImage
| DescriptorType::StorageImage
| DescriptorType::InputAttachment
));
DescriptorWriteInfo::Image(
elements
.iter()
.map(|image_view| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.layout_for(descriptor_type).into(),
}
})
.collect(),
)
}
DescriptorWriteElements::ImageViewSampler(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::CombinedImageSampler
));
DescriptorWriteInfo::Image(
elements
.iter()
.map(|(image_view, sampler)| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: sampler.internal_object(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.layout_for(descriptor_type).into(),
}
})
.collect(),
)
}
DescriptorWriteElements::Sampler(elements) => {
debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
DescriptorWriteInfo::Image(
elements
.iter()
.map(|sampler| ash::vk::DescriptorImageInfo {
sampler: sampler.internal_object(),
image_view: ash::vk::ImageView::null(),
image_layout: ash::vk::ImageLayout::UNDEFINED,
})
.collect(),
)
}
}
}
pub(crate) fn to_vulkan(
&self,
dst_set: ash::vk::DescriptorSet,
descriptor_type: DescriptorType,
) -> ash::vk::WriteDescriptorSet {
ash::vk::WriteDescriptorSet {
dst_set,
dst_binding: self.binding_num,
dst_array_element: self.first_array_element,
descriptor_count: 0,
descriptor_type: descriptor_type.into(),
p_image_info: ptr::null(),
p_buffer_info: ptr::null(),
p_texel_buffer_view: ptr::null(),
..Default::default()
}
}
}
/// The elements held by a descriptor write.
pub enum DescriptorWriteElements {
Buffer(SmallVec<[Arc<dyn BufferAccess>; 1]>),
BufferView(SmallVec<[Arc<dyn BufferViewAbstract>; 1]>),
ImageView(SmallVec<[Arc<dyn ImageViewAbstract>; 1]>),
ImageViewSampler(SmallVec<[(Arc<dyn ImageViewAbstract>, Arc<Sampler>); 1]>),
Sampler(SmallVec<[Arc<Sampler>; 1]>),
}
impl DescriptorWriteElements {
/// Returns the number of elements.
#[inline]
pub fn len(&self) -> u32 {
match self {
DescriptorWriteElements::Buffer(elements) => elements.len() as u32,
DescriptorWriteElements::BufferView(elements) => elements.len() as u32,
DescriptorWriteElements::ImageView(elements) => elements.len() as u32,
DescriptorWriteElements::ImageViewSampler(elements) => elements.len() as u32,
DescriptorWriteElements::Sampler(elements) => elements.len() as u32,
}
}
}
#[derive(Clone, Debug)]
enum DescriptorWriteInfo {
pub(crate) enum DescriptorWriteInfo {
Image(SmallVec<[ash::vk::DescriptorImageInfo; 1]>),
Buffer(SmallVec<[ash::vk::DescriptorBufferInfo; 1]>),
BufferView(SmallVec<[ash::vk::BufferView; 1]>),
}
impl DescriptorWrite {
#[inline]
pub fn storage_image<'a, I>(
binding: u32,
first_array_element: u32,
image_views: impl IntoIterator<Item = &'a I>,
) -> DescriptorWrite
where
I: ImageViewAbstract + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::StorageImage,
info: DescriptorWriteInfo::Image(
image_views
.into_iter()
.map(|image_view| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.storage_image.into(),
}
})
.collect(),
),
}
}
#[inline]
pub fn sampler<'a>(
binding: u32,
first_array_element: u32,
samplers: impl IntoIterator<Item = &'a Arc<Sampler>>,
) -> DescriptorWrite {
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::Sampler,
info: DescriptorWriteInfo::Image(
samplers
.into_iter()
.map(|sampler| ash::vk::DescriptorImageInfo {
sampler: sampler.internal_object(),
image_view: ash::vk::ImageView::null(),
image_layout: ash::vk::ImageLayout::UNDEFINED,
})
.collect(),
),
}
}
#[inline]
pub fn sampled_image<'a, I>(
binding: u32,
first_array_element: u32,
image_views: impl IntoIterator<Item = &'a I>,
) -> DescriptorWrite
where
I: ImageViewAbstract + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::SampledImage,
info: DescriptorWriteInfo::Image(
image_views
.into_iter()
.map(|image_view| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.sampled_image.into(),
}
})
.collect(),
),
}
}
#[inline]
pub fn combined_image_sampler<'a, I>(
binding: u32,
first_array_element: u32,
image_views_samplers: impl IntoIterator<Item = (Option<&'a Arc<Sampler>>, &'a I)>, // Some for dynamic sampler, None for immutable
) -> DescriptorWrite
where
I: ImageViewAbstract + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::CombinedImageSampler,
info: DescriptorWriteInfo::Image(
image_views_samplers
.into_iter()
.map(|(sampler, image_view)| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: sampler.map(|s| s.internal_object()).unwrap_or_default(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.combined_image_sampler.into(),
}
})
.collect(),
),
}
}
#[inline]
pub fn uniform_texel_buffer<'a, B>(
binding: u32,
first_array_element: u32,
buffer_views: impl IntoIterator<Item = &'a BufferView<B>>,
) -> DescriptorWrite
where
B: BufferAccess + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::UniformTexelBuffer,
info: DescriptorWriteInfo::BufferView(
buffer_views
.into_iter()
.map(|buffer_view| {
assert!(buffer_view.uniform_texel_buffer());
buffer_view.internal_object()
})
.collect(),
),
}
}
#[inline]
pub fn storage_texel_buffer<'a, B>(
binding: u32,
first_array_element: u32,
buffer_view: impl IntoIterator<Item = &'a BufferView<B>>,
) -> DescriptorWrite
where
B: BufferAccess + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::StorageTexelBuffer,
info: DescriptorWriteInfo::BufferView(
buffer_view
.into_iter()
.map(|buffer_view| {
assert!(buffer_view.storage_texel_buffer());
buffer_view.internal_object()
})
.collect(),
),
}
}
#[inline]
pub unsafe fn uniform_buffer<'a, B>(
binding: u32,
first_array_element: u32,
buffers: impl IntoIterator<Item = &'a B>,
) -> DescriptorWrite
where
B: BufferAccess + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::UniformBuffer,
info: DescriptorWriteInfo::Buffer(
buffers
.into_iter()
.map(|buffer| {
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_uniform_buffer_offset_alignment,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_uniform_buffer_range
as DeviceSize
);
ash::vk::DescriptorBufferInfo {
buffer: buffer.internal_object(),
offset,
range: size,
}
})
.collect(),
),
}
}
#[inline]
pub unsafe fn storage_buffer<'a, B>(
binding: u32,
first_array_element: u32,
buffers: impl IntoIterator<Item = &'a B>,
) -> DescriptorWrite
where
B: BufferAccess + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::StorageBuffer,
info: DescriptorWriteInfo::Buffer(
buffers
.into_iter()
.map(|buffer| {
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_storage_buffer_offset_alignment,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_storage_buffer_range
as DeviceSize
);
ash::vk::DescriptorBufferInfo {
buffer: buffer.internal_object(),
offset,
range: size,
}
})
.collect(),
),
}
}
#[inline]
pub unsafe fn dynamic_uniform_buffer<'a, B>(
binding: u32,
first_array_element: u32,
buffers: impl IntoIterator<Item = &'a B>,
) -> DescriptorWrite
where
B: BufferAccess + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::UniformBufferDynamic,
info: DescriptorWriteInfo::Buffer(
buffers
.into_iter()
.map(|buffer| {
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_uniform_buffer_offset_alignment,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_uniform_buffer_range
as DeviceSize
);
ash::vk::DescriptorBufferInfo {
buffer: buffer.internal_object(),
offset,
range: size,
}
})
.collect(),
),
}
}
#[inline]
pub unsafe fn dynamic_storage_buffer<'a, B>(
binding: u32,
first_array_element: u32,
buffers: impl IntoIterator<Item = &'a B>,
) -> DescriptorWrite
where
B: BufferAccess + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::StorageBufferDynamic,
info: DescriptorWriteInfo::Buffer(
buffers
.into_iter()
.map(|buffer| {
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_storage_buffer_offset_alignment,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_storage_buffer_range
as DeviceSize
);
ash::vk::DescriptorBufferInfo {
buffer: buffer.internal_object(),
offset,
range: size,
}
})
.collect(),
),
}
}
#[inline]
pub fn input_attachment<'a, I>(
binding: u32,
first_array_element: u32,
image_views: impl IntoIterator<Item = &'a I>,
) -> DescriptorWrite
where
I: ImageViewAbstract + 'a,
{
DescriptorWrite {
binding,
first_array_element,
descriptor_type: DescriptorType::InputAttachment,
info: DescriptorWriteInfo::Image(
image_views
.into_iter()
.map(|image_view| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.input_attachment.into(),
}
})
.collect(),
),
}
}
pub(crate) fn to_vulkan(&self, dst_set: ash::vk::DescriptorSet) -> ash::vk::WriteDescriptorSet {
let mut result = ash::vk::WriteDescriptorSet {
dst_set,
dst_binding: self.binding,
dst_array_element: self.first_array_element,
descriptor_count: 0,
descriptor_type: self.descriptor_type.into(),
p_image_info: ptr::null(),
p_buffer_info: ptr::null(),
p_texel_buffer_view: ptr::null(),
..Default::default()
};
// Set the pointers separately.
// You must keep `*self` alive and unmoved until the function call is done.
match &self.info {
impl DescriptorWriteInfo {
fn set_info(&self, write: &mut ash::vk::WriteDescriptorSet) {
match self {
DescriptorWriteInfo::Image(info) => {
result.descriptor_count = info.len() as u32;
result.p_image_info = info.as_ptr();
write.descriptor_count = info.len() as u32;
write.p_image_info = info.as_ptr();
}
DescriptorWriteInfo::Buffer(info) => {
result.descriptor_count = info.len() as u32;
result.p_buffer_info = info.as_ptr();
write.descriptor_count = info.len() as u32;
write.p_buffer_info = info.as_ptr();
}
DescriptorWriteInfo::BufferView(info) => {
result.descriptor_count = info.len() as u32;
result.p_texel_buffer_view = info.as_ptr();
write.descriptor_count = info.len() as u32;
write.p_texel_buffer_view = info.as_ptr();
}
}
// Since the `DescriptorWrite` objects are built only through functions, we know for
// sure that it's impossible to have an empty descriptor write.
debug_assert!(result.descriptor_count != 0);
result
debug_assert!(write.descriptor_count != 0);
}
}

View File

@ -7,6 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::descriptor_set::layout::DescriptorType;
/// Layout of an image.
///
/// > **Note**: In vulkano, image layouts are mostly a low-level detail. You can ignore them,
@ -58,3 +60,18 @@ pub struct ImageDescriptorLayouts {
/// The image layout to use in a descriptor as an input attachment.
pub input_attachment: ImageLayout,
}
impl ImageDescriptorLayouts {
/// Returns the layout for the given descriptor type. Panics if `descriptor_type` is not an
/// image descriptor type.
#[inline]
pub fn layout_for(&self, descriptor_type: DescriptorType) -> ImageLayout {
match descriptor_type {
DescriptorType::CombinedImageSampler => self.combined_image_sampler,
DescriptorType::SampledImage => self.sampled_image,
DescriptorType::StorageImage => self.storage_image,
DescriptorType::InputAttachment => self.input_attachment,
_ => panic!("{:?} is not an image descriptor type", descriptor_type),
}
}
}