1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 //! Bindings between shaders and the resources they access. 11 //! 12 //! # Overview 13 //! 14 //! In order to access a buffer or an image from a shader, that buffer or image must be put in a 15 //! *descriptor*. Each descriptor contains one buffer or one image alongside with the way that it 16 //! can be accessed. A descriptor can also be an array, in which case it contains multiple buffers 17 //! or images that all have the same layout. 18 //! 19 //! Descriptors are grouped in what is called *descriptor sets*. In Vulkan you don't bind 20 //! individual descriptors one by one, but you create then bind descriptor sets one by one. As 21 //! binding a descriptor set has (small but non-null) a cost, you are encouraged to put descriptors 22 //! that are often used together in the same set so that you can keep the same set binding through 23 //! multiple draws. 24 //! 25 //! # Example 26 //! 27 //! > **Note**: This section describes the simple way to bind resources. There are more optimized 28 //! > ways. 29 //! 30 //! There are two steps to give access to a resource in a shader: creating the descriptor set, and 31 //! passing the descriptor sets when drawing. 32 //! 33 //! ## Creating a descriptor set 34 //! 35 //! TODO: write example for: PersistentDescriptorSet::start(layout.clone()).add_buffer(data_buffer.clone()) 36 //! 37 //! ## Passing the descriptor set when drawing 38 //! 39 //! TODO: write 40 //! 41 //! # When drawing 42 //! 43 //! When you call a function that adds a draw command to a command buffer, one of the parameters 44 //! corresponds to the list of descriptor sets to use. Vulkano will check that what you passed is 45 //! compatible with the layout of the pipeline. 46 //! 47 //! TODO: talk about perfs of changing sets 48 //! 49 //! # Descriptor sets creation and management 50 //! 51 //! There are three concepts in Vulkan related to descriptor sets: 52 //! 53 //! - A `DescriptorSetLayout` is a Vulkan object that describes to the Vulkan implementation the 54 //! layout of a future descriptor set. When you allocate a descriptor set, you have to pass an 55 //! instance of this object. This is represented with the `DescriptorSetLayout` type in 56 //! vulkano. 57 //! - A `DescriptorPool` is a Vulkan object that holds the memory of descriptor sets and that can 58 //! be used to allocate and free individual descriptor sets. This is represented with the 59 //! `UnsafeDescriptorPool` type in vulkano. 60 //! - A `DescriptorSet` contains the bindings to resources and is allocated from a pool. This is 61 //! represented with the `UnsafeDescriptorSet` type in vulkano. 62 //! 63 //! In addition to this, vulkano defines the following: 64 //! 65 //! - The `DescriptorPool` trait can be implemented on types from which you can allocate and free 66 //! descriptor sets. However it is different from Vulkan descriptor pools in the sense that an 67 //! implementation of the `DescriptorPool` trait can manage multiple Vulkan descriptor pools. 68 //! - The `StdDescriptorPool` type is a default implementation of the `DescriptorPool` trait. 69 //! - The `DescriptorSet` trait is implemented on types that wrap around Vulkan descriptor sets in 70 //! a safe way. A Vulkan descriptor set is inherently unsafe, so we need safe wrappers around 71 //! them. 72 //! - The `SimpleDescriptorSet` type is a default implementation of the `DescriptorSet` trait. 73 //! - The `DescriptorSetsCollection` trait is implemented on collections of types that implement 74 //! `DescriptorSet`. It is what you pass to the draw functions. 75 76 pub use self::collection::DescriptorSetsCollection; 77 pub use self::fixed_size_pool::FixedSizeDescriptorSetsPool; 78 use self::layout::DescriptorSetLayout; 79 pub use self::persistent::PersistentDescriptorSet; 80 pub use self::persistent::PersistentDescriptorSetBuildError; 81 pub use self::persistent::PersistentDescriptorSetError; 82 use self::sys::UnsafeDescriptorSet; 83 use crate::buffer::BufferAccess; 84 use crate::descriptor_set::layout::{DescriptorBufferDesc, DescriptorDescTy}; 85 use crate::device::DeviceOwned; 86 use crate::image::view::ImageViewAbstract; 87 use crate::SafeDeref; 88 use crate::VulkanObject; 89 use smallvec::SmallVec; 90 use std::hash::Hash; 91 use std::hash::Hasher; 92 use std::sync::Arc; 93 94 mod collection; 95 pub mod fixed_size_pool; 96 pub mod layout; 97 pub mod persistent; 98 pub mod pool; 99 pub mod sys; 100 101 /// Trait for objects that contain a collection of resources that will be accessible by shaders. 102 /// 103 /// Objects of this type can be passed when submitting a draw command. 104 pub unsafe trait DescriptorSet: DeviceOwned { 105 /// Returns the inner `UnsafeDescriptorSet`. inner(&self) -> &UnsafeDescriptorSet106 fn inner(&self) -> &UnsafeDescriptorSet; 107 108 /// Returns the layout of this descriptor set. layout(&self) -> &Arc<DescriptorSetLayout>109 fn layout(&self) -> &Arc<DescriptorSetLayout>; 110 111 /// Creates a [`DescriptorSetWithOffsets`] with the given dynamic offsets. offsets<I>(self, dynamic_offsets: I) -> DescriptorSetWithOffsets where Self: Sized + Send + Sync + 'static, I: IntoIterator<Item = u32>,112 fn offsets<I>(self, dynamic_offsets: I) -> DescriptorSetWithOffsets 113 where 114 Self: Sized + Send + Sync + 'static, 115 I: IntoIterator<Item = u32>, 116 { 117 DescriptorSetWithOffsets::new(self, dynamic_offsets) 118 } 119 120 /// Returns the number of buffers within this descriptor set. num_buffers(&self) -> usize121 fn num_buffers(&self) -> usize; 122 123 /// Returns the `index`th buffer of this descriptor set, or `None` if out of range. Also 124 /// returns the index of the descriptor that uses this buffer. 125 /// 126 /// The valid range is between 0 and `num_buffers()`. buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>127 fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>; 128 129 /// Returns the number of images within this descriptor set. num_images(&self) -> usize130 fn num_images(&self) -> usize; 131 132 /// Returns the `index`th image of this descriptor set, or `None` if out of range. Also returns 133 /// the index of the descriptor that uses this image. 134 /// 135 /// The valid range is between 0 and `num_images()`. image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>136 fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>; 137 } 138 139 unsafe impl<T> DescriptorSet for T 140 where 141 T: SafeDeref, 142 T::Target: DescriptorSet, 143 { 144 #[inline] inner(&self) -> &UnsafeDescriptorSet145 fn inner(&self) -> &UnsafeDescriptorSet { 146 (**self).inner() 147 } 148 149 #[inline] layout(&self) -> &Arc<DescriptorSetLayout>150 fn layout(&self) -> &Arc<DescriptorSetLayout> { 151 (**self).layout() 152 } 153 154 #[inline] num_buffers(&self) -> usize155 fn num_buffers(&self) -> usize { 156 (**self).num_buffers() 157 } 158 159 #[inline] buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>160 fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> { 161 (**self).buffer(index) 162 } 163 164 #[inline] num_images(&self) -> usize165 fn num_images(&self) -> usize { 166 (**self).num_images() 167 } 168 169 #[inline] image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>170 fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> { 171 (**self).image(index) 172 } 173 } 174 175 impl PartialEq for dyn DescriptorSet + Send + Sync { 176 #[inline] eq(&self, other: &Self) -> bool177 fn eq(&self, other: &Self) -> bool { 178 self.inner().internal_object() == other.inner().internal_object() 179 && self.device() == other.device() 180 } 181 } 182 183 impl Eq for dyn DescriptorSet + Send + Sync {} 184 185 impl Hash for dyn DescriptorSet + Send + Sync { 186 #[inline] hash<H: Hasher>(&self, state: &mut H)187 fn hash<H: Hasher>(&self, state: &mut H) { 188 self.inner().internal_object().hash(state); 189 self.device().hash(state); 190 } 191 } 192 193 pub struct DescriptorSetWithOffsets { 194 descriptor_set: Box<dyn DescriptorSet + Send + Sync>, 195 dynamic_offsets: SmallVec<[u32; 4]>, 196 } 197 198 impl DescriptorSetWithOffsets { 199 #[inline] new<S, O>(descriptor_set: S, dynamic_offsets: O) -> Self where S: DescriptorSet + Send + Sync + 'static, O: IntoIterator<Item = u32>,200 pub fn new<S, O>(descriptor_set: S, dynamic_offsets: O) -> Self 201 where 202 S: DescriptorSet + Send + Sync + 'static, 203 O: IntoIterator<Item = u32>, 204 { 205 let dynamic_offsets: SmallVec<_> = dynamic_offsets.into_iter().collect(); 206 let layout = descriptor_set.layout(); 207 let properties = layout.device().physical_device().properties(); 208 let min_uniform_off_align = properties.min_uniform_buffer_offset_alignment as u32; 209 let min_storage_off_align = properties.min_storage_buffer_offset_alignment as u32; 210 let mut dynamic_offset_index = 0; 211 212 // Ensure that the number of dynamic_offsets is correct and that each 213 // dynamic offset is a multiple of the minimum offset alignment specified 214 // by the physical device. 215 for desc in layout.desc().bindings() { 216 let desc = desc.as_ref().unwrap(); 217 if let DescriptorDescTy::Buffer(DescriptorBufferDesc { 218 dynamic: Some(true), 219 storage, 220 }) = desc.ty 221 { 222 // Don't check alignment if there are not enough offsets anyway 223 if dynamic_offsets.len() > dynamic_offset_index { 224 if storage { 225 assert!( 226 dynamic_offsets[dynamic_offset_index] % min_storage_off_align == 0, 227 "Dynamic storage buffer offset must be a multiple of min_storage_buffer_offset_alignment: got {}, expected a multiple of {}", 228 dynamic_offsets[dynamic_offset_index], 229 min_storage_off_align 230 ); 231 } else { 232 assert!( 233 dynamic_offsets[dynamic_offset_index] % min_uniform_off_align == 0, 234 "Dynamic uniform buffer offset must be a multiple of min_uniform_buffer_offset_alignment: got {}, expected a multiple of {}", 235 dynamic_offsets[dynamic_offset_index], 236 min_uniform_off_align 237 ); 238 } 239 } 240 dynamic_offset_index += 1; 241 } 242 } 243 244 assert!( 245 !(dynamic_offsets.len() < dynamic_offset_index), 246 "Too few dynamic offsets: got {}, expected {}", 247 dynamic_offsets.len(), 248 dynamic_offset_index 249 ); 250 assert!( 251 !(dynamic_offsets.len() > dynamic_offset_index), 252 "Too many dynamic offsets: got {}, expected {}", 253 dynamic_offsets.len(), 254 dynamic_offset_index 255 ); 256 257 DescriptorSetWithOffsets { 258 descriptor_set: Box::new(descriptor_set), 259 dynamic_offsets, 260 } 261 } 262 263 #[inline] as_ref(&self) -> (&dyn DescriptorSet, &[u32])264 pub fn as_ref(&self) -> (&dyn DescriptorSet, &[u32]) { 265 (&self.descriptor_set, &self.dynamic_offsets) 266 } 267 268 #[inline] into_tuple( self, ) -> ( Box<dyn DescriptorSet + Send + Sync>, impl ExactSizeIterator<Item = u32>, )269 pub fn into_tuple( 270 self, 271 ) -> ( 272 Box<dyn DescriptorSet + Send + Sync>, 273 impl ExactSizeIterator<Item = u32>, 274 ) { 275 (self.descriptor_set, self.dynamic_offsets.into_iter()) 276 } 277 } 278 279 impl<S> From<S> for DescriptorSetWithOffsets 280 where 281 S: DescriptorSet + Send + Sync + 'static, 282 { 283 #[inline] from(descriptor_set: S) -> Self284 fn from(descriptor_set: S) -> Self { 285 Self::new(descriptor_set, std::iter::empty()) 286 } 287 } 288