blob: 656f767c440d77ac367d60881b042ed61a21ab46 [file] [log] [blame]
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::check_errors;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorSetDesc;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::OomError;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
#[derive(Debug)]
pub struct DescriptorSetLayout {
// The layout.
handle: ash::vk::DescriptorSetLayout,
// The device this layout belongs to.
device: Arc<Device>,
// Descriptors.
desc: DescriptorSetDesc,
// Number of descriptors.
descriptors_count: DescriptorsCount,
}
impl DescriptorSetLayout {
/// Builds a new `DescriptorSetLayout` with the given descriptors.
///
/// The descriptors must be passed in the order of the bindings. In order words, descriptor
/// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
/// empty, you can make the iterator yield `None` for an element.
pub fn new<D>(device: Arc<Device>, desc: D) -> Result<DescriptorSetLayout, OomError>
where
D: Into<DescriptorSetDesc>,
{
let desc = desc.into();
let mut descriptors_count = DescriptorsCount::zero();
let bindings = desc
.bindings()
.iter()
.enumerate()
.filter_map(|(binding, desc)| {
let desc = match desc {
Some(d) => d,
None => return None,
};
// FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
// doesn't have tess shaders enabled
let ty = desc.ty.ty();
descriptors_count.add_num(ty, desc.array_count);
Some(ash::vk::DescriptorSetLayoutBinding {
binding: binding as u32,
descriptor_type: ty.into(),
descriptor_count: desc.array_count,
stage_flags: desc.stages.into(),
p_immutable_samplers: ptr::null(), // FIXME: not yet implemented
})
})
.collect::<SmallVec<[_; 32]>>();
// Note that it seems legal to have no descriptor at all in the set.
let handle = unsafe {
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
binding_count: bindings.len() as u32,
p_bindings: bindings.as_ptr(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = device.fns();
check_errors(fns.v1_0.create_descriptor_set_layout(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(DescriptorSetLayout {
handle,
device,
desc,
descriptors_count,
})
}
pub(crate) fn desc(&self) -> &DescriptorSetDesc {
&self.desc
}
/// Returns the number of descriptors of each type.
#[inline]
pub fn descriptors_count(&self) -> &DescriptorsCount {
&self.descriptors_count
}
/// Returns the number of binding slots in the set.
#[inline]
pub fn num_bindings(&self) -> usize {
self.desc.bindings().len()
}
/// Returns a description of a descriptor, or `None` if out of range.
#[inline]
pub fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
self.desc.bindings().get(binding).cloned().unwrap_or(None)
}
}
unsafe impl DeviceOwned for DescriptorSetLayout {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl VulkanObject for DescriptorSetLayout {
type Object = ash::vk::DescriptorSetLayout;
#[inline]
fn internal_object(&self) -> ash::vk::DescriptorSetLayout {
self.handle
}
}
impl Drop for DescriptorSetLayout {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
fns.v1_0.destroy_descriptor_set_layout(
self.device.internal_object(),
self.handle,
ptr::null(),
);
}
}
}
#[cfg(test)]
mod tests {
use crate::descriptor_set::layout::DescriptorBufferDesc;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::layout::DescriptorSetDesc;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::pipeline::shader::ShaderStages;
use std::iter;
#[test]
fn empty() {
let (device, _) = gfx_dev_and_queue!();
let _layout = DescriptorSetLayout::new(device, DescriptorSetDesc::empty());
}
#[test]
fn basic_create() {
let (device, _) = gfx_dev_and_queue!();
let layout = DescriptorDesc {
ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
dynamic: Some(false),
storage: false,
}),
array_count: 1,
stages: ShaderStages::all_graphics(),
readonly: true,
};
let sl = DescriptorSetLayout::new(
device.clone(),
DescriptorSetDesc::new(iter::once(Some(layout))),
)
.unwrap();
assert_eq!(
sl.descriptors_count(),
&DescriptorsCount {
uniform_buffer: 1,
..DescriptorsCount::zero()
}
);
}
}