use std::sync::Arc;
use ash::vk;
use crate::{image::*, Buffer, CommandBuffer, Device, Error, Pipeline, ImageLayout};
pub use vk::DescriptorType;
pub use vk::ShaderStageFlags as ShaderStage;
#[derive(thiserror::Error, Debug)]
pub enum DescriptorError {
#[error("The number of provided dynamic offsets is not equal the number of bound dynamic descriptors. Provided {actual} dynamic offsets, but expected {expected}")]
DynamicOffsetOutOfBounds {
actual: usize,
expected: usize,
},
}
pub struct PoolSize {
pub ty: DescriptorType,
pub count: u32,
}
pub struct DescriptorPoolBuilder {
sizes: Vec<PoolSize>,
max_sets: Option<u32>,
}
impl Default for DescriptorPoolBuilder {
fn default() -> Self {
Self {
sizes: vec![],
max_sets: None,
}
}
}
impl DescriptorPoolBuilder {
pub fn add_size(&mut self, ty: DescriptorType, count: u32) -> &mut Self {
self.sizes.push(PoolSize { ty, count });
self
}
pub fn max_sets(&mut self, max_sets: u32) -> &mut Self {
self.max_sets = Some(max_sets);
self
}
pub fn build(&self, device: &Arc<Device>) -> Result<DescriptorPool, Error> {
let max_sets = self
.max_sets
.unwrap_or(self.sizes.iter().map(|size| size.count).sum());
DescriptorPool::new(device, &self.sizes, max_sets)
}
}
pub struct DescriptorPool {
device: Arc<Device>,
pool: vk::DescriptorPool,
}
impl Drop for DescriptorPool {
fn drop(&mut self) {
unsafe {
self.device.destroy_descriptor_pool(self.pool, None);
}
}
}
impl DescriptorPool {
pub fn new(device: &Arc<Device>, sizes: &[PoolSize], max_sets: u32) -> Result<Self, Error> {
let pool_sizes = sizes
.iter()
.map(|size| {
*vk::DescriptorPoolSize::builder()
.ty(size.ty)
.descriptor_count(size.count)
})
.collect::<Vec<_>>();
let pool_info = vk::DescriptorPoolCreateInfo::builder()
.pool_sizes(&pool_sizes)
.max_sets(max_sets);
let pool = unsafe { device.create_descriptor_pool(&pool_info, None)? };
Ok(Self {
device: Arc::clone(&device),
pool,
})
}
pub fn builder() -> DescriptorPoolBuilder {
DescriptorPoolBuilder::default()
}
}
pub struct LayoutBinding {
pub binding: u32,
pub ty: DescriptorType,
pub stage: ShaderStage,
pub count: u32,
}
pub struct DescriptorSetLayout {
device: Arc<Device>,
pub(crate) layout: vk::DescriptorSetLayout,
}
impl Drop for DescriptorSetLayout {
fn drop(&mut self) {
unsafe {
self.device.destroy_descriptor_set_layout(self.layout, None);
}
}
}
impl DescriptorSetLayout {
pub fn new(device: &Arc<Device>, bindings: &[LayoutBinding]) -> Result<Self, Error> {
let bindings = bindings
.iter()
.map(|binding| {
*vk::DescriptorSetLayoutBinding::builder()
.binding(binding.binding)
.descriptor_type(binding.ty)
.descriptor_count(binding.count)
.stage_flags(binding.stage)
})
.collect::<Vec<_>>();
let layout_info = vk::DescriptorSetLayoutCreateInfo::builder().bindings(&bindings);
let layout = unsafe { device.create_descriptor_set_layout(&layout_info, None)? };
Ok(Self {
device: Arc::clone(&device),
layout,
})
}
}
enum WriteDescriptor {
Buffer {
binding: u32,
ty: DescriptorType,
info: [vk::DescriptorBufferInfo; 1],
alignment: usize,
},
Image {
binding: u32,
ty: DescriptorType,
info: [vk::DescriptorImageInfo; 1],
},
}
pub struct DescriptorAllocator {
device: Arc<Device>,
writes: Vec<WriteDescriptor>,
}
impl DescriptorAllocator {
pub fn new(device: &Arc<Device>) -> Self {
Self {
device: Arc::clone(&device),
writes: vec![],
}
}
pub fn add_buffer_binding<T>(
&mut self,
binding: u32,
ty: DescriptorType,
buffer: &Buffer<T>,
) -> &mut Self {
self.add_buffer_index_binding(binding, 0, buffer.instance_count, ty, buffer)
}
pub fn add_buffer_index_binding<T>(
&mut self,
binding: u32,
index: usize,
instance_count: usize,
ty: DescriptorType,
buffer: &Buffer<T>,
) -> &mut Self {
let info = [buffer.descriptor_info(index, instance_count)];
let write = WriteDescriptor::Buffer {
binding,
ty,
info,
alignment: buffer.alignment_size,
};
self.writes.push(write);
self
}
pub fn add_image_binding(
&mut self,
binding: u32,
ty: DescriptorType,
image: &Image,
sampler: &Sampler,
layout: ImageLayout,
) -> &mut Self {
let info = [image.descriptor_info(sampler, layout)];
let write = WriteDescriptor::Image {
binding,
ty,
info,
};
self.writes.push(write);
self
}
pub fn allocate(
&mut self,
layout: &DescriptorSetLayout,
pool: &DescriptorPool,
) -> Result<DescriptorSet, Error> {
let layouts = [layout.layout];
let alloc_info = vk::DescriptorSetAllocateInfo::builder()
.descriptor_pool(pool.pool)
.set_layouts(&layouts);
let set = unsafe { self.device.allocate_descriptor_sets(&alloc_info)?[0] };
let mut dynamic_sizes = vec![];
let writes = self
.writes
.iter_mut()
.map(|write| match write {
WriteDescriptor::Buffer { binding, ty, info, alignment } => {
if (*ty == DescriptorType::UNIFORM_BUFFER_DYNAMIC) || (*ty == DescriptorType::STORAGE_BUFFER_DYNAMIC) {
dynamic_sizes.push(*alignment as u32);
}
*vk::WriteDescriptorSet::builder()
.dst_set(set)
.dst_binding(*binding)
.descriptor_type(*ty)
.dst_array_element(0)
.buffer_info(info)
}
WriteDescriptor::Image { binding, ty, info } => {
*vk::WriteDescriptorSet::builder()
.dst_set(set)
.dst_binding(*binding)
.descriptor_type(*ty)
.dst_array_element(0)
.image_info(info)
}
})
.collect::<Vec<_>>();
unsafe { self.device.update_descriptor_sets(&writes, &[]) };
Ok(DescriptorSet {
device: Arc::clone(&self.device),
set,
dynamic_sizes,
})
}
}
pub struct DescriptorSet {
device: Arc<Device>,
set: vk::DescriptorSet,
dynamic_sizes: Vec<u32>,
}
impl DescriptorSet {
pub fn bind(&self, cmd_buffer: &CommandBuffer, pipeline: &Pipeline, first_set: u32, dynamic_offsets: &[u32]) -> Result<(), Error> {
if dynamic_offsets.len() != self.dynamic_sizes.len() {
return Err(DescriptorError::DynamicOffsetOutOfBounds { actual: dynamic_offsets.len(), expected: self.dynamic_sizes.len() }.into())
}
let dynamic_offsets = self.dynamic_sizes.iter()
.enumerate()
.map(|(i, s)| s * dynamic_offsets[i])
.collect::<Vec<_>>();
unsafe {
self.device.cmd_bind_descriptor_sets(
**cmd_buffer,
vk::PipelineBindPoint::GRAPHICS,
pipeline.layout,
first_set,
&[self.set],
&dynamic_offsets,
)
};
Ok(())
}
}