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 //! # Examples 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 //! [`DescriptorPool`] 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 [`DescriptorSetAllocator`] trait can be implemented on types from which you can allocate 66 //! and free descriptor sets. However it is different from Vulkan descriptor pools in the sense 67 //! that an implementation of the [`DescriptorSetAllocator`] trait can manage multiple Vulkan 68 //! descriptor pools. 69 //! - The [`StandardDescriptorSetAllocator`] type is a default implementation of the 70 //! [`DescriptorSetAllocator`] trait. 71 //! - The [`DescriptorSet`] trait is implemented on types that wrap around Vulkan descriptor sets in 72 //! a safe way. A Vulkan descriptor set is inherently unsafe, so we need safe wrappers around 73 //! them. 74 //! - The [`DescriptorSetsCollection`] trait is implemented on collections of types that implement 75 //! [`DescriptorSet`]. It is what you pass to the draw functions. 76 //! 77 //! [`DescriptorPool`]: pool::DescriptorPool 78 //! [`DescriptorSetAllocator`]: allocator::DescriptorSetAllocator 79 //! [`StandardDescriptorSetAllocator`]: allocator::StandardDescriptorSetAllocator 80 81 pub(crate) use self::update::{check_descriptor_write, DescriptorWriteInfo}; 82 pub use self::{ 83 collection::DescriptorSetsCollection, 84 persistent::PersistentDescriptorSet, 85 update::{DescriptorSetUpdateError, WriteDescriptorSet, WriteDescriptorSetElements}, 86 }; 87 use self::{layout::DescriptorSetLayout, sys::UnsafeDescriptorSet}; 88 use crate::{ 89 buffer::{view::BufferView, Subbuffer}, 90 descriptor_set::layout::DescriptorType, 91 device::DeviceOwned, 92 image::view::ImageViewAbstract, 93 sampler::Sampler, 94 DeviceSize, OomError, VulkanObject, 95 }; 96 use ahash::HashMap; 97 use smallvec::{smallvec, SmallVec}; 98 use std::{ 99 error::Error, 100 fmt::{Display, Error as FmtError, Formatter}, 101 hash::{Hash, Hasher}, 102 ops::Range, 103 ptr, 104 sync::Arc, 105 }; 106 107 pub mod allocator; 108 mod collection; 109 pub mod layout; 110 pub mod persistent; 111 pub mod pool; 112 pub mod sys; 113 mod update; 114 115 /// Trait for objects that contain a collection of resources that will be accessible by shaders. 116 /// 117 /// Objects of this type can be passed when submitting a draw command. 118 pub unsafe trait DescriptorSet: DeviceOwned + Send + Sync { 119 /// Returns the inner `UnsafeDescriptorSet`. inner(&self) -> &UnsafeDescriptorSet120 fn inner(&self) -> &UnsafeDescriptorSet; 121 122 /// Returns the layout of this descriptor set. layout(&self) -> &Arc<DescriptorSetLayout>123 fn layout(&self) -> &Arc<DescriptorSetLayout>; 124 125 /// Returns the variable descriptor count that this descriptor set was allocated with. variable_descriptor_count(&self) -> u32126 fn variable_descriptor_count(&self) -> u32; 127 128 /// Creates a [`DescriptorSetWithOffsets`] with the given dynamic offsets. offsets( self: Arc<Self>, dynamic_offsets: impl IntoIterator<Item = u32>, ) -> DescriptorSetWithOffsets where Self: Sized + 'static,129 fn offsets( 130 self: Arc<Self>, 131 dynamic_offsets: impl IntoIterator<Item = u32>, 132 ) -> DescriptorSetWithOffsets 133 where 134 Self: Sized + 'static, 135 { 136 DescriptorSetWithOffsets::new(self, dynamic_offsets) 137 } 138 139 /// Returns the resources bound to this descriptor set. resources(&self) -> &DescriptorSetResources140 fn resources(&self) -> &DescriptorSetResources; 141 } 142 143 impl PartialEq for dyn DescriptorSet { 144 #[inline] eq(&self, other: &Self) -> bool145 fn eq(&self, other: &Self) -> bool { 146 self.inner() == other.inner() 147 } 148 } 149 150 impl Eq for dyn DescriptorSet {} 151 152 impl Hash for dyn DescriptorSet { hash<H: Hasher>(&self, state: &mut H)153 fn hash<H: Hasher>(&self, state: &mut H) { 154 self.inner().hash(state); 155 } 156 } 157 158 pub(crate) struct DescriptorSetInner { 159 layout: Arc<DescriptorSetLayout>, 160 variable_descriptor_count: u32, 161 resources: DescriptorSetResources, 162 } 163 164 impl DescriptorSetInner { new( handle: ash::vk::DescriptorSet, layout: Arc<DescriptorSetLayout>, variable_descriptor_count: u32, descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, ) -> Result<Self, DescriptorSetUpdateError>165 pub(crate) fn new( 166 handle: ash::vk::DescriptorSet, 167 layout: Arc<DescriptorSetLayout>, 168 variable_descriptor_count: u32, 169 descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>, 170 ) -> Result<Self, DescriptorSetUpdateError> { 171 assert!( 172 !layout.push_descriptor(), 173 "the provided descriptor set layout is for push descriptors, and cannot be used to \ 174 build a descriptor set object", 175 ); 176 177 let max_count = layout.variable_descriptor_count(); 178 179 assert!( 180 variable_descriptor_count <= max_count, 181 "the provided variable_descriptor_count ({}) is greater than the maximum number of \ 182 variable count descriptors in the layout ({})", 183 variable_descriptor_count, 184 max_count, 185 ); 186 187 let mut resources = DescriptorSetResources::new(&layout, variable_descriptor_count); 188 189 let descriptor_writes = descriptor_writes.into_iter(); 190 let (lower_size_bound, _) = descriptor_writes.size_hint(); 191 let mut descriptor_write_info: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound); 192 let mut write_descriptor_set: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound); 193 194 for write in descriptor_writes { 195 let layout_binding = 196 check_descriptor_write(&write, &layout, variable_descriptor_count)?; 197 198 resources.update(&write); 199 descriptor_write_info.push(write.to_vulkan_info(layout_binding.descriptor_type)); 200 write_descriptor_set.push(write.to_vulkan(handle, layout_binding.descriptor_type)); 201 } 202 203 if !write_descriptor_set.is_empty() { 204 for (info, write) in descriptor_write_info 205 .iter() 206 .zip(write_descriptor_set.iter_mut()) 207 { 208 match info { 209 DescriptorWriteInfo::Image(info) => { 210 write.descriptor_count = info.len() as u32; 211 write.p_image_info = info.as_ptr(); 212 } 213 DescriptorWriteInfo::Buffer(info) => { 214 write.descriptor_count = info.len() as u32; 215 write.p_buffer_info = info.as_ptr(); 216 } 217 DescriptorWriteInfo::BufferView(info) => { 218 write.descriptor_count = info.len() as u32; 219 write.p_texel_buffer_view = info.as_ptr(); 220 } 221 } 222 } 223 } 224 225 unsafe { 226 let fns = layout.device().fns(); 227 228 (fns.v1_0.update_descriptor_sets)( 229 layout.device().handle(), 230 write_descriptor_set.len() as u32, 231 write_descriptor_set.as_ptr(), 232 0, 233 ptr::null(), 234 ); 235 } 236 237 Ok(DescriptorSetInner { 238 layout, 239 variable_descriptor_count, 240 resources, 241 }) 242 } 243 layout(&self) -> &Arc<DescriptorSetLayout>244 pub(crate) fn layout(&self) -> &Arc<DescriptorSetLayout> { 245 &self.layout 246 } 247 resources(&self) -> &DescriptorSetResources248 pub(crate) fn resources(&self) -> &DescriptorSetResources { 249 &self.resources 250 } 251 } 252 253 /// The resources that are bound to a descriptor set. 254 #[derive(Clone)] 255 pub struct DescriptorSetResources { 256 binding_resources: HashMap<u32, DescriptorBindingResources>, 257 } 258 259 impl DescriptorSetResources { 260 /// Creates a new `DescriptorSetResources` matching the provided descriptor set layout, and 261 /// all descriptors set to `None`. 262 #[inline] new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self263 pub fn new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self { 264 assert!(variable_descriptor_count <= layout.variable_descriptor_count()); 265 266 let binding_resources = layout 267 .bindings() 268 .iter() 269 .map(|(&binding_num, binding)| { 270 let count = if binding.variable_descriptor_count { 271 variable_descriptor_count 272 } else { 273 binding.descriptor_count 274 } as usize; 275 276 let binding_resources = match binding.descriptor_type { 277 DescriptorType::UniformBuffer 278 | DescriptorType::StorageBuffer 279 | DescriptorType::UniformBufferDynamic 280 | DescriptorType::StorageBufferDynamic => { 281 DescriptorBindingResources::Buffer(smallvec![None; count]) 282 } 283 DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer => { 284 DescriptorBindingResources::BufferView(smallvec![None; count]) 285 } 286 DescriptorType::SampledImage 287 | DescriptorType::StorageImage 288 | DescriptorType::InputAttachment => { 289 DescriptorBindingResources::ImageView(smallvec![None; count]) 290 } 291 DescriptorType::CombinedImageSampler => { 292 if binding.immutable_samplers.is_empty() { 293 DescriptorBindingResources::ImageViewSampler(smallvec![None; count]) 294 } else { 295 DescriptorBindingResources::ImageView(smallvec![None; count]) 296 } 297 } 298 DescriptorType::Sampler => { 299 if binding.immutable_samplers.is_empty() { 300 DescriptorBindingResources::Sampler(smallvec![None; count]) 301 } else if layout.push_descriptor() { 302 // For push descriptors, no resource is written by default, this needs 303 // to be done explicitly via a dummy write. 304 DescriptorBindingResources::None(smallvec![None; count]) 305 } else { 306 // For regular descriptor sets, all descriptors are considered valid 307 // from the start. 308 DescriptorBindingResources::None(smallvec![Some(()); count]) 309 } 310 } 311 }; 312 (binding_num, binding_resources) 313 }) 314 .collect(); 315 316 Self { binding_resources } 317 } 318 319 /// Applies a descriptor write to the resources. 320 /// 321 /// # Panics 322 /// 323 /// - Panics if the binding number of a write does not exist in the resources. 324 /// - See also [`DescriptorBindingResources::update`]. 325 #[inline] update(&mut self, write: &WriteDescriptorSet)326 pub fn update(&mut self, write: &WriteDescriptorSet) { 327 self.binding_resources 328 .get_mut(&write.binding()) 329 .expect("descriptor write has invalid binding number") 330 .update(write) 331 } 332 333 /// Returns a reference to the bound resources for `binding`. Returns `None` if the binding 334 /// doesn't exist. 335 #[inline] binding(&self, binding: u32) -> Option<&DescriptorBindingResources>336 pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> { 337 self.binding_resources.get(&binding) 338 } 339 } 340 341 /// The resources that are bound to a single descriptor set binding. 342 #[derive(Clone)] 343 pub enum DescriptorBindingResources { 344 None(Elements<()>), 345 Buffer(Elements<(Subbuffer<[u8]>, Range<DeviceSize>)>), 346 BufferView(Elements<Arc<BufferView>>), 347 ImageView(Elements<Arc<dyn ImageViewAbstract>>), 348 ImageViewSampler(Elements<(Arc<dyn ImageViewAbstract>, Arc<Sampler>)>), 349 Sampler(Elements<Arc<Sampler>>), 350 } 351 352 type Elements<T> = SmallVec<[Option<T>; 1]>; 353 354 impl DescriptorBindingResources { 355 /// Applies a descriptor write to the resources. 356 /// 357 /// # Panics 358 /// 359 /// - Panics if the resource types do not match. 360 /// - Panics if the write goes out of bounds. 361 #[inline] update(&mut self, write: &WriteDescriptorSet)362 pub fn update(&mut self, write: &WriteDescriptorSet) { 363 fn write_resources<T: Clone>(first: usize, resources: &mut [Option<T>], elements: &[T]) { 364 resources 365 .get_mut(first..first + elements.len()) 366 .expect("descriptor write for binding out of bounds") 367 .iter_mut() 368 .zip(elements) 369 .for_each(|(resource, element)| { 370 *resource = Some(element.clone()); 371 }); 372 } 373 374 let first = write.first_array_element() as usize; 375 376 match (self, write.elements()) { 377 ( 378 DescriptorBindingResources::None(resources), 379 WriteDescriptorSetElements::None(num_elements), 380 ) => { 381 resources 382 .get_mut(first..first + *num_elements as usize) 383 .expect("descriptor write for binding out of bounds") 384 .iter_mut() 385 .for_each(|resource| { 386 *resource = Some(()); 387 }); 388 } 389 ( 390 DescriptorBindingResources::Buffer(resources), 391 WriteDescriptorSetElements::Buffer(elements), 392 ) => write_resources(first, resources, elements), 393 ( 394 DescriptorBindingResources::BufferView(resources), 395 WriteDescriptorSetElements::BufferView(elements), 396 ) => write_resources(first, resources, elements), 397 ( 398 DescriptorBindingResources::ImageView(resources), 399 WriteDescriptorSetElements::ImageView(elements), 400 ) => write_resources(first, resources, elements), 401 ( 402 DescriptorBindingResources::ImageViewSampler(resources), 403 WriteDescriptorSetElements::ImageViewSampler(elements), 404 ) => write_resources(first, resources, elements), 405 ( 406 DescriptorBindingResources::Sampler(resources), 407 WriteDescriptorSetElements::Sampler(elements), 408 ) => write_resources(first, resources, elements), 409 _ => panic!( 410 "descriptor write for binding {} has wrong resource type", 411 write.binding(), 412 ), 413 } 414 } 415 } 416 417 #[derive(Clone)] 418 pub struct DescriptorSetWithOffsets { 419 descriptor_set: Arc<dyn DescriptorSet>, 420 dynamic_offsets: SmallVec<[u32; 4]>, 421 } 422 423 impl DescriptorSetWithOffsets { new( descriptor_set: Arc<dyn DescriptorSet>, dynamic_offsets: impl IntoIterator<Item = u32>, ) -> Self424 pub fn new( 425 descriptor_set: Arc<dyn DescriptorSet>, 426 dynamic_offsets: impl IntoIterator<Item = u32>, 427 ) -> Self { 428 Self { 429 descriptor_set, 430 dynamic_offsets: dynamic_offsets.into_iter().collect(), 431 } 432 } 433 434 #[inline] as_ref(&self) -> (&Arc<dyn DescriptorSet>, &[u32])435 pub fn as_ref(&self) -> (&Arc<dyn DescriptorSet>, &[u32]) { 436 (&self.descriptor_set, &self.dynamic_offsets) 437 } 438 439 #[inline] into_tuple(self) -> (Arc<dyn DescriptorSet>, impl ExactSizeIterator<Item = u32>)440 pub fn into_tuple(self) -> (Arc<dyn DescriptorSet>, impl ExactSizeIterator<Item = u32>) { 441 (self.descriptor_set, self.dynamic_offsets.into_iter()) 442 } 443 } 444 445 impl<S> From<Arc<S>> for DescriptorSetWithOffsets 446 where 447 S: DescriptorSet + 'static, 448 { from(descriptor_set: Arc<S>) -> Self449 fn from(descriptor_set: Arc<S>) -> Self { 450 DescriptorSetWithOffsets::new(descriptor_set, std::iter::empty()) 451 } 452 } 453 454 #[derive(Clone, Copy, Debug)] 455 pub enum DescriptorSetCreationError { 456 DescriptorSetUpdateError(DescriptorSetUpdateError), 457 OomError(OomError), 458 } 459 460 impl Error for DescriptorSetCreationError { source(&self) -> Option<&(dyn Error + 'static)>461 fn source(&self) -> Option<&(dyn Error + 'static)> { 462 match self { 463 Self::DescriptorSetUpdateError(err) => Some(err), 464 Self::OomError(err) => Some(err), 465 } 466 } 467 } 468 469 impl Display for DescriptorSetCreationError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>470 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 471 match self { 472 Self::DescriptorSetUpdateError(_) => { 473 write!(f, "an error occurred while updating the descriptor set") 474 } 475 Self::OomError(_) => write!(f, "out of memory"), 476 } 477 } 478 } 479 480 impl From<DescriptorSetUpdateError> for DescriptorSetCreationError { from(err: DescriptorSetUpdateError) -> Self481 fn from(err: DescriptorSetUpdateError) -> Self { 482 Self::DescriptorSetUpdateError(err) 483 } 484 } 485 486 impl From<OomError> for DescriptorSetCreationError { from(err: OomError) -> Self487 fn from(err: OomError) -> Self { 488 Self::OomError(err) 489 } 490 } 491