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 //! Communication channel with a physical device. 11 //! 12 //! The `Device` is one of the most important objects of Vulkan. Creating a `Device` is required 13 //! before you can create buffers, textures, shaders, etc. 14 //! 15 //! Basic example: 16 //! 17 //! ```no_run 18 //! use vulkano::device::Device; 19 //! use vulkano::device::DeviceExtensions; 20 //! use vulkano::device::Features; 21 //! use vulkano::instance::Instance; 22 //! use vulkano::instance::InstanceExtensions; 23 //! use vulkano::device::physical::PhysicalDevice; 24 //! use vulkano::Version; 25 //! 26 //! // Creating the instance. See the documentation of the `instance` module. 27 //! let instance = match Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None) { 28 //! Ok(i) => i, 29 //! Err(err) => panic!("Couldn't build instance: {:?}", err) 30 //! }; 31 //! 32 //! // We just choose the first physical device. In a real application you would choose depending 33 //! // on the capabilities of the physical device and the user's preferences. 34 //! let physical_device = PhysicalDevice::enumerate(&instance).next().expect("No physical device"); 35 //! 36 //! // Here is the device-creating code. 37 //! let device = { 38 //! let queue_family = physical_device.queue_families().next().unwrap(); 39 //! let features = Features::none(); 40 //! let ext = DeviceExtensions::none(); 41 //! 42 //! match Device::new(physical_device, &features, &ext, Some((queue_family, 1.0))) { 43 //! Ok(d) => d, 44 //! Err(err) => panic!("Couldn't build device: {:?}", err) 45 //! } 46 //! }; 47 //! ``` 48 //! 49 //! # Features and extensions 50 //! 51 //! Two of the parameters that you pass to `Device::new` are the list of the features and the list 52 //! of extensions to enable on the newly-created device. 53 //! 54 //! > **Note**: Device extensions are the same as instance extensions, except for the device. 55 //! > Features are similar to extensions, except that they are part of the core Vulkan 56 //! > specifications instead of being separate documents. 57 //! 58 //! Some Vulkan capabilities, such as swapchains (that allow you to render on the screen) or 59 //! geometry shaders for example, require that you enable a certain feature or extension when you 60 //! create the device. Contrary to OpenGL, you can't use the functions provided by a feature or an 61 //! extension if you didn't explicitly enable it when creating the device. 62 //! 63 //! Not all physical devices support all possible features and extensions. For example mobile 64 //! devices tend to not support geometry shaders, because their hardware is not capable of it. You 65 //! can query what is supported with respectively `PhysicalDevice::supported_features` and 66 //! `DeviceExtensions::supported_by_device`. 67 //! 68 //! > **Note**: The fact that you need to manually enable features at initialization also means 69 //! > that you don't need to worry about a capability not being supported later on in your code. 70 //! 71 //! # Queues 72 //! 73 //! Each physical device proposes one or more *queues* that are divided in *queue families*. A 74 //! queue is a thread of execution to which you can submit commands that the GPU will execute. 75 //! 76 //! > **Note**: You can think of a queue like a CPU thread. Each queue executes its commands one 77 //! > after the other, and queues run concurrently. A GPU behaves similarly to the hyper-threading 78 //! > technology, in the sense that queues will only run partially in parallel. 79 //! 80 //! The Vulkan API requires that you specify the list of queues that you are going to use at the 81 //! same time as when you create the device. This is done in vulkano by passing an iterator where 82 //! each element is a tuple containing a queue family and a number between 0.0 and 1.0 indicating 83 //! the priority of execution of the queue relative to the others. 84 //! 85 //! TODO: write better doc here 86 //! 87 //! The `Device::new` function returns the newly-created device, but also the list of queues. 88 //! 89 //! # Extended example 90 //! 91 //! TODO: write 92 93 pub(crate) use self::features::FeaturesFfi; 94 pub use self::features::{FeatureRestriction, FeatureRestrictionError, Features}; 95 pub use self::properties::Properties; 96 pub(crate) use self::properties::PropertiesFfi; 97 pub use crate::autogen::DeviceExtensions; 98 use crate::check_errors; 99 use crate::command_buffer::pool::StandardCommandPool; 100 use crate::descriptor_set::pool::StdDescriptorPool; 101 use crate::device::physical::PhysicalDevice; 102 use crate::device::physical::QueueFamily; 103 pub use crate::extensions::{ 104 ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError, 105 }; 106 use crate::fns::DeviceFunctions; 107 use crate::format::Format; 108 use crate::image::ImageCreateFlags; 109 use crate::image::ImageFormatProperties; 110 use crate::image::ImageTiling; 111 use crate::image::ImageType; 112 use crate::image::ImageUsage; 113 use crate::instance::Instance; 114 use crate::memory::pool::StdMemoryPool; 115 use crate::Error; 116 use crate::OomError; 117 use crate::SynchronizedVulkanObject; 118 use crate::Version; 119 use crate::VulkanObject; 120 use ash::vk::Handle; 121 use fnv::FnvHasher; 122 use smallvec::SmallVec; 123 use std::collections::hash_map::Entry; 124 use std::collections::HashMap; 125 use std::error; 126 use std::ffi::CStr; 127 use std::ffi::CString; 128 use std::fmt; 129 use std::hash::BuildHasherDefault; 130 use std::hash::Hash; 131 use std::hash::Hasher; 132 use std::mem; 133 use std::mem::MaybeUninit; 134 use std::ops::Deref; 135 use std::ptr; 136 use std::sync::Arc; 137 use std::sync::Mutex; 138 use std::sync::MutexGuard; 139 use std::sync::Weak; 140 141 pub(crate) mod extensions; 142 pub(crate) mod features; 143 pub mod physical; 144 pub(crate) mod properties; 145 146 /// Represents a Vulkan context. 147 pub struct Device { 148 instance: Arc<Instance>, 149 physical_device: usize, 150 device: ash::vk::Device, 151 152 // The highest version that is supported for this device. 153 // This is the minimum of Instance::max_api_version and PhysicalDevice::api_version. 154 api_version: Version, 155 156 fns: DeviceFunctions, 157 standard_pool: Mutex<Weak<StdMemoryPool>>, 158 standard_descriptor_pool: Mutex<Weak<StdDescriptorPool>>, 159 standard_command_pools: 160 Mutex<HashMap<u32, Weak<StandardCommandPool>, BuildHasherDefault<FnvHasher>>>, 161 features: Features, 162 extensions: DeviceExtensions, 163 active_queue_families: SmallVec<[u32; 8]>, 164 allocation_count: Mutex<u32>, 165 fence_pool: Mutex<Vec<ash::vk::Fence>>, 166 semaphore_pool: Mutex<Vec<ash::vk::Semaphore>>, 167 event_pool: Mutex<Vec<ash::vk::Event>>, 168 } 169 170 // The `StandardCommandPool` type doesn't implement Send/Sync, so we have to manually reimplement 171 // them for the device itself. 172 unsafe impl Send for Device {} 173 unsafe impl Sync for Device {} 174 175 impl Device { 176 /// Builds a new Vulkan device for the given physical device. 177 /// 178 /// You must pass two things when creating a logical device: 179 /// 180 /// - A list of optional Vulkan features that must be enabled on the device. Note that if a 181 /// feature is not enabled at device creation, you can't use it later even it it's supported 182 /// by the physical device. 183 /// 184 /// - An iterator to a list of queues to create. Each element of the iterator must indicate 185 /// the family whose queue belongs to and a priority between 0.0 and 1.0 to assign to it. 186 /// A queue with a higher value indicates that the commands will execute faster than on a 187 /// queue with a lower value. Note however that no guarantee can be made on the way the 188 /// priority value is handled by the implementation. 189 /// 190 /// # Panic 191 /// 192 /// - Panics if one of the queue families doesn't belong to the given device. 193 /// 194 // TODO: return Arc<Queue> and handle synchronization in the Queue 195 // TODO: should take the PhysicalDevice by value new<'a, I>( physical_device: PhysicalDevice, requested_features: &Features, requested_extensions: &DeviceExtensions, queue_families: I, ) -> Result<(Arc<Device>, QueuesIter), DeviceCreationError> where I: IntoIterator<Item = (QueueFamily<'a>, f32)>,196 pub fn new<'a, I>( 197 physical_device: PhysicalDevice, 198 requested_features: &Features, 199 requested_extensions: &DeviceExtensions, 200 queue_families: I, 201 ) -> Result<(Arc<Device>, QueuesIter), DeviceCreationError> 202 where 203 I: IntoIterator<Item = (QueueFamily<'a>, f32)>, 204 { 205 let instance = physical_device.instance(); 206 let fns_i = instance.fns(); 207 let api_version = physical_device.api_version(); 208 209 // Check if the extensions are correct 210 requested_extensions.check_requirements( 211 physical_device.supported_extensions(), 212 api_version, 213 instance.enabled_extensions(), 214 )?; 215 216 let mut requested_features = requested_features.clone(); 217 218 // TODO: The plan regarding `robust_buffer_access` is to check the shaders' code to see 219 // if they can possibly perform out-of-bounds reads and writes. If the user tries 220 // to use a shader that can perform out-of-bounds operations without having 221 // `robust_buffer_access` enabled, an error is returned. 222 // 223 // However for the moment this verification isn't performed. In order to be safe, 224 // we always enable the `robust_buffer_access` feature as it is guaranteed to be 225 // supported everywhere. 226 // 227 // The only alternative (while waiting for shaders introspection to work) is to 228 // make all shaders depend on `robust_buffer_access`. But since usually the 229 // majority of shaders don't need this feature, it would be very annoying to have 230 // to enable it manually when you don't need it. 231 // 232 // Note that if we ever remove this, don't forget to adjust the change in 233 // `Device`'s construction below. 234 requested_features.robust_buffer_access = true; 235 236 // Check if the features are correct 237 requested_features.check_requirements( 238 physical_device.supported_features(), 239 api_version, 240 requested_extensions, 241 )?; 242 243 // device creation 244 let (device, queues) = unsafe { 245 // each element of `queues` is a `(queue_family, priorities)` 246 // each queue family must only have one entry in `queues` 247 let mut queues: Vec<(u32, Vec<f32>)> = 248 Vec::with_capacity(physical_device.queue_families().len()); 249 250 // this variable will contain the queue family ID and queue ID of each requested queue 251 let mut output_queues: SmallVec<[(u32, u32); 8]> = SmallVec::new(); 252 253 for (queue_family, priority) in queue_families { 254 // checking the parameters 255 assert_eq!( 256 queue_family.physical_device().internal_object(), 257 physical_device.internal_object() 258 ); 259 if priority < 0.0 || priority > 1.0 { 260 return Err(DeviceCreationError::PriorityOutOfRange); 261 } 262 263 // adding to `queues` and `output_queues` 264 if let Some(q) = queues.iter_mut().find(|q| q.0 == queue_family.id()) { 265 output_queues.push((queue_family.id(), q.1.len() as u32)); 266 q.1.push(priority); 267 if q.1.len() > queue_family.queues_count() { 268 return Err(DeviceCreationError::TooManyQueuesForFamily); 269 } 270 continue; 271 } 272 queues.push((queue_family.id(), vec![priority])); 273 output_queues.push((queue_family.id(), 0)); 274 } 275 276 // turning `queues` into an array of `vkDeviceQueueCreateInfo` suitable for Vulkan 277 let queues = queues 278 .iter() 279 .map( 280 |&(queue_id, ref priorities)| ash::vk::DeviceQueueCreateInfo { 281 flags: ash::vk::DeviceQueueCreateFlags::empty(), 282 queue_family_index: queue_id, 283 queue_count: priorities.len() as u32, 284 p_queue_priorities: priorities.as_ptr(), 285 ..Default::default() 286 }, 287 ) 288 .collect::<SmallVec<[_; 16]>>(); 289 290 let mut features_ffi = FeaturesFfi::default(); 291 features_ffi.make_chain( 292 api_version, 293 requested_extensions, 294 instance.enabled_extensions(), 295 ); 296 features_ffi.write(&requested_features); 297 298 // Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be 299 // ignored by the driver. For backwards compatibility, the spec recommends passing the 300 // exact instance layers to the device as well. There's no need to support separate 301 // requests at device creation time for legacy drivers: the spec claims that "[at] the 302 // time of deprecation there were no known device-only layers." 303 // 304 // Because there's no way to query the list of layers enabled for an instance, we need 305 // to save it alongside the instance. (`vkEnumerateDeviceLayerProperties` should get 306 // the right list post-1.0.13, but not pre-1.0.13, so we can't use it here.) 307 let layers_ptrs = instance 308 .enabled_layers() 309 .map(|layer| layer.as_ptr()) 310 .collect::<SmallVec<[_; 16]>>(); 311 312 let extensions_strings: Vec<CString> = requested_extensions.into(); 313 let extensions_ptrs = extensions_strings 314 .iter() 315 .map(|extension| extension.as_ptr()) 316 .collect::<SmallVec<[_; 16]>>(); 317 318 let has_khr_get_physical_device_properties2 = instance 319 .enabled_extensions() 320 .khr_get_physical_device_properties2; 321 322 let infos = ash::vk::DeviceCreateInfo { 323 p_next: if has_khr_get_physical_device_properties2 { 324 features_ffi.head_as_ref() as *const _ as _ 325 } else { 326 ptr::null() 327 }, 328 flags: ash::vk::DeviceCreateFlags::empty(), 329 queue_create_info_count: queues.len() as u32, 330 p_queue_create_infos: queues.as_ptr(), 331 enabled_layer_count: layers_ptrs.len() as u32, 332 pp_enabled_layer_names: layers_ptrs.as_ptr(), 333 enabled_extension_count: extensions_ptrs.len() as u32, 334 pp_enabled_extension_names: extensions_ptrs.as_ptr(), 335 p_enabled_features: if has_khr_get_physical_device_properties2 { 336 ptr::null() 337 } else { 338 &features_ffi.head_as_ref().features 339 }, 340 ..Default::default() 341 }; 342 343 let mut output = MaybeUninit::uninit(); 344 check_errors(fns_i.v1_0.create_device( 345 physical_device.internal_object(), 346 &infos, 347 ptr::null(), 348 output.as_mut_ptr(), 349 ))?; 350 351 (output.assume_init(), output_queues) 352 }; 353 354 // loading the function pointers of the newly-created device 355 let fns = DeviceFunctions::load(|name| unsafe { 356 mem::transmute(fns_i.v1_0.get_device_proc_addr(device, name.as_ptr())) 357 }); 358 359 let mut active_queue_families: SmallVec<[u32; 8]> = SmallVec::new(); 360 for (queue_family, _) in queues.iter() { 361 if let None = active_queue_families 362 .iter() 363 .find(|&&qf| qf == *queue_family) 364 { 365 active_queue_families.push(*queue_family); 366 } 367 } 368 369 let device = Arc::new(Device { 370 instance: physical_device.instance().clone(), 371 physical_device: physical_device.index(), 372 device: device, 373 api_version, 374 fns, 375 standard_pool: Mutex::new(Weak::new()), 376 standard_descriptor_pool: Mutex::new(Weak::new()), 377 standard_command_pools: Mutex::new(Default::default()), 378 features: Features { 379 // Always enabled ; see above 380 robust_buffer_access: true, 381 ..requested_features.clone() 382 }, 383 extensions: requested_extensions.clone(), 384 active_queue_families, 385 allocation_count: Mutex::new(0), 386 fence_pool: Mutex::new(Vec::new()), 387 semaphore_pool: Mutex::new(Vec::new()), 388 event_pool: Mutex::new(Vec::new()), 389 }); 390 391 // Iterator for the produced queues. 392 let queues = QueuesIter { 393 next_queue: 0, 394 device: device.clone(), 395 families_and_ids: queues, 396 }; 397 398 Ok((device, queues)) 399 } 400 401 /// Returns the Vulkan version supported by the device. 402 /// 403 /// This is the lower of the 404 /// [physical device's supported version](crate::instance::PhysicalDevice::api_version) and 405 /// the instance's [`max_api_version`](crate::instance::Instance::max_api_version). 406 #[inline] api_version(&self) -> Version407 pub fn api_version(&self) -> Version { 408 self.api_version 409 } 410 411 /// Grants access to the Vulkan functions of the device. 412 #[inline] fns(&self) -> &DeviceFunctions413 pub fn fns(&self) -> &DeviceFunctions { 414 &self.fns 415 } 416 417 /// Waits until all work on this device has finished. You should never need to call 418 /// this function, but it can be useful for debugging or benchmarking purposes. 419 /// 420 /// > **Note**: This is the Vulkan equivalent of OpenGL's `glFinish`. 421 /// 422 /// # Safety 423 /// 424 /// This function is not thread-safe. You must not submit anything to any of the queue 425 /// of the device (either explicitly or implicitly, for example with a future's destructor) 426 /// while this function is waiting. 427 /// wait(&self) -> Result<(), OomError>428 pub unsafe fn wait(&self) -> Result<(), OomError> { 429 check_errors(self.fns.v1_0.device_wait_idle(self.device))?; 430 Ok(()) 431 } 432 433 /// Returns the instance used to create this device. 434 #[inline] instance(&self) -> &Arc<Instance>435 pub fn instance(&self) -> &Arc<Instance> { 436 &self.instance 437 } 438 439 /// Returns the physical device that was used to create this device. 440 #[inline] physical_device(&self) -> PhysicalDevice441 pub fn physical_device(&self) -> PhysicalDevice { 442 PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap() 443 } 444 445 /// Returns an iterator to the list of queues families that this device uses. 446 /// 447 /// > **Note**: Will return `-> impl ExactSizeIterator<Item = QueueFamily>` in the future. 448 // TODO: ^ 449 #[inline] active_queue_families<'a>( &'a self, ) -> Box<dyn ExactSizeIterator<Item = QueueFamily<'a>> + 'a>450 pub fn active_queue_families<'a>( 451 &'a self, 452 ) -> Box<dyn ExactSizeIterator<Item = QueueFamily<'a>> + 'a> { 453 let physical_device = self.physical_device(); 454 Box::new( 455 self.active_queue_families 456 .iter() 457 .map(move |&id| physical_device.queue_family_by_id(id).unwrap()), 458 ) 459 } 460 461 /// Returns the features that have been enabled on the device. 462 #[inline] enabled_features(&self) -> &Features463 pub fn enabled_features(&self) -> &Features { 464 &self.features 465 } 466 467 /// Returns the extensions that have been enabled on the device. 468 #[inline] enabled_extensions(&self) -> &DeviceExtensions469 pub fn enabled_extensions(&self) -> &DeviceExtensions { 470 &self.extensions 471 } 472 473 /// Returns the standard memory pool used by default if you don't provide any other pool. standard_pool(me: &Arc<Self>) -> Arc<StdMemoryPool>474 pub fn standard_pool(me: &Arc<Self>) -> Arc<StdMemoryPool> { 475 let mut pool = me.standard_pool.lock().unwrap(); 476 477 if let Some(p) = pool.upgrade() { 478 return p; 479 } 480 481 // The weak pointer is empty, so we create the pool. 482 let new_pool = StdMemoryPool::new(me.clone()); 483 *pool = Arc::downgrade(&new_pool); 484 new_pool 485 } 486 487 /// Returns the standard descriptor pool used by default if you don't provide any other pool. standard_descriptor_pool(me: &Arc<Self>) -> Arc<StdDescriptorPool>488 pub fn standard_descriptor_pool(me: &Arc<Self>) -> Arc<StdDescriptorPool> { 489 let mut pool = me.standard_descriptor_pool.lock().unwrap(); 490 491 if let Some(p) = pool.upgrade() { 492 return p; 493 } 494 495 // The weak pointer is empty, so we create the pool. 496 let new_pool = Arc::new(StdDescriptorPool::new(me.clone())); 497 *pool = Arc::downgrade(&new_pool); 498 new_pool 499 } 500 501 /// Returns the standard command buffer pool used by default if you don't provide any other 502 /// pool. 503 /// 504 /// # Panic 505 /// 506 /// - Panics if the device and the queue family don't belong to the same physical device. 507 /// standard_command_pool(me: &Arc<Self>, queue: QueueFamily) -> Arc<StandardCommandPool>508 pub fn standard_command_pool(me: &Arc<Self>, queue: QueueFamily) -> Arc<StandardCommandPool> { 509 let mut standard_command_pools = me.standard_command_pools.lock().unwrap(); 510 511 match standard_command_pools.entry(queue.id()) { 512 Entry::Occupied(mut entry) => { 513 if let Some(pool) = entry.get().upgrade() { 514 return pool; 515 } 516 517 let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue)); 518 *entry.get_mut() = Arc::downgrade(&new_pool); 519 new_pool 520 } 521 Entry::Vacant(entry) => { 522 let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue)); 523 entry.insert(Arc::downgrade(&new_pool)); 524 new_pool 525 } 526 } 527 } 528 529 /// Used to track the number of allocations on this device. 530 /// 531 /// To ensure valid usage of the Vulkan API, we cannot call `vkAllocateMemory` when 532 /// `maxMemoryAllocationCount` has been exceeded. See the Vulkan specs: 533 /// https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#vkAllocateMemory 534 /// 535 /// Warning: You should never modify this value, except in `device_memory` module allocation_count(&self) -> &Mutex<u32>536 pub(crate) fn allocation_count(&self) -> &Mutex<u32> { 537 &self.allocation_count 538 } 539 fence_pool(&self) -> &Mutex<Vec<ash::vk::Fence>>540 pub(crate) fn fence_pool(&self) -> &Mutex<Vec<ash::vk::Fence>> { 541 &self.fence_pool 542 } 543 semaphore_pool(&self) -> &Mutex<Vec<ash::vk::Semaphore>>544 pub(crate) fn semaphore_pool(&self) -> &Mutex<Vec<ash::vk::Semaphore>> { 545 &self.semaphore_pool 546 } 547 event_pool(&self) -> &Mutex<Vec<ash::vk::Event>>548 pub(crate) fn event_pool(&self) -> &Mutex<Vec<ash::vk::Event>> { 549 &self.event_pool 550 } 551 552 /// Assigns a human-readable name to `object` for debugging purposes. 553 /// 554 /// # Panics 555 /// * If `object` is not owned by this device. set_object_name<T: VulkanObject + DeviceOwned>( &self, object: &T, name: &CStr, ) -> Result<(), OomError>556 pub fn set_object_name<T: VulkanObject + DeviceOwned>( 557 &self, 558 object: &T, 559 name: &CStr, 560 ) -> Result<(), OomError> { 561 assert!(object.device().internal_object() == self.internal_object()); 562 unsafe { 563 self.set_object_name_raw(T::Object::TYPE, object.internal_object().as_raw(), name) 564 } 565 } 566 567 /// Assigns a human-readable name to `object` for debugging purposes. 568 /// 569 /// # Safety 570 /// `object` must be a Vulkan handle owned by this device, and its type must be accurately described by `ty`. set_object_name_raw( &self, ty: ash::vk::ObjectType, object: u64, name: &CStr, ) -> Result<(), OomError>571 pub unsafe fn set_object_name_raw( 572 &self, 573 ty: ash::vk::ObjectType, 574 object: u64, 575 name: &CStr, 576 ) -> Result<(), OomError> { 577 let info = ash::vk::DebugUtilsObjectNameInfoEXT { 578 object_type: ty, 579 object_handle: object, 580 p_object_name: name.as_ptr(), 581 ..Default::default() 582 }; 583 check_errors( 584 self.instance 585 .fns() 586 .ext_debug_utils 587 .set_debug_utils_object_name_ext(self.device, &info), 588 )?; 589 Ok(()) 590 } 591 592 /// Checks the given combination of image attributes/configuration for compatibility with the physical device. 593 /// 594 /// Returns a struct with additional capabilities available for this image configuration. image_format_properties( &self, format: Format, ty: ImageType, tiling: ImageTiling, usage: ImageUsage, create_flags: ImageCreateFlags, ) -> Result<ImageFormatProperties, String>595 pub fn image_format_properties( 596 &self, 597 format: Format, 598 ty: ImageType, 599 tiling: ImageTiling, 600 usage: ImageUsage, 601 create_flags: ImageCreateFlags, 602 ) -> Result<ImageFormatProperties, String> { 603 let fns_i = self.instance().fns(); 604 let mut output = MaybeUninit::uninit(); 605 let physical_device = self.physical_device().internal_object(); 606 unsafe { 607 let r = fns_i.v1_0.get_physical_device_image_format_properties( 608 physical_device, 609 format.into(), 610 ty.into(), 611 tiling.into(), 612 usage.into(), 613 create_flags.into(), 614 output.as_mut_ptr(), 615 ); 616 617 match check_errors(r) { 618 Ok(_) => Ok(output.assume_init().into()), 619 Err(e) => { 620 return Err(String::from(format!( 621 "Image properties not supported. {:#?}", 622 e 623 ))) 624 } 625 } 626 } 627 } 628 } 629 630 impl fmt::Debug for Device { 631 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>632 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 633 write!(fmt, "<Vulkan device {:?}>", self.device) 634 } 635 } 636 637 unsafe impl VulkanObject for Device { 638 type Object = ash::vk::Device; 639 640 #[inline] internal_object(&self) -> ash::vk::Device641 fn internal_object(&self) -> ash::vk::Device { 642 self.device 643 } 644 } 645 646 impl Drop for Device { 647 #[inline] drop(&mut self)648 fn drop(&mut self) { 649 unsafe { 650 for &raw_fence in self.fence_pool.lock().unwrap().iter() { 651 self.fns 652 .v1_0 653 .destroy_fence(self.device, raw_fence, ptr::null()); 654 } 655 for &raw_sem in self.semaphore_pool.lock().unwrap().iter() { 656 self.fns 657 .v1_0 658 .destroy_semaphore(self.device, raw_sem, ptr::null()); 659 } 660 for &raw_event in self.event_pool.lock().unwrap().iter() { 661 self.fns 662 .v1_0 663 .destroy_event(self.device, raw_event, ptr::null()); 664 } 665 self.fns.v1_0.destroy_device(self.device, ptr::null()); 666 } 667 } 668 } 669 670 impl PartialEq for Device { 671 #[inline] eq(&self, other: &Self) -> bool672 fn eq(&self, other: &Self) -> bool { 673 self.device == other.device && self.instance == other.instance 674 } 675 } 676 677 impl Eq for Device {} 678 679 impl Hash for Device { 680 #[inline] hash<H: Hasher>(&self, state: &mut H)681 fn hash<H: Hasher>(&self, state: &mut H) { 682 self.device.hash(state); 683 self.instance.hash(state); 684 } 685 } 686 687 /// Implemented on objects that belong to a Vulkan device. 688 /// 689 /// # Safety 690 /// 691 /// - `device()` must return the correct device. 692 /// 693 pub unsafe trait DeviceOwned { 694 /// Returns the device that owns `Self`. device(&self) -> &Arc<Device>695 fn device(&self) -> &Arc<Device>; 696 } 697 698 unsafe impl<T> DeviceOwned for T 699 where 700 T: Deref, 701 T::Target: DeviceOwned, 702 { 703 #[inline] device(&self) -> &Arc<Device>704 fn device(&self) -> &Arc<Device> { 705 (**self).device() 706 } 707 } 708 709 /// Iterator that returns the queues produced when creating a device. 710 pub struct QueuesIter { 711 next_queue: usize, 712 device: Arc<Device>, 713 families_and_ids: SmallVec<[(u32, u32); 8]>, 714 } 715 716 unsafe impl DeviceOwned for QueuesIter { device(&self) -> &Arc<Device>717 fn device(&self) -> &Arc<Device> { 718 &self.device 719 } 720 } 721 722 impl Iterator for QueuesIter { 723 type Item = Arc<Queue>; 724 next(&mut self) -> Option<Arc<Queue>>725 fn next(&mut self) -> Option<Arc<Queue>> { 726 unsafe { 727 let &(family, id) = match self.families_and_ids.get(self.next_queue) { 728 Some(a) => a, 729 None => return None, 730 }; 731 732 self.next_queue += 1; 733 734 let mut output = MaybeUninit::uninit(); 735 self.device.fns.v1_0.get_device_queue( 736 self.device.device, 737 family, 738 id, 739 output.as_mut_ptr(), 740 ); 741 742 Some(Arc::new(Queue { 743 queue: Mutex::new(output.assume_init()), 744 device: self.device.clone(), 745 family: family, 746 id: id, 747 })) 748 } 749 } 750 751 #[inline] size_hint(&self) -> (usize, Option<usize>)752 fn size_hint(&self) -> (usize, Option<usize>) { 753 let len = self.families_and_ids.len().saturating_sub(self.next_queue); 754 (len, Some(len)) 755 } 756 } 757 758 impl ExactSizeIterator for QueuesIter {} 759 760 /// Error that can be returned when creating a device. 761 #[derive(Copy, Clone, Debug)] 762 pub enum DeviceCreationError { 763 /// Failed to create the device for an implementation-specific reason. 764 InitializationFailed, 765 /// You have reached the limit to the number of devices that can be created from the same 766 /// physical device. 767 TooManyObjects, 768 /// Failed to connect to the device. 769 DeviceLost, 770 /// Some of the requested features are unsupported by the physical device. 771 FeatureNotPresent, 772 /// Some of the requested device extensions are not supported by the physical device. 773 ExtensionNotPresent, 774 /// Tried to create too many queues for a given family. 775 TooManyQueuesForFamily, 776 /// The priority of one of the queues is out of the [0.0; 1.0] range. 777 PriorityOutOfRange, 778 /// There is no memory available on the host (ie. the CPU, RAM, etc.). 779 OutOfHostMemory, 780 /// There is no memory available on the device (ie. video memory). 781 OutOfDeviceMemory, 782 /// A restriction for an extension was not met. 783 ExtensionRestrictionNotMet(ExtensionRestrictionError), 784 /// A restriction for a feature was not met. 785 FeatureRestrictionNotMet(FeatureRestrictionError), 786 } 787 788 impl error::Error for DeviceCreationError {} 789 790 impl fmt::Display for DeviceCreationError { 791 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>792 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 793 match *self { 794 DeviceCreationError::InitializationFailed => { 795 write!( 796 fmt, 797 "failed to create the device for an implementation-specific reason" 798 ) 799 } 800 DeviceCreationError::OutOfHostMemory => write!(fmt, "no memory available on the host"), 801 DeviceCreationError::OutOfDeviceMemory => { 802 write!(fmt, "no memory available on the graphical device") 803 } 804 DeviceCreationError::DeviceLost => write!(fmt, "failed to connect to the device"), 805 DeviceCreationError::TooManyQueuesForFamily => { 806 write!(fmt, "tried to create too many queues for a given family") 807 } 808 DeviceCreationError::FeatureNotPresent => { 809 write!( 810 fmt, 811 "some of the requested features are unsupported by the physical device" 812 ) 813 } 814 DeviceCreationError::PriorityOutOfRange => { 815 write!( 816 fmt, 817 "the priority of one of the queues is out of the [0.0; 1.0] range" 818 ) 819 } 820 DeviceCreationError::ExtensionNotPresent => { 821 write!(fmt,"some of the requested device extensions are not supported by the physical device") 822 } 823 DeviceCreationError::TooManyObjects => { 824 write!(fmt,"you have reached the limit to the number of devices that can be created from the same physical device") 825 } 826 DeviceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt), 827 DeviceCreationError::FeatureRestrictionNotMet(err) => err.fmt(fmt), 828 } 829 } 830 } 831 832 impl From<Error> for DeviceCreationError { 833 #[inline] from(err: Error) -> DeviceCreationError834 fn from(err: Error) -> DeviceCreationError { 835 match err { 836 Error::InitializationFailed => DeviceCreationError::InitializationFailed, 837 Error::OutOfHostMemory => DeviceCreationError::OutOfHostMemory, 838 Error::OutOfDeviceMemory => DeviceCreationError::OutOfDeviceMemory, 839 Error::DeviceLost => DeviceCreationError::DeviceLost, 840 Error::ExtensionNotPresent => DeviceCreationError::ExtensionNotPresent, 841 Error::FeatureNotPresent => DeviceCreationError::FeatureNotPresent, 842 Error::TooManyObjects => DeviceCreationError::TooManyObjects, 843 _ => panic!("Unexpected error value: {}", err as i32), 844 } 845 } 846 } 847 848 impl From<ExtensionRestrictionError> for DeviceCreationError { 849 #[inline] from(err: ExtensionRestrictionError) -> Self850 fn from(err: ExtensionRestrictionError) -> Self { 851 Self::ExtensionRestrictionNotMet(err) 852 } 853 } 854 855 impl From<FeatureRestrictionError> for DeviceCreationError { 856 #[inline] from(err: FeatureRestrictionError) -> Self857 fn from(err: FeatureRestrictionError) -> Self { 858 Self::FeatureRestrictionNotMet(err) 859 } 860 } 861 862 /// Represents a queue where commands can be submitted. 863 // TODO: should use internal synchronization? 864 #[derive(Debug)] 865 pub struct Queue { 866 queue: Mutex<ash::vk::Queue>, 867 device: Arc<Device>, 868 family: u32, 869 id: u32, // id within family 870 } 871 872 impl Queue { 873 /// Returns the device this queue belongs to. 874 #[inline] device(&self) -> &Arc<Device>875 pub fn device(&self) -> &Arc<Device> { 876 &self.device 877 } 878 879 /// Returns true if this is the same queue as another one. 880 #[inline] is_same(&self, other: &Queue) -> bool881 pub fn is_same(&self, other: &Queue) -> bool { 882 self.id == other.id 883 && self.family == other.family 884 && self.device.internal_object() == other.device.internal_object() 885 } 886 887 /// Returns the family this queue belongs to. 888 #[inline] family(&self) -> QueueFamily889 pub fn family(&self) -> QueueFamily { 890 self.device 891 .physical_device() 892 .queue_family_by_id(self.family) 893 .unwrap() 894 } 895 896 /// Returns the index of this queue within its family. 897 #[inline] id_within_family(&self) -> u32898 pub fn id_within_family(&self) -> u32 { 899 self.id 900 } 901 902 /// Waits until all work on this queue has finished. 903 /// 904 /// Just like `Device::wait()`, you shouldn't have to call this function in a typical program. 905 #[inline] wait(&self) -> Result<(), OomError>906 pub fn wait(&self) -> Result<(), OomError> { 907 unsafe { 908 let fns = self.device.fns(); 909 let queue = self.queue.lock().unwrap(); 910 check_errors(fns.v1_0.queue_wait_idle(*queue))?; 911 Ok(()) 912 } 913 } 914 } 915 916 impl PartialEq for Queue { eq(&self, other: &Self) -> bool917 fn eq(&self, other: &Self) -> bool { 918 self.is_same(other) 919 } 920 } 921 922 impl Eq for Queue {} 923 924 unsafe impl DeviceOwned for Queue { device(&self) -> &Arc<Device>925 fn device(&self) -> &Arc<Device> { 926 &self.device 927 } 928 } 929 930 unsafe impl SynchronizedVulkanObject for Queue { 931 type Object = ash::vk::Queue; 932 933 #[inline] internal_object_guard(&self) -> MutexGuard<ash::vk::Queue>934 fn internal_object_guard(&self) -> MutexGuard<ash::vk::Queue> { 935 self.queue.lock().unwrap() 936 } 937 } 938 939 #[cfg(test)] 940 mod tests { 941 use crate::device::physical::PhysicalDevice; 942 use crate::device::Device; 943 use crate::device::DeviceCreationError; 944 use crate::device::DeviceExtensions; 945 use crate::device::{FeatureRestriction, FeatureRestrictionError, Features}; 946 use std::sync::Arc; 947 948 #[test] one_ref()949 fn one_ref() { 950 let (mut device, _) = gfx_dev_and_queue!(); 951 assert!(Arc::get_mut(&mut device).is_some()); 952 } 953 954 #[test] too_many_queues()955 fn too_many_queues() { 956 let instance = instance!(); 957 let physical = match PhysicalDevice::enumerate(&instance).next() { 958 Some(p) => p, 959 None => return, 960 }; 961 962 let family = physical.queue_families().next().unwrap(); 963 let queues = (0..family.queues_count() + 1).map(|_| (family, 1.0)); 964 965 match Device::new( 966 physical, 967 &Features::none(), 968 &DeviceExtensions::none(), 969 queues, 970 ) { 971 Err(DeviceCreationError::TooManyQueuesForFamily) => return, // Success 972 _ => panic!(), 973 }; 974 } 975 976 #[test] unsupposed_features()977 fn unsupposed_features() { 978 let instance = instance!(); 979 let physical = match PhysicalDevice::enumerate(&instance).next() { 980 Some(p) => p, 981 None => return, 982 }; 983 984 let family = physical.queue_families().next().unwrap(); 985 986 let features = Features::all(); 987 // In the unlikely situation where the device supports everything, we ignore the test. 988 if physical.supported_features().is_superset_of(&features) { 989 return; 990 } 991 992 match Device::new( 993 physical, 994 &features, 995 &DeviceExtensions::none(), 996 Some((family, 1.0)), 997 ) { 998 Err(DeviceCreationError::FeatureRestrictionNotMet(FeatureRestrictionError { 999 restriction: FeatureRestriction::NotSupported, 1000 .. 1001 })) => return, // Success 1002 _ => panic!(), 1003 }; 1004 } 1005 1006 #[test] priority_out_of_range()1007 fn priority_out_of_range() { 1008 let instance = instance!(); 1009 let physical = match PhysicalDevice::enumerate(&instance).next() { 1010 Some(p) => p, 1011 None => return, 1012 }; 1013 1014 let family = physical.queue_families().next().unwrap(); 1015 1016 match Device::new( 1017 physical, 1018 &Features::none(), 1019 &DeviceExtensions::none(), 1020 Some((family, 1.4)), 1021 ) { 1022 Err(DeviceCreationError::PriorityOutOfRange) => (), // Success 1023 _ => panic!(), 1024 }; 1025 1026 match Device::new( 1027 physical, 1028 &Features::none(), 1029 &DeviceExtensions::none(), 1030 Some((family, -0.2)), 1031 ) { 1032 Err(DeviceCreationError::PriorityOutOfRange) => (), // Success 1033 _ => panic!(), 1034 }; 1035 } 1036 } 1037