1 // Copyright (c) 2021 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 use crate::check_errors; 11 use crate::descriptor_set::layout::DescriptorSetLayout; 12 use crate::descriptor_set::pool::DescriptorsCount; 13 use crate::descriptor_set::UnsafeDescriptorSet; 14 use crate::device::Device; 15 use crate::device::DeviceOwned; 16 use crate::OomError; 17 use crate::VulkanObject; 18 use smallvec::SmallVec; 19 use std::error; 20 use std::fmt; 21 use std::mem::MaybeUninit; 22 use std::ptr; 23 use std::sync::Arc; 24 use std::vec::IntoIter as VecIntoIter; 25 26 /// Pool from which descriptor sets are allocated from. 27 /// 28 /// A pool has a maximum number of descriptor sets and a maximum number of descriptors (one value 29 /// per descriptor type) it can allocate. 30 pub struct UnsafeDescriptorPool { 31 pool: ash::vk::DescriptorPool, 32 device: Arc<Device>, 33 } 34 35 impl UnsafeDescriptorPool { 36 /// Initializes a new pool. 37 /// 38 /// Initializes a pool whose capacity is given by `count` and `max_sets`. At most `count` 39 /// descriptors or `max_sets` descriptor sets can be allocated at once with this pool. 40 /// 41 /// If `free_descriptor_set_bit` is `true`, then individual descriptor sets can be free'd from 42 /// the pool. Otherwise you must reset or destroy the whole pool at once. 43 /// 44 /// # Panic 45 /// 46 /// - Panics if all the descriptors count are 0. 47 /// - Panics if `max_sets` is 0. 48 /// new( device: Arc<Device>, count: &DescriptorsCount, max_sets: u32, free_descriptor_set_bit: bool, ) -> Result<UnsafeDescriptorPool, OomError>49 pub fn new( 50 device: Arc<Device>, 51 count: &DescriptorsCount, 52 max_sets: u32, 53 free_descriptor_set_bit: bool, 54 ) -> Result<UnsafeDescriptorPool, OomError> { 55 let fns = device.fns(); 56 57 assert_ne!(max_sets, 0, "The maximum number of sets can't be 0"); 58 59 let mut pool_sizes: SmallVec<[_; 10]> = SmallVec::new(); 60 61 macro_rules! elem { 62 ($field:ident, $ty:expr) => { 63 if count.$field >= 1 { 64 pool_sizes.push(ash::vk::DescriptorPoolSize { 65 ty: $ty, 66 descriptor_count: count.$field, 67 }); 68 } 69 }; 70 } 71 72 elem!(uniform_buffer, ash::vk::DescriptorType::UNIFORM_BUFFER); 73 elem!(storage_buffer, ash::vk::DescriptorType::STORAGE_BUFFER); 74 elem!( 75 uniform_buffer_dynamic, 76 ash::vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC 77 ); 78 elem!( 79 storage_buffer_dynamic, 80 ash::vk::DescriptorType::STORAGE_BUFFER_DYNAMIC 81 ); 82 elem!( 83 uniform_texel_buffer, 84 ash::vk::DescriptorType::UNIFORM_TEXEL_BUFFER 85 ); 86 elem!( 87 storage_texel_buffer, 88 ash::vk::DescriptorType::STORAGE_TEXEL_BUFFER 89 ); 90 elem!(sampled_image, ash::vk::DescriptorType::SAMPLED_IMAGE); 91 elem!(storage_image, ash::vk::DescriptorType::STORAGE_IMAGE); 92 elem!(sampler, ash::vk::DescriptorType::SAMPLER); 93 elem!( 94 combined_image_sampler, 95 ash::vk::DescriptorType::COMBINED_IMAGE_SAMPLER 96 ); 97 elem!(input_attachment, ash::vk::DescriptorType::INPUT_ATTACHMENT); 98 99 assert!( 100 !pool_sizes.is_empty(), 101 "All the descriptors count of a pool are 0" 102 ); 103 104 let pool = unsafe { 105 let infos = ash::vk::DescriptorPoolCreateInfo { 106 flags: if free_descriptor_set_bit { 107 ash::vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET 108 } else { 109 ash::vk::DescriptorPoolCreateFlags::empty() 110 }, 111 max_sets: max_sets, 112 pool_size_count: pool_sizes.len() as u32, 113 p_pool_sizes: pool_sizes.as_ptr(), 114 ..Default::default() 115 }; 116 117 let mut output = MaybeUninit::uninit(); 118 check_errors(fns.v1_0.create_descriptor_pool( 119 device.internal_object(), 120 &infos, 121 ptr::null(), 122 output.as_mut_ptr(), 123 ))?; 124 output.assume_init() 125 }; 126 127 Ok(UnsafeDescriptorPool { 128 pool, 129 device: device.clone(), 130 }) 131 } 132 133 /// Allocates descriptor sets from the pool, one for each layout. 134 /// Returns an iterator to the allocated sets, or an error. 135 /// 136 /// The `FragmentedPool` errors often can't be prevented. If the function returns this error, 137 /// you should just create a new pool. 138 /// 139 /// # Panic 140 /// 141 /// - Panics if one of the layouts wasn't created with the same device as the pool. 142 /// 143 /// # Safety 144 /// 145 /// See also the `new` function. 146 /// 147 /// - The total descriptors of the layouts must fit in the pool. 148 /// - The total number of descriptor sets allocated from the pool must not overflow the pool. 149 /// - You must ensure that the allocated descriptor sets are no longer in use when the pool 150 /// is destroyed, as destroying the pool is equivalent to freeing all the sets. 151 /// 152 #[inline] alloc<'l, I>( &mut self, layouts: I, ) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError> where I: IntoIterator<Item = &'l DescriptorSetLayout>,153 pub unsafe fn alloc<'l, I>( 154 &mut self, 155 layouts: I, 156 ) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError> 157 where 158 I: IntoIterator<Item = &'l DescriptorSetLayout>, 159 { 160 let layouts: SmallVec<[_; 8]> = layouts 161 .into_iter() 162 .map(|l| { 163 assert_eq!( 164 self.device.internal_object(), 165 l.device().internal_object(), 166 "Tried to allocate from a pool with a set layout of a different \ 167 device" 168 ); 169 l.internal_object() 170 }) 171 .collect(); 172 173 self.alloc_impl(&layouts) 174 } 175 176 // Actual implementation of `alloc`. Separated so that it is not inlined. alloc_impl( &mut self, layouts: &SmallVec<[ash::vk::DescriptorSetLayout; 8]>, ) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError>177 unsafe fn alloc_impl( 178 &mut self, 179 layouts: &SmallVec<[ash::vk::DescriptorSetLayout; 8]>, 180 ) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError> { 181 let num = layouts.len(); 182 183 if num == 0 { 184 return Ok(UnsafeDescriptorPoolAllocIter { 185 sets: vec![].into_iter(), 186 }); 187 } 188 189 let infos = ash::vk::DescriptorSetAllocateInfo { 190 descriptor_pool: self.pool, 191 descriptor_set_count: layouts.len() as u32, 192 p_set_layouts: layouts.as_ptr(), 193 ..Default::default() 194 }; 195 196 let mut output = Vec::with_capacity(num); 197 198 let fns = self.device.fns(); 199 let ret = fns.v1_0.allocate_descriptor_sets( 200 self.device.internal_object(), 201 &infos, 202 output.as_mut_ptr(), 203 ); 204 205 // According to the specs, because `VK_ERROR_FRAGMENTED_POOL` was added after version 206 // 1.0 of Vulkan, any negative return value except out-of-memory errors must be 207 // considered as a fragmented pool error. 208 match ret { 209 ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY => { 210 return Err(DescriptorPoolAllocError::OutOfHostMemory); 211 } 212 ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => { 213 return Err(DescriptorPoolAllocError::OutOfDeviceMemory); 214 } 215 ash::vk::Result::ERROR_OUT_OF_POOL_MEMORY_KHR => { 216 return Err(DescriptorPoolAllocError::OutOfPoolMemory); 217 } 218 c if c.as_raw() < 0 => { 219 return Err(DescriptorPoolAllocError::FragmentedPool); 220 } 221 _ => (), 222 }; 223 224 output.set_len(num); 225 226 Ok(UnsafeDescriptorPoolAllocIter { 227 sets: output.into_iter(), 228 }) 229 } 230 231 /// Frees some descriptor sets. 232 /// 233 /// Note that it is not mandatory to free sets. Destroying or resetting the pool destroys all 234 /// the descriptor sets. 235 /// 236 /// # Safety 237 /// 238 /// - The pool must have been created with `free_descriptor_set_bit` set to `true`. 239 /// - The descriptor sets must have been allocated from the pool. 240 /// - The descriptor sets must not be free'd twice. 241 /// - The descriptor sets must not be in use by the GPU. 242 /// 243 #[inline] free<I>(&mut self, descriptor_sets: I) -> Result<(), OomError> where I: IntoIterator<Item = UnsafeDescriptorSet>,244 pub unsafe fn free<I>(&mut self, descriptor_sets: I) -> Result<(), OomError> 245 where 246 I: IntoIterator<Item = UnsafeDescriptorSet>, 247 { 248 let sets: SmallVec<[_; 8]> = descriptor_sets 249 .into_iter() 250 .map(|s| s.internal_object()) 251 .collect(); 252 if !sets.is_empty() { 253 self.free_impl(&sets) 254 } else { 255 Ok(()) 256 } 257 } 258 259 // Actual implementation of `free`. Separated so that it is not inlined. free_impl( &mut self, sets: &SmallVec<[ash::vk::DescriptorSet; 8]>, ) -> Result<(), OomError>260 unsafe fn free_impl( 261 &mut self, 262 sets: &SmallVec<[ash::vk::DescriptorSet; 8]>, 263 ) -> Result<(), OomError> { 264 let fns = self.device.fns(); 265 check_errors(fns.v1_0.free_descriptor_sets( 266 self.device.internal_object(), 267 self.pool, 268 sets.len() as u32, 269 sets.as_ptr(), 270 ))?; 271 Ok(()) 272 } 273 274 /// Resets the pool. 275 /// 276 /// This destroys all descriptor sets and empties the pool. reset(&mut self) -> Result<(), OomError>277 pub unsafe fn reset(&mut self) -> Result<(), OomError> { 278 let fns = self.device.fns(); 279 check_errors(fns.v1_0.reset_descriptor_pool( 280 self.device.internal_object(), 281 self.pool, 282 ash::vk::DescriptorPoolResetFlags::empty(), 283 ))?; 284 Ok(()) 285 } 286 } 287 288 unsafe impl DeviceOwned for UnsafeDescriptorPool { 289 #[inline] device(&self) -> &Arc<Device>290 fn device(&self) -> &Arc<Device> { 291 &self.device 292 } 293 } 294 295 impl fmt::Debug for UnsafeDescriptorPool { fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>296 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 297 fmt.debug_struct("UnsafeDescriptorPool") 298 .field("raw", &self.pool) 299 .field("device", &self.device) 300 .finish() 301 } 302 } 303 304 impl Drop for UnsafeDescriptorPool { 305 #[inline] drop(&mut self)306 fn drop(&mut self) { 307 unsafe { 308 let fns = self.device.fns(); 309 fns.v1_0 310 .destroy_descriptor_pool(self.device.internal_object(), self.pool, ptr::null()); 311 } 312 } 313 } 314 315 /// Error that can be returned when creating a device. 316 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 317 pub enum DescriptorPoolAllocError { 318 /// There is no memory available on the host (ie. the CPU, RAM, etc.). 319 OutOfHostMemory, 320 /// There is no memory available on the device (ie. video memory). 321 OutOfDeviceMemory, 322 /// Allocation has failed because the pool is too fragmented. 323 FragmentedPool, 324 /// There is no more space available in the descriptor pool. 325 OutOfPoolMemory, 326 } 327 328 impl error::Error for DescriptorPoolAllocError {} 329 330 impl fmt::Display for DescriptorPoolAllocError { 331 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>332 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 333 write!( 334 fmt, 335 "{}", 336 match *self { 337 DescriptorPoolAllocError::OutOfHostMemory => "no memory available on the host", 338 DescriptorPoolAllocError::OutOfDeviceMemory => { 339 "no memory available on the graphical device" 340 } 341 DescriptorPoolAllocError::FragmentedPool => { 342 "allocation has failed because the pool is too fragmented" 343 } 344 DescriptorPoolAllocError::OutOfPoolMemory => { 345 "there is no more space available in the descriptor pool" 346 } 347 } 348 ) 349 } 350 } 351 352 /// Iterator to the descriptor sets allocated from an unsafe descriptor pool. 353 #[derive(Debug)] 354 pub struct UnsafeDescriptorPoolAllocIter { 355 sets: VecIntoIter<ash::vk::DescriptorSet>, 356 } 357 358 impl Iterator for UnsafeDescriptorPoolAllocIter { 359 type Item = UnsafeDescriptorSet; 360 361 #[inline] next(&mut self) -> Option<UnsafeDescriptorSet>362 fn next(&mut self) -> Option<UnsafeDescriptorSet> { 363 self.sets.next().map(|s| UnsafeDescriptorSet { set: s }) 364 } 365 366 #[inline] size_hint(&self) -> (usize, Option<usize>)367 fn size_hint(&self) -> (usize, Option<usize>) { 368 self.sets.size_hint() 369 } 370 } 371 372 impl ExactSizeIterator for UnsafeDescriptorPoolAllocIter {} 373 374 #[cfg(test)] 375 mod tests { 376 use crate::descriptor_set::layout::DescriptorBufferDesc; 377 use crate::descriptor_set::layout::DescriptorDesc; 378 use crate::descriptor_set::layout::DescriptorDescTy; 379 use crate::descriptor_set::layout::DescriptorSetDesc; 380 use crate::descriptor_set::layout::DescriptorSetLayout; 381 use crate::descriptor_set::pool::DescriptorsCount; 382 use crate::descriptor_set::pool::UnsafeDescriptorPool; 383 use crate::pipeline::shader::ShaderStages; 384 use std::iter; 385 386 #[test] pool_create()387 fn pool_create() { 388 let (device, _) = gfx_dev_and_queue!(); 389 let desc = DescriptorsCount { 390 uniform_buffer: 1, 391 ..DescriptorsCount::zero() 392 }; 393 394 let _ = UnsafeDescriptorPool::new(device, &desc, 10, false).unwrap(); 395 } 396 397 #[test] zero_max_set()398 fn zero_max_set() { 399 let (device, _) = gfx_dev_and_queue!(); 400 let desc = DescriptorsCount { 401 uniform_buffer: 1, 402 ..DescriptorsCount::zero() 403 }; 404 405 assert_should_panic!("The maximum number of sets can't be 0", { 406 let _ = UnsafeDescriptorPool::new(device, &desc, 0, false); 407 }); 408 } 409 410 #[test] zero_descriptors()411 fn zero_descriptors() { 412 let (device, _) = gfx_dev_and_queue!(); 413 414 assert_should_panic!("All the descriptors count of a pool are 0", { 415 let _ = UnsafeDescriptorPool::new(device, &DescriptorsCount::zero(), 10, false); 416 }); 417 } 418 419 #[test] basic_alloc()420 fn basic_alloc() { 421 let (device, _) = gfx_dev_and_queue!(); 422 423 let layout = DescriptorDesc { 424 ty: DescriptorDescTy::Buffer(DescriptorBufferDesc { 425 dynamic: Some(false), 426 storage: false, 427 }), 428 array_count: 1, 429 stages: ShaderStages::all_graphics(), 430 readonly: true, 431 }; 432 433 let set_layout = DescriptorSetLayout::new( 434 device.clone(), 435 DescriptorSetDesc::new(iter::once(Some(layout))), 436 ) 437 .unwrap(); 438 439 let desc = DescriptorsCount { 440 uniform_buffer: 10, 441 ..DescriptorsCount::zero() 442 }; 443 444 let mut pool = UnsafeDescriptorPool::new(device, &desc, 10, false).unwrap(); 445 unsafe { 446 let sets = pool.alloc(iter::once(&set_layout)).unwrap(); 447 assert_eq!(sets.count(), 1); 448 } 449 } 450 451 #[test] alloc_diff_device()452 fn alloc_diff_device() { 453 let (device1, _) = gfx_dev_and_queue!(); 454 let (device2, _) = gfx_dev_and_queue!(); 455 456 let layout = DescriptorDesc { 457 ty: DescriptorDescTy::Buffer(DescriptorBufferDesc { 458 dynamic: Some(false), 459 storage: false, 460 }), 461 array_count: 1, 462 stages: ShaderStages::all_graphics(), 463 readonly: true, 464 }; 465 466 let set_layout = 467 DescriptorSetLayout::new(device1, DescriptorSetDesc::new(iter::once(Some(layout)))) 468 .unwrap(); 469 470 let desc = DescriptorsCount { 471 uniform_buffer: 10, 472 ..DescriptorsCount::zero() 473 }; 474 475 assert_should_panic!( 476 "Tried to allocate from a pool with a set layout \ 477 of a different device", 478 { 479 let mut pool = UnsafeDescriptorPool::new(device2, &desc, 10, false).unwrap(); 480 481 unsafe { 482 let _ = pool.alloc(iter::once(&set_layout)); 483 } 484 } 485 ); 486 } 487 488 #[test] alloc_zero()489 fn alloc_zero() { 490 let (device, _) = gfx_dev_and_queue!(); 491 492 let desc = DescriptorsCount { 493 uniform_buffer: 1, 494 ..DescriptorsCount::zero() 495 }; 496 497 let mut pool = UnsafeDescriptorPool::new(device, &desc, 1, false).unwrap(); 498 unsafe { 499 let sets = pool.alloc(iter::empty()).unwrap(); 500 assert_eq!(sets.count(), 0); 501 } 502 } 503 } 504