// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // 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::{ descriptor_set::{ layout::DescriptorSetLayout, update::{DescriptorWriteInfo, WriteDescriptorSet}, }, device::DeviceOwned, macros::impl_id_counter, VulkanObject, }; use smallvec::SmallVec; use std::{ fmt::{Debug, Error as FmtError, Formatter}, num::NonZeroU64, ptr, }; /// 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 [`DescriptorPool`]. /// /// [`DescriptorPool`]: super::pool::DescriptorPool pub struct UnsafeDescriptorSet { handle: ash::vk::DescriptorSet, id: NonZeroU64, } impl UnsafeDescriptorSet { pub(crate) fn new(handle: ash::vk::DescriptorSet) -> Self { Self { handle, id: Self::next_id(), } } /// 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. /// /// # Safety /// /// - The `Device` must be the device the pool of this set was created with. /// - 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<'a>( &mut self, layout: &DescriptorSetLayout, writes: impl IntoIterator, ) { let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = writes .into_iter() .map(|write| { let descriptor_type = layout.bindings()[&write.binding()].descriptor_type; ( 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 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)( layout.device().handle(), 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 { type Handle = ash::vk::DescriptorSet; #[inline] fn handle(&self) -> Self::Handle { self.handle } } impl Debug for UnsafeDescriptorSet { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { write!(f, "", self.handle) } } impl_id_counter!(UnsafeDescriptorSet);