aboutsummaryrefslogtreecommitdiff
path: root/src/descriptor_set/sys.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/descriptor_set/sys.rs')
-rw-r--r--src/descriptor_set/sys.rs588
1 files changed, 588 insertions, 0 deletions
diff --git a/src/descriptor_set/sys.rs b/src/descriptor_set/sys.rs
new file mode 100644
index 0000000..d1c7cc1
--- /dev/null
+++ b/src/descriptor_set/sys.rs
@@ -0,0 +1,588 @@
+// 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.
+
+//! 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::device::DeviceOwned;
+use crate::image::view::ImageViewAbstract;
+use crate::sampler::Sampler;
+use crate::DeviceSize;
+use crate::VulkanObject;
+use smallvec::SmallVec;
+use std::fmt;
+use std::ptr;
+use std::sync::Arc;
+
+/// Low-level descriptor set.
+///
+/// Contrary to most other objects in this library, this one doesn't free itself automatically and
+/// 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,
+}
+
+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
+
+ /// 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<I>(&mut self, device: &Device, writes: I)
+ where
+ I: Iterator<Item = DescriptorWrite>,
+ {
+ let fns = device.fns();
+
+ // In this function, we build 4 arrays: one array of image descriptors (image_descriptors),
+ // one for buffer descriptors (buffer_descriptors), one for buffer view descriptors
+ // (buffer_views_descriptors), and one for the final list of writes (raw_writes).
+ // Only the final list is passed to Vulkan, but it will contain pointers to the first three
+ // lists in `pImageInfo`, `pBufferInfo` and `pTexelBufferView`.
+ //
+ // In order to handle that, we start by writing null pointers as placeholders in the final
+ // writes, and we store in `raw_writes_img_infos`, `raw_writes_buf_infos` and
+ // `raw_writes_buf_view_infos` the offsets of the pointers compared to the start of the
+ // list.
+ // Once we have finished iterating all the writes requested by the user, we modify
+ // `raw_writes` to point to the correct locations.
+
+ let mut buffer_descriptors: SmallVec<[_; 64]> = SmallVec::new();
+ let mut image_descriptors: SmallVec<[_; 64]> = SmallVec::new();
+ let mut buffer_views_descriptors: SmallVec<[_; 64]> = SmallVec::new();
+
+ let mut raw_writes: SmallVec<[_; 64]> = SmallVec::new();
+ let mut raw_writes_img_infos: SmallVec<[_; 64]> = SmallVec::new();
+ let mut raw_writes_buf_infos: SmallVec<[_; 64]> = SmallVec::new();
+ let mut raw_writes_buf_view_infos: SmallVec<[_; 64]> = SmallVec::new();
+
+ for indiv_write in writes {
+ // 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!(!indiv_write.inner.is_empty());
+
+ // The whole struct thats written here is valid, except for pImageInfo, pBufferInfo
+ // and pTexelBufferView which are placeholder values.
+ raw_writes.push(ash::vk::WriteDescriptorSet {
+ dst_set: self.set,
+ dst_binding: indiv_write.binding,
+ dst_array_element: indiv_write.first_array_element,
+ descriptor_count: indiv_write.inner.len() as u32,
+ descriptor_type: indiv_write.ty().into(),
+ p_image_info: ptr::null(),
+ p_buffer_info: ptr::null(),
+ p_texel_buffer_view: ptr::null(),
+ ..Default::default()
+ });
+
+ match indiv_write.inner[0] {
+ DescriptorWriteInner::Sampler(_)
+ | DescriptorWriteInner::CombinedImageSampler(_, _, _)
+ | DescriptorWriteInner::SampledImage(_, _)
+ | DescriptorWriteInner::StorageImage(_, _)
+ | DescriptorWriteInner::InputAttachment(_, _) => {
+ raw_writes_img_infos.push(Some(image_descriptors.len()));
+ raw_writes_buf_infos.push(None);
+ raw_writes_buf_view_infos.push(None);
+ }
+ DescriptorWriteInner::UniformBuffer(_, _, _)
+ | DescriptorWriteInner::StorageBuffer(_, _, _)
+ | DescriptorWriteInner::DynamicUniformBuffer(_, _, _)
+ | DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
+ raw_writes_img_infos.push(None);
+ raw_writes_buf_infos.push(Some(buffer_descriptors.len()));
+ raw_writes_buf_view_infos.push(None);
+ }
+ DescriptorWriteInner::UniformTexelBuffer(_)
+ | DescriptorWriteInner::StorageTexelBuffer(_) => {
+ raw_writes_img_infos.push(None);
+ raw_writes_buf_infos.push(None);
+ raw_writes_buf_view_infos.push(Some(buffer_views_descriptors.len()));
+ }
+ }
+
+ for elem in indiv_write.inner.iter() {
+ match *elem {
+ DescriptorWriteInner::UniformBuffer(buffer, offset, size)
+ | DescriptorWriteInner::DynamicUniformBuffer(buffer, offset, size) => {
+ buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
+ buffer,
+ offset,
+ range: size,
+ });
+ }
+ DescriptorWriteInner::StorageBuffer(buffer, offset, size)
+ | DescriptorWriteInner::DynamicStorageBuffer(buffer, offset, size) => {
+ buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
+ buffer,
+ offset,
+ range: size,
+ });
+ }
+ DescriptorWriteInner::Sampler(sampler) => {
+ image_descriptors.push(ash::vk::DescriptorImageInfo {
+ sampler,
+ image_view: ash::vk::ImageView::null(),
+ image_layout: ash::vk::ImageLayout::UNDEFINED,
+ });
+ }
+ DescriptorWriteInner::CombinedImageSampler(sampler, view, layout) => {
+ image_descriptors.push(ash::vk::DescriptorImageInfo {
+ sampler,
+ image_view: view,
+ image_layout: layout,
+ });
+ }
+ DescriptorWriteInner::StorageImage(view, layout) => {
+ image_descriptors.push(ash::vk::DescriptorImageInfo {
+ sampler: ash::vk::Sampler::null(),
+ image_view: view,
+ image_layout: layout,
+ });
+ }
+ DescriptorWriteInner::SampledImage(view, layout) => {
+ image_descriptors.push(ash::vk::DescriptorImageInfo {
+ sampler: ash::vk::Sampler::null(),
+ image_view: view,
+ image_layout: layout,
+ });
+ }
+ DescriptorWriteInner::InputAttachment(view, layout) => {
+ image_descriptors.push(ash::vk::DescriptorImageInfo {
+ sampler: ash::vk::Sampler::null(),
+ image_view: view,
+ image_layout: layout,
+ });
+ }
+ DescriptorWriteInner::UniformTexelBuffer(view)
+ | DescriptorWriteInner::StorageTexelBuffer(view) => {
+ buffer_views_descriptors.push(view);
+ }
+ }
+ }
+ }
+
+ // Now that `image_descriptors`, `buffer_descriptors` and `buffer_views_descriptors` are
+ // entirely filled and will never move again, we can fill the pointers in `raw_writes`.
+ for (i, write) in raw_writes.iter_mut().enumerate() {
+ write.p_image_info = match raw_writes_img_infos[i] {
+ Some(off) => image_descriptors.as_ptr().offset(off as isize),
+ None => ptr::null(),
+ };
+
+ write.p_buffer_info = match raw_writes_buf_infos[i] {
+ Some(off) => buffer_descriptors.as_ptr().offset(off as isize),
+ None => ptr::null(),
+ };
+
+ write.p_texel_buffer_view = match raw_writes_buf_view_infos[i] {
+ Some(off) => buffer_views_descriptors.as_ptr().offset(off as isize),
+ None => ptr::null(),
+ };
+ }
+
+ // It is forbidden to call `vkUpdateDescriptorSets` with 0 writes, so we need to perform
+ // this emptiness check.
+ if !raw_writes.is_empty() {
+ fns.v1_0.update_descriptor_sets(
+ device.internal_object(),
+ raw_writes.len() as u32,
+ raw_writes.as_ptr(),
+ 0,
+ ptr::null(),
+ );
+ }
+ }
+}
+
+unsafe impl VulkanObject for UnsafeDescriptorSet {
+ type Object = ash::vk::DescriptorSet;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::DescriptorSet {
+ self.set
+ }
+}
+
+impl fmt::Debug for UnsafeDescriptorSet {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan descriptor set {:?}>", self.set)
+ }
+}
+
+/// Represents a single write entry to a descriptor set.
+///
+/// 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.
+// TODO: allow binding whole arrays at once
+pub struct DescriptorWrite {
+ binding: u32,
+ first_array_element: u32,
+ inner: SmallVec<[DescriptorWriteInner; 1]>,
+}
+
+#[derive(Debug, Clone)]
+enum DescriptorWriteInner {
+ Sampler(ash::vk::Sampler),
+ StorageImage(ash::vk::ImageView, ash::vk::ImageLayout),
+ SampledImage(ash::vk::ImageView, ash::vk::ImageLayout),
+ CombinedImageSampler(ash::vk::Sampler, ash::vk::ImageView, ash::vk::ImageLayout),
+ UniformTexelBuffer(ash::vk::BufferView),
+ StorageTexelBuffer(ash::vk::BufferView),
+ UniformBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
+ StorageBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
+ DynamicUniformBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
+ DynamicStorageBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
+ InputAttachment(ash::vk::ImageView, ash::vk::ImageLayout),
+}
+
+macro_rules! smallvec {
+ ($elem:expr) => {{
+ let mut s = SmallVec::new();
+ s.push($elem);
+ s
+ }};
+}
+
+impl DescriptorWrite {
+ #[inline]
+ pub fn storage_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
+ where
+ I: ImageViewAbstract,
+ {
+ let layouts = image_view
+ .image()
+ .descriptor_layouts()
+ .expect("descriptor_layouts must return Some when used in an image view");
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!({
+ DescriptorWriteInner::StorageImage(
+ image_view.inner().internal_object(),
+ layouts.storage_image.into(),
+ )
+ }),
+ }
+ }
+
+ #[inline]
+ pub fn sampler(binding: u32, array_element: u32, sampler: &Arc<Sampler>) -> DescriptorWrite {
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!(DescriptorWriteInner::Sampler(sampler.internal_object())),
+ }
+ }
+
+ #[inline]
+ pub fn sampled_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
+ where
+ I: ImageViewAbstract,
+ {
+ let layouts = image_view
+ .image()
+ .descriptor_layouts()
+ .expect("descriptor_layouts must return Some when used in an image view");
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!({
+ DescriptorWriteInner::SampledImage(
+ image_view.inner().internal_object(),
+ layouts.sampled_image.into(),
+ )
+ }),
+ }
+ }
+
+ #[inline]
+ pub fn combined_image_sampler<I>(
+ binding: u32,
+ array_element: u32,
+ sampler: &Arc<Sampler>,
+ image_view: &I,
+ ) -> DescriptorWrite
+ where
+ I: ImageViewAbstract,
+ {
+ let layouts = image_view
+ .image()
+ .descriptor_layouts()
+ .expect("descriptor_layouts must return Some when used in an image view");
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!({
+ DescriptorWriteInner::CombinedImageSampler(
+ sampler.internal_object(),
+ image_view.inner().internal_object(),
+ layouts.combined_image_sampler.into(),
+ )
+ }),
+ }
+ }
+
+ #[inline]
+ pub fn uniform_texel_buffer<'a, B>(
+ binding: u32,
+ array_element: u32,
+ view: &BufferView<B>,
+ ) -> DescriptorWrite
+ where
+ B: BufferAccess,
+ {
+ assert!(view.uniform_texel_buffer());
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!(DescriptorWriteInner::UniformTexelBuffer(
+ view.internal_object()
+ )),
+ }
+ }
+
+ #[inline]
+ pub fn storage_texel_buffer<'a, B>(
+ binding: u32,
+ array_element: u32,
+ view: &BufferView<B>,
+ ) -> DescriptorWrite
+ where
+ B: BufferAccess,
+ {
+ assert!(view.storage_texel_buffer());
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!(DescriptorWriteInner::StorageTexelBuffer(
+ view.internal_object()
+ )),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn uniform_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
+ where
+ B: BufferAccess,
+ {
+ 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
+ );
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!({
+ DescriptorWriteInner::UniformBuffer(buffer.internal_object(), offset, size)
+ }),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn storage_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
+ where
+ B: BufferAccess,
+ {
+ 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
+ );
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!({
+ DescriptorWriteInner::StorageBuffer(buffer.internal_object(), offset, size)
+ }),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn dynamic_uniform_buffer<B>(
+ binding: u32,
+ array_element: u32,
+ buffer: &B,
+ ) -> DescriptorWrite
+ where
+ B: BufferAccess,
+ {
+ 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
+ );
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!(DescriptorWriteInner::DynamicUniformBuffer(
+ buffer.internal_object(),
+ offset,
+ size
+ )),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn dynamic_storage_buffer<B>(
+ binding: u32,
+ array_element: u32,
+ buffer: &B,
+ ) -> DescriptorWrite
+ where
+ B: BufferAccess,
+ {
+ 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
+ );
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!(DescriptorWriteInner::DynamicStorageBuffer(
+ buffer.internal_object(),
+ offset,
+ size
+ )),
+ }
+ }
+
+ #[inline]
+ pub fn input_attachment<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
+ where
+ I: ImageViewAbstract,
+ {
+ let layouts = image_view
+ .image()
+ .descriptor_layouts()
+ .expect("descriptor_layouts must return Some when used in an image view");
+
+ DescriptorWrite {
+ binding,
+ first_array_element: array_element,
+ inner: smallvec!({
+ DescriptorWriteInner::InputAttachment(
+ image_view.inner().internal_object(),
+ layouts.input_attachment.into(),
+ )
+ }),
+ }
+ }
+
+ /// Returns the type corresponding to this write.
+ #[inline]
+ pub fn ty(&self) -> DescriptorType {
+ match self.inner[0] {
+ DescriptorWriteInner::Sampler(_) => DescriptorType::Sampler,
+ DescriptorWriteInner::CombinedImageSampler(_, _, _) => {
+ DescriptorType::CombinedImageSampler
+ }
+ DescriptorWriteInner::SampledImage(_, _) => DescriptorType::SampledImage,
+ DescriptorWriteInner::StorageImage(_, _) => DescriptorType::StorageImage,
+ DescriptorWriteInner::UniformTexelBuffer(_) => DescriptorType::UniformTexelBuffer,
+ DescriptorWriteInner::StorageTexelBuffer(_) => DescriptorType::StorageTexelBuffer,
+ DescriptorWriteInner::UniformBuffer(_, _, _) => DescriptorType::UniformBuffer,
+ DescriptorWriteInner::StorageBuffer(_, _, _) => DescriptorType::StorageBuffer,
+ DescriptorWriteInner::DynamicUniformBuffer(_, _, _) => {
+ DescriptorType::UniformBufferDynamic
+ }
+ DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
+ DescriptorType::StorageBufferDynamic
+ }
+ DescriptorWriteInner::InputAttachment(_, _) => DescriptorType::InputAttachment,
+ }
+ }
+}