1 /*!
2 # Vulkan backend internals.
3 
4 ## Stack memory
5 
6 Most of the code just passes the data through. The only problem
7 that affects all the pieces is related to memory allocation:
8 Vulkan expects slices, but the API gives us `Iterator`.
9 So we end up using a lot of `inplace_it` to get things collected on stack.
10 
11 ## Framebuffers
12 
13 One part that has actual logic is related to framebuffers. HAL is modelled
14 after image-less framebuffers. If the the Vulkan implementation supports it,
15 we map it 1:1, and everything is great. If it doesn't expose
16 `KHR_imageless_framebuffer`, however, than we have to keep all the created
17 framebuffers internally in an internally-synchronized map, per `B::Framebuffer`.
18 !*/
19 
20 #![allow(non_snake_case)]
21 
22 #[macro_use]
23 extern crate log;
24 
25 #[cfg(target_os = "macos")]
26 #[macro_use]
27 extern crate objc;
28 
29 #[cfg(not(feature = "use-rtld-next"))]
30 use ash::Entry;
31 use ash::{
32     extensions::{ext, khr, nv::MeshShader},
33     version::{DeviceV1_0, EntryV1_0, InstanceV1_0},
34     vk,
35 };
36 
37 use hal::{
38     adapter,
39     device::{DeviceLost, OutOfMemory},
40     image, memory,
41     pso::PipelineStage,
42     queue,
43     window::{OutOfDate, PresentError, Suboptimal, SurfaceLost},
44     Features,
45 };
46 
47 use std::{
48     borrow::Cow,
49     cmp,
50     ffi::{CStr, CString},
51     fmt, slice,
52     sync::Arc,
53     thread, unreachable,
54 };
55 
56 #[cfg(feature = "use-rtld-next")]
57 use ash::EntryCustom;
58 
59 mod command;
60 mod conv;
61 mod device;
62 mod info;
63 mod native;
64 mod physical_device;
65 mod pool;
66 mod window;
67 
68 pub use physical_device::*;
69 
70 // Sets up the maximum count we expect in most cases, but maybe not all of them.
71 const ROUGH_MAX_ATTACHMENT_COUNT: usize = 5;
72 
73 pub struct RawInstance {
74     inner: ash::Instance,
75     debug_messenger: Option<DebugMessenger>,
76     get_physical_device_properties: Option<vk::KhrGetPhysicalDeviceProperties2Fn>,
77 
78     pub render_doc_entry: Result<RenderDocEntry, String>,
79 }
80 
81 pub enum DebugMessenger {
82     Utils(ext::DebugUtils, vk::DebugUtilsMessengerEXT),
83     #[allow(deprecated)] // `DebugReport`
84     Report(ext::DebugReport, vk::DebugReportCallbackEXT),
85 }
86 
87 impl Drop for RawInstance {
drop(&mut self)88     fn drop(&mut self) {
89         unsafe {
90             match self.debug_messenger {
91                 Some(DebugMessenger::Utils(ref ext, callback)) => {
92                     ext.destroy_debug_utils_messenger(callback, None)
93                 }
94                 #[allow(deprecated)] // `DebugReport`
95                 Some(DebugMessenger::Report(ref ext, callback)) => {
96                     ext.destroy_debug_report_callback(callback, None)
97                 }
98                 None => {}
99             }
100             self.inner.destroy_instance(None);
101         }
102     }
103 }
104 
105 /// Helper wrapper around `vk::make_version`.
106 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
107 #[repr(transparent)]
108 pub struct Version(u32);
109 
110 impl Version {
111     pub const V1_0: Version = Self(vk::make_version(1, 0, 0));
112     pub const V1_1: Version = Self(vk::make_version(1, 1, 0));
113     pub const V1_2: Version = Self(vk::make_version(1, 2, 0));
114 
major(self) -> u32115     pub const fn major(self) -> u32 {
116         vk::version_major(self.0)
117     }
118 
minor(self) -> u32119     pub const fn minor(self) -> u32 {
120         vk::version_minor(self.0)
121     }
122 
patch(self) -> u32123     pub const fn patch(self) -> u32 {
124         vk::version_patch(self.0)
125     }
126 }
127 
128 impl fmt::Debug for Version {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result129     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130         f.debug_struct("ApiVersion")
131             .field("major", &self.major())
132             .field("minor", &self.minor())
133             .field("patch", &self.patch())
134             .finish()
135     }
136 }
137 
138 impl Into<u32> for Version {
into(self) -> u32139     fn into(self) -> u32 {
140         self.0
141     }
142 }
143 
144 impl Into<Version> for u32 {
into(self) -> Version145     fn into(self) -> Version {
146         Version(self)
147     }
148 }
149 
150 #[repr(C)]
151 pub struct RenderDocEntry {
152     api: renderdoc_sys::RENDERDOC_API_1_4_1,
153     lib: libloading::Library,
154 }
155 
156 unsafe impl Send for RenderDocEntry {}
157 
158 unsafe impl Sync for RenderDocEntry {}
159 
160 pub struct Instance {
161     pub raw: Arc<RawInstance>,
162 
163     /// Supported extensions of this instance.
164     pub extensions: Vec<&'static CStr>,
165 
166     #[cfg(not(feature = "use-rtld-next"))]
167     pub entry: Entry,
168 
169     #[cfg(feature = "use-rtld-next")]
170     pub entry: EntryCustom<()>,
171 }
172 
173 impl fmt::Debug for Instance {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result174     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
175         fmt.write_str("Instance")
176     }
177 }
178 
map_queue_type(flags: vk::QueueFlags) -> queue::QueueType179 fn map_queue_type(flags: vk::QueueFlags) -> queue::QueueType {
180     if flags.contains(vk::QueueFlags::GRAPHICS | vk::QueueFlags::COMPUTE) {
181         // TRANSFER_BIT optional
182         queue::QueueType::General
183     } else if flags.contains(vk::QueueFlags::GRAPHICS) {
184         // TRANSFER_BIT optional
185         queue::QueueType::Graphics
186     } else if flags.contains(vk::QueueFlags::COMPUTE) {
187         // TRANSFER_BIT optional
188         queue::QueueType::Compute
189     } else if flags.contains(vk::QueueFlags::TRANSFER) {
190         queue::QueueType::Transfer
191     } else {
192         // TODO: present only queues?
193         unimplemented!()
194     }
195 }
196 
display_debug_utils_label_ext( label_structs: *mut vk::DebugUtilsLabelEXT, count: usize, ) -> Option<String>197 unsafe fn display_debug_utils_label_ext(
198     label_structs: *mut vk::DebugUtilsLabelEXT,
199     count: usize,
200 ) -> Option<String> {
201     if count == 0 {
202         return None;
203     }
204 
205     Some(
206         slice::from_raw_parts::<vk::DebugUtilsLabelEXT>(label_structs, count)
207             .iter()
208             .flat_map(|dul_obj| {
209                 dul_obj
210                     .p_label_name
211                     .as_ref()
212                     .map(|lbl| CStr::from_ptr(lbl).to_string_lossy().into_owned())
213             })
214             .collect::<Vec<String>>()
215             .join(", "),
216     )
217 }
218 
display_debug_utils_object_name_info_ext( info_structs: *mut vk::DebugUtilsObjectNameInfoEXT, count: usize, ) -> Option<String>219 unsafe fn display_debug_utils_object_name_info_ext(
220     info_structs: *mut vk::DebugUtilsObjectNameInfoEXT,
221     count: usize,
222 ) -> Option<String> {
223     if count == 0 {
224         return None;
225     }
226 
227     //TODO: use color field of vk::DebugUtilsLabelExt in a meaningful way?
228     Some(
229         slice::from_raw_parts::<vk::DebugUtilsObjectNameInfoEXT>(info_structs, count)
230             .iter()
231             .map(|obj_info| {
232                 let object_name = obj_info
233                     .p_object_name
234                     .as_ref()
235                     .map(|name| CStr::from_ptr(name).to_string_lossy().into_owned());
236 
237                 match object_name {
238                     Some(name) => format!(
239                         "(type: {:?}, hndl: 0x{:x}, name: {})",
240                         obj_info.object_type, obj_info.object_handle, name
241                     ),
242                     None => format!(
243                         "(type: {:?}, hndl: 0x{:x})",
244                         obj_info.object_type, obj_info.object_handle
245                     ),
246                 }
247             })
248             .collect::<Vec<String>>()
249             .join(", "),
250     )
251 }
252 
debug_utils_messenger_callback( message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, message_type: vk::DebugUtilsMessageTypeFlagsEXT, p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT, _user_data: *mut std::os::raw::c_void, ) -> vk::Bool32253 unsafe extern "system" fn debug_utils_messenger_callback(
254     message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
255     message_type: vk::DebugUtilsMessageTypeFlagsEXT,
256     p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
257     _user_data: *mut std::os::raw::c_void,
258 ) -> vk::Bool32 {
259     if thread::panicking() {
260         return vk::FALSE;
261     }
262     let callback_data = *p_callback_data;
263 
264     let message_severity = match message_severity {
265         vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
266         vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
267         vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Info,
268         vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => log::Level::Trace,
269         _ => log::Level::Warn,
270     };
271     let message_type = &format!("{:?}", message_type);
272     let message_id_number: i32 = callback_data.message_id_number as i32;
273 
274     let message_id_name = if callback_data.p_message_id_name.is_null() {
275         Cow::from("")
276     } else {
277         CStr::from_ptr(callback_data.p_message_id_name).to_string_lossy()
278     };
279 
280     let message = if callback_data.p_message.is_null() {
281         Cow::from("")
282     } else {
283         CStr::from_ptr(callback_data.p_message).to_string_lossy()
284     };
285 
286     let additional_info: [(&str, Option<String>); 3] = [
287         (
288             "queue info",
289             display_debug_utils_label_ext(
290                 callback_data.p_queue_labels as *mut _,
291                 callback_data.queue_label_count as usize,
292             ),
293         ),
294         (
295             "cmd buf info",
296             display_debug_utils_label_ext(
297                 callback_data.p_cmd_buf_labels as *mut _,
298                 callback_data.cmd_buf_label_count as usize,
299             ),
300         ),
301         (
302             "object info",
303             display_debug_utils_object_name_info_ext(
304                 callback_data.p_objects as *mut _,
305                 callback_data.object_count as usize,
306             ),
307         ),
308     ];
309 
310     log!(message_severity, "{}\n", {
311         let mut msg = format!(
312             "\n{} [{} (0x{:x})] : {}",
313             message_type, message_id_name, message_id_number, message
314         );
315 
316         for &(info_label, ref info) in additional_info.iter() {
317             if let Some(ref data) = *info {
318                 msg = format!("{}\n{}: {}", msg, info_label, data);
319             }
320         }
321 
322         msg
323     });
324 
325     vk::FALSE
326 }
327 
debug_report_callback( type_: vk::DebugReportFlagsEXT, _: vk::DebugReportObjectTypeEXT, _object: u64, _location: usize, _msg_code: i32, layer_prefix: *const std::os::raw::c_char, description: *const std::os::raw::c_char, _user_data: *mut std::os::raw::c_void, ) -> vk::Bool32328 unsafe extern "system" fn debug_report_callback(
329     type_: vk::DebugReportFlagsEXT,
330     _: vk::DebugReportObjectTypeEXT,
331     _object: u64,
332     _location: usize,
333     _msg_code: i32,
334     layer_prefix: *const std::os::raw::c_char,
335     description: *const std::os::raw::c_char,
336     _user_data: *mut std::os::raw::c_void,
337 ) -> vk::Bool32 {
338     if thread::panicking() {
339         return vk::FALSE;
340     }
341 
342     let level = match type_ {
343         vk::DebugReportFlagsEXT::ERROR => log::Level::Error,
344         vk::DebugReportFlagsEXT::WARNING => log::Level::Warn,
345         vk::DebugReportFlagsEXT::INFORMATION => log::Level::Info,
346         vk::DebugReportFlagsEXT::DEBUG => log::Level::Debug,
347         _ => log::Level::Warn,
348     };
349 
350     let layer_prefix = CStr::from_ptr(layer_prefix).to_str().unwrap();
351     let description = CStr::from_ptr(description).to_str().unwrap();
352     log!(level, "[{}] {}", layer_prefix, description);
353     vk::FALSE
354 }
355 
356 impl hal::Instance<Backend> for Instance {
create(name: &str, version: u32) -> Result<Self, hal::UnsupportedBackend>357     fn create(name: &str, version: u32) -> Result<Self, hal::UnsupportedBackend> {
358         #[cfg(not(feature = "use-rtld-next"))]
359         let entry = match unsafe { Entry::new() } {
360             Ok(entry) => entry,
361             Err(err) => {
362                 info!("Missing Vulkan entry points: {:?}", err);
363                 return Err(hal::UnsupportedBackend);
364             }
365         };
366 
367         #[cfg(feature = "use-rtld-next")]
368         let entry = EntryCustom::new_custom((), |_, name| unsafe {
369             libc::dlsym(libc::RTLD_NEXT, name.as_ptr())
370         });
371 
372         let driver_api_version = match entry.try_enumerate_instance_version() {
373             // Vulkan 1.1+
374             Ok(Some(version)) => version.into(),
375 
376             // Vulkan 1.0
377             Ok(None) => Version::V1_0,
378 
379             // Ignore out of memory since it's unlikely to happen and `Instance::create` doesn't have a way to express it in the return value.
380             Err(err) if err == vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
381                 warn!("vkEnumerateInstanceVersion returned VK_ERROR_OUT_OF_HOST_MEMORY");
382                 return Err(hal::UnsupportedBackend);
383             }
384 
385             Err(_) => unreachable!(),
386         };
387 
388         let app_name = CString::new(name).unwrap();
389         let app_info = vk::ApplicationInfo::builder()
390             .application_name(app_name.as_c_str())
391             .application_version(version)
392             .engine_name(CStr::from_bytes_with_nul(b"gfx-rs\0").unwrap())
393             .engine_version(1)
394             .api_version({
395                 // Pick the latest API version available, but don't go later than the SDK version used by `gfx_backend_vulkan`.
396                 cmp::min(driver_api_version, {
397                     // This is the max Vulkan API version supported by `gfx_backend_vulkan`.
398                     //
399                     // If we want to increment this, there are some things that must be done first:
400                     //  - Audit the behavioral differences between the previous and new API versions.
401                     //  - Audit all extensions used by this backend:
402                     //    - If any were promoted in the new API version and the behavior has changed, we must handle the new behavior in addition to the old behavior.
403                     //    - If any were obsoleted in the new API version, we must implement a fallback for the new API version
404                     //    - If any are non-KHR-vendored, we must ensure the new behavior is still correct (since backwards-compatibility is not guaranteed).
405                     //
406                     // TODO: This should be replaced by `vk::HEADER_VERSION_COMPLETE` (added in `ash@6f488cd`) and this comment moved to either `README.md` or `Cargo.toml`.
407                     Version::V1_2
408                 })
409                 .into()
410             });
411 
412         let instance_extensions = entry
413             .enumerate_instance_extension_properties()
414             .map_err(|e| {
415                 info!("Unable to enumerate instance extensions: {:?}", e);
416                 hal::UnsupportedBackend
417             })?;
418 
419         let instance_layers = entry.enumerate_instance_layer_properties().map_err(|e| {
420             info!("Unable to enumerate instance layers: {:?}", e);
421             hal::UnsupportedBackend
422         })?;
423 
424         // Check our extensions against the available extensions
425         let extensions = {
426             let mut extensions: Vec<&'static CStr> = Vec::new();
427             extensions.push(khr::Surface::name());
428 
429             // Platform-specific WSI extensions
430             if cfg!(all(
431                 unix,
432                 not(target_os = "android"),
433                 not(target_os = "macos")
434             )) {
435                 extensions.push(khr::XlibSurface::name());
436                 extensions.push(khr::XcbSurface::name());
437                 extensions.push(khr::WaylandSurface::name());
438             }
439             if cfg!(target_os = "android") {
440                 extensions.push(khr::AndroidSurface::name());
441             }
442             if cfg!(target_os = "windows") {
443                 extensions.push(khr::Win32Surface::name());
444             }
445             if cfg!(target_os = "macos") {
446                 extensions.push(ash::extensions::mvk::MacOSSurface::name());
447             }
448 
449             extensions.push(ext::DebugUtils::name());
450             if cfg!(debug_assertions) {
451                 #[allow(deprecated)]
452                 extensions.push(ext::DebugReport::name());
453             }
454 
455             extensions.push(vk::KhrGetPhysicalDeviceProperties2Fn::name());
456 
457             // VK_KHR_storage_buffer_storage_class required for `Naga` on Vulkan 1.0 devices
458             if driver_api_version == Version::V1_0 {
459                 extensions.push(vk::KhrStorageBufferStorageClassFn::name());
460             }
461 
462             // Only keep available extensions.
463             extensions.retain(|&ext| {
464                 if instance_extensions
465                     .iter()
466                     .find(|inst_ext| unsafe {
467                         CStr::from_ptr(inst_ext.extension_name.as_ptr()) == ext
468                     })
469                     .is_some()
470                 {
471                     true
472                 } else {
473                     info!("Unable to find extension: {}", ext.to_string_lossy());
474                     false
475                 }
476             });
477             extensions
478         };
479 
480         if driver_api_version == Version::V1_0
481             && !extensions.contains(&vk::KhrStorageBufferStorageClassFn::name())
482         {
483             warn!("Unable to create Vulkan instance. Required VK_KHR_storage_buffer_storage_class extension is not supported");
484             return Err(hal::UnsupportedBackend);
485         }
486 
487         // Check requested layers against the available layers
488         let layers = {
489             let mut layers: Vec<&'static CStr> = Vec::new();
490             if cfg!(debug_assertions) {
491                 layers.push(CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap());
492             }
493 
494             // Only keep available layers.
495             layers.retain(|&layer| {
496                 if instance_layers
497                     .iter()
498                     .find(|inst_layer| unsafe {
499                         CStr::from_ptr(inst_layer.layer_name.as_ptr()) == layer
500                     })
501                     .is_some()
502                 {
503                     true
504                 } else {
505                     warn!("Unable to find layer: {}", layer.to_string_lossy());
506                     false
507                 }
508             });
509             layers
510         };
511 
512         let instance = {
513             let str_pointers = layers
514                 .iter()
515                 .chain(extensions.iter())
516                 .map(|&s| {
517                     // Safe because `layers` and `extensions` entries have static lifetime.
518                     s.as_ptr()
519                 })
520                 .collect::<Vec<_>>();
521 
522             let create_info = vk::InstanceCreateInfo::builder()
523                 .flags(vk::InstanceCreateFlags::empty())
524                 .application_info(&app_info)
525                 .enabled_layer_names(&str_pointers[..layers.len()])
526                 .enabled_extension_names(&str_pointers[layers.len()..]);
527 
528             unsafe { entry.create_instance(&create_info, None) }.map_err(|e| {
529                 warn!("Unable to create Vulkan instance: {:?}", e);
530                 hal::UnsupportedBackend
531             })?
532         };
533 
534         let get_physical_device_properties = extensions
535             .iter()
536             .find(|&&ext| ext == vk::KhrGetPhysicalDeviceProperties2Fn::name())
537             .map(|_| {
538                 vk::KhrGetPhysicalDeviceProperties2Fn::load(|name| unsafe {
539                     std::mem::transmute(
540                         entry.get_instance_proc_addr(instance.handle(), name.as_ptr()),
541                     )
542                 })
543             });
544 
545         #[allow(deprecated)] // `DebugReport`
546         let debug_messenger = {
547             // make sure VK_EXT_debug_utils is available
548             if instance_extensions.iter().any(|props| unsafe {
549                 CStr::from_ptr(props.extension_name.as_ptr()) == ext::DebugUtils::name()
550             }) {
551                 let ext = ext::DebugUtils::new(&entry, &instance);
552                 let info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
553                     .flags(vk::DebugUtilsMessengerCreateFlagsEXT::empty())
554                     .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all())
555                     .message_type(vk::DebugUtilsMessageTypeFlagsEXT::all())
556                     .pfn_user_callback(Some(debug_utils_messenger_callback));
557                 let handle = unsafe { ext.create_debug_utils_messenger(&info, None) }.unwrap();
558                 Some(DebugMessenger::Utils(ext, handle))
559             } else if cfg!(debug_assertions)
560                 && instance_extensions.iter().any(|props| unsafe {
561                     CStr::from_ptr(props.extension_name.as_ptr()) == ext::DebugReport::name()
562                 })
563             {
564                 let ext = ext::DebugReport::new(&entry, &instance);
565                 let info = vk::DebugReportCallbackCreateInfoEXT::builder()
566                     .flags(vk::DebugReportFlagsEXT::all())
567                     .pfn_callback(Some(debug_report_callback));
568                 let handle = unsafe { ext.create_debug_report_callback(&info, None) }.unwrap();
569                 Some(DebugMessenger::Report(ext, handle))
570             } else {
571                 None
572             }
573         };
574 
575         Ok(Instance {
576             raw: Arc::new(RawInstance {
577                 inner: instance,
578                 debug_messenger,
579                 get_physical_device_properties,
580                 render_doc_entry: unsafe { load_renderdoc_entrypoint() },
581             }),
582             extensions,
583             entry,
584         })
585     }
586 
enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>>587     fn enumerate_adapters(&self) -> Vec<adapter::Adapter<Backend>> {
588         let devices = match unsafe { self.raw.inner.enumerate_physical_devices() } {
589             Ok(devices) => devices,
590             Err(err) => {
591                 error!("Could not enumerate physical devices! {}", err);
592                 vec![]
593             }
594         };
595 
596         devices
597             .into_iter()
598             .map(|device| physical_device::load_adapter(&self.raw, device))
599             .collect()
600     }
601 
create_surface( &self, has_handle: &impl raw_window_handle::HasRawWindowHandle, ) -> Result<window::Surface, hal::window::InitError>602     unsafe fn create_surface(
603         &self,
604         has_handle: &impl raw_window_handle::HasRawWindowHandle,
605     ) -> Result<window::Surface, hal::window::InitError> {
606         use raw_window_handle::RawWindowHandle;
607 
608         match has_handle.raw_window_handle() {
609             #[cfg(all(
610                 unix,
611                 not(target_os = "android"),
612                 not(target_os = "macos"),
613                 not(target_os = "solaris")
614             ))]
615             RawWindowHandle::Wayland(handle)
616                 if self.extensions.contains(&khr::WaylandSurface::name()) =>
617             {
618                 Ok(self.create_surface_from_wayland(handle.display, handle.surface))
619             }
620             #[cfg(all(
621                 unix,
622                 not(target_os = "android"),
623                 not(target_os = "macos"),
624                 not(target_os = "solaris")
625             ))]
626             RawWindowHandle::Xlib(handle)
627                 if self.extensions.contains(&khr::XlibSurface::name()) =>
628             {
629                 Ok(self.create_surface_from_xlib(handle.display as *mut _, handle.window))
630             }
631             #[cfg(all(
632                 unix,
633                 not(target_os = "android"),
634                 not(target_os = "macos"),
635                 not(target_os = "ios")
636             ))]
637             RawWindowHandle::Xcb(handle) if self.extensions.contains(&khr::XcbSurface::name()) => {
638                 Ok(self.create_surface_from_xcb(handle.connection as *mut _, handle.window))
639             }
640             #[cfg(target_os = "android")]
641             RawWindowHandle::Android(handle) => {
642                 Ok(self.create_surface_android(handle.a_native_window))
643             }
644             #[cfg(windows)]
645             RawWindowHandle::Windows(handle) => {
646                 use winapi::um::libloaderapi::GetModuleHandleW;
647 
648                 let hinstance = GetModuleHandleW(std::ptr::null());
649                 Ok(self.create_surface_from_hwnd(hinstance as *mut _, handle.hwnd))
650             }
651             #[cfg(target_os = "macos")]
652             RawWindowHandle::MacOS(handle) => Ok(self.create_surface_from_ns_view(handle.ns_view)),
653             _ => Err(hal::window::InitError::UnsupportedWindowHandle),
654         }
655     }
656 
destroy_surface(&self, surface: window::Surface)657     unsafe fn destroy_surface(&self, surface: window::Surface) {
658         surface
659             .raw
660             .functor
661             .destroy_surface(surface.raw.handle, None);
662     }
663 }
664 
load_renderdoc_entrypoint() -> Result<RenderDocEntry, String>665 unsafe fn load_renderdoc_entrypoint() -> Result<RenderDocEntry, String> {
666     if !cfg!(debug_assertions) {
667         return Err("RenderDoc support is only enabled with 'debug_assertions'".into());
668     }
669 
670     type GetApiFn = unsafe extern "C" fn(version: u32, out: *mut *mut std::ffi::c_void) -> i32;
671 
672     #[cfg(windows)]
673     let renderdoc_filename = "renderdoc.dll";
674     #[cfg(all(unix, not(target_os = "android")))]
675     let renderdoc_filename = "librenderdoc.so";
676     #[cfg(target_os = "android")]
677     let renderdoc_filename = "libVkLayer_GLES_RenderDoc.so";
678 
679     let renderdoc_lib = libloading::Library::new(renderdoc_filename).map_err(|e| {
680         format!(
681             "Unable to load renderdoc library '{}': {:?}",
682             renderdoc_filename, e
683         )
684     })?;
685 
686     let get_api: libloading::Symbol<GetApiFn> =
687         renderdoc_lib.get(b"RENDERDOC_GetAPI\0").map_err(|e| {
688             format!(
689                 "Unable to get RENDERDOC_GetAPI from renderdoc library '{}': {:?}",
690                 renderdoc_filename, e
691             )
692         })?;
693     let mut obj = std::ptr::null_mut();
694     match get_api(10401, &mut obj) {
695         1 => Ok(RenderDocEntry {
696             api: *(obj as *mut renderdoc_sys::RENDERDOC_API_1_4_1),
697             lib: renderdoc_lib,
698         }),
699         return_value => Err(format!(
700             "Unable to get API from renderdoc library '{}': {}",
701             renderdoc_filename, return_value
702         )),
703     }
704     .map_err(|error| {
705         warn!("Error loading renderdoc library: {}", error);
706         error
707     })
708 }
709 
710 #[derive(Debug, Clone)]
711 pub struct QueueFamily {
712     properties: vk::QueueFamilyProperties,
713     device: vk::PhysicalDevice,
714     index: u32,
715 }
716 
717 impl queue::QueueFamily for QueueFamily {
queue_type(&self) -> queue::QueueType718     fn queue_type(&self) -> queue::QueueType {
719         map_queue_type(self.properties.queue_flags)
720     }
max_queues(&self) -> usize721     fn max_queues(&self) -> usize {
722         self.properties.queue_count as _
723     }
id(&self) -> queue::QueueFamilyId724     fn id(&self) -> queue::QueueFamilyId {
725         queue::QueueFamilyId(self.index as _)
726     }
supports_sparse_binding(&self) -> bool727     fn supports_sparse_binding(&self) -> bool {
728         self.properties
729             .queue_flags
730             .contains(vk::QueueFlags::SPARSE_BINDING)
731     }
732 }
733 
734 struct DeviceExtensionFunctions {
735     mesh_shaders: Option<ExtensionFn<MeshShader>>,
736     draw_indirect_count: Option<ExtensionFn<khr::DrawIndirectCount>>,
737 }
738 
739 // TODO there's no reason why this can't be unified--the function pointers should all be the same--it's not clear how to do this with `ash`.
740 enum ExtensionFn<T> {
741     /// The loaded function pointer struct for an extension.
742     Extension(T),
743     /// The extension was promoted to a core version of Vulkan and the functions on `ash`'s `DeviceV1_x` traits should be used.
744     Promoted,
745 }
746 
747 impl<T> ExtensionFn<T> {
748     /// Expect `self` to be `ExtensionFn::Extension` and return the inner value.
unwrap_extension(&self) -> &T749     fn unwrap_extension(&self) -> &T {
750         if let ExtensionFn::Extension(t) = self {
751             t
752         } else {
753             panic!()
754         }
755     }
756 }
757 
758 #[doc(hidden)]
759 pub struct RawDevice {
760     raw: ash::Device,
761     features: Features,
762     instance: Arc<RawInstance>,
763     extension_fns: DeviceExtensionFunctions,
764     /// The `hal::Features::NDC_Y_UP` flag is implemented with either `VK_AMD_negative_viewport_height` or `VK_KHR_maintenance1`/1.1+. The AMD extension for negative viewport height does not require a Y shift.
765     ///
766     /// This flag is `true` if the device has `VK_KHR_maintenance1`/1.1+ and `false` otherwise (i.e. in the case of `VK_AMD_negative_viewport_height`).
767     flip_y_requires_shift: bool,
768     imageless_framebuffers: bool,
769     image_view_usage: bool,
770     timestamp_period: f32,
771 }
772 
773 impl fmt::Debug for RawDevice {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result774     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
775         write!(f, "RawDevice") // TODO: Real Debug impl
776     }
777 }
778 impl Drop for RawDevice {
drop(&mut self)779     fn drop(&mut self) {
780         unsafe {
781             self.raw.destroy_device(None);
782         }
783     }
784 }
785 
786 impl RawDevice {
debug_messenger(&self) -> Option<&DebugMessenger>787     fn debug_messenger(&self) -> Option<&DebugMessenger> {
788         self.instance.debug_messenger.as_ref()
789     }
790 
map_viewport(&self, rect: &hal::pso::Viewport) -> vk::Viewport791     fn map_viewport(&self, rect: &hal::pso::Viewport) -> vk::Viewport {
792         let flip_y = self.features.contains(hal::Features::NDC_Y_UP);
793         let shift_y = flip_y && self.flip_y_requires_shift;
794         conv::map_viewport(rect, flip_y, shift_y)
795     }
796 
set_object_name( &self, object_type: vk::ObjectType, object: impl vk::Handle, name: &str, )797     unsafe fn set_object_name(
798         &self,
799         object_type: vk::ObjectType,
800         object: impl vk::Handle,
801         name: &str,
802     ) {
803         let instance = &self.instance;
804         if let Some(DebugMessenger::Utils(ref debug_utils_ext, _)) = instance.debug_messenger {
805             // Keep variables outside the if-else block to ensure they do not
806             // go out of scope while we hold a pointer to them
807             let mut buffer: [u8; 64] = [0u8; 64];
808             let buffer_vec: Vec<u8>;
809 
810             // Append a null terminator to the string
811             let name_cstr = if name.len() < 64 {
812                 // Common case, string is very small. Allocate a copy on the stack.
813                 std::ptr::copy_nonoverlapping(name.as_ptr(), buffer.as_mut_ptr(), name.len());
814                 // Add null terminator
815                 buffer[name.len()] = 0;
816                 CStr::from_bytes_with_nul(&buffer[..name.len() + 1]).unwrap()
817             } else {
818                 // Less common case, the string is large.
819                 // This requires a heap allocation.
820                 buffer_vec = name
821                     .as_bytes()
822                     .iter()
823                     .cloned()
824                     .chain(std::iter::once(0))
825                     .collect::<Vec<u8>>();
826                 CStr::from_bytes_with_nul(&buffer_vec).unwrap()
827             };
828             let _result = debug_utils_ext.debug_utils_set_object_name(
829                 self.raw.handle(),
830                 &vk::DebugUtilsObjectNameInfoEXT::builder()
831                     .object_type(object_type)
832                     .object_handle(object.as_raw())
833                     .object_name(name_cstr),
834             );
835         }
836     }
837 }
838 
839 // Need to explicitly synchronize on submission and present.
840 pub type RawCommandQueue = Arc<vk::Queue>;
841 
842 pub struct Queue {
843     raw: RawCommandQueue,
844     device: Arc<RawDevice>,
845     swapchain_fn: khr::Swapchain,
846 }
847 
848 impl fmt::Debug for Queue {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result849     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
850         fmt.write_str("Queue")
851     }
852 }
853 
854 impl queue::Queue<Backend> for Queue {
submit<'a, Ic, Iw, Is>( &mut self, command_buffers: Ic, wait_semaphores: Iw, signal_semaphores: Is, fence: Option<&mut native::Fence>, ) where Ic: Iterator<Item = &'a command::CommandBuffer>, Iw: Iterator<Item = (&'a native::Semaphore, PipelineStage)>, Is: Iterator<Item = &'a native::Semaphore>,855     unsafe fn submit<'a, Ic, Iw, Is>(
856         &mut self,
857         command_buffers: Ic,
858         wait_semaphores: Iw,
859         signal_semaphores: Is,
860         fence: Option<&mut native::Fence>,
861     ) where
862         Ic: Iterator<Item = &'a command::CommandBuffer>,
863         Iw: Iterator<Item = (&'a native::Semaphore, PipelineStage)>,
864         Is: Iterator<Item = &'a native::Semaphore>,
865     {
866         //TODO: avoid heap allocations
867         let mut waits = Vec::new();
868         let mut stages = Vec::new();
869 
870         let buffers = command_buffers.map(|cmd| cmd.raw).collect::<Vec<_>>();
871         for (semaphore, stage) in wait_semaphores {
872             waits.push(semaphore.0);
873             stages.push(conv::map_pipeline_stage(stage));
874         }
875         let signals = signal_semaphores
876             .map(|semaphore| semaphore.0)
877             .collect::<Vec<_>>();
878 
879         let mut info = vk::SubmitInfo::builder()
880             .wait_semaphores(&waits)
881             .command_buffers(&buffers)
882             .signal_semaphores(&signals);
883         // If count is zero, AMD driver crashes if nullptr is not set for stage masks
884         if !stages.is_empty() {
885             info = info.wait_dst_stage_mask(&stages);
886         }
887 
888         let fence_raw = fence.map(|fence| fence.0).unwrap_or(vk::Fence::null());
889 
890         let result = self.device.raw.queue_submit(*self.raw, &[*info], fence_raw);
891         if let Err(e) = result {
892             error!("Submit resulted in {:?}", e);
893         }
894     }
895 
bind_sparse<'a, Iw, Is, Ibi, Ib, Iii, Io, Ii>( &mut self, wait_semaphores: Iw, signal_semaphores: Is, buffer_memory_binds: Ib, image_opaque_memory_binds: Io, image_memory_binds: Ii, device: &Device, fence: Option<&native::Fence>, ) where Ibi: Iterator<Item = &'a memory::SparseBind<&'a native::Memory>>, Ib: Iterator<Item = (&'a mut native::Buffer, Ibi)>, Iii: Iterator<Item = &'a memory::SparseImageBind<&'a native::Memory>>, Io: Iterator<Item = (&'a mut native::Image, Ibi)>, Ii: Iterator<Item = (&'a mut native::Image, Iii)>, Iw: Iterator<Item = &'a native::Semaphore>, Is: Iterator<Item = &'a native::Semaphore>,896     unsafe fn bind_sparse<'a, Iw, Is, Ibi, Ib, Iii, Io, Ii>(
897         &mut self,
898         wait_semaphores: Iw,
899         signal_semaphores: Is,
900         buffer_memory_binds: Ib,
901         image_opaque_memory_binds: Io,
902         image_memory_binds: Ii,
903         device: &Device,
904         fence: Option<&native::Fence>,
905     ) where
906         Ibi: Iterator<Item = &'a memory::SparseBind<&'a native::Memory>>,
907         Ib: Iterator<Item = (&'a mut native::Buffer, Ibi)>,
908         Iii: Iterator<Item = &'a memory::SparseImageBind<&'a native::Memory>>,
909         Io: Iterator<Item = (&'a mut native::Image, Ibi)>,
910         Ii: Iterator<Item = (&'a mut native::Image, Iii)>,
911         Iw: Iterator<Item = &'a native::Semaphore>,
912         Is: Iterator<Item = &'a native::Semaphore>,
913     {
914         //TODO: avoid heap allocations
915         let mut waits = Vec::new();
916 
917         for semaphore in wait_semaphores {
918             waits.push(semaphore.0);
919         }
920         let signals = signal_semaphores
921             .map(|semaphore| semaphore.0)
922             .collect::<Vec<_>>();
923 
924         let mut buffer_memory_binds_vec = Vec::new();
925         let mut buffer_binds = buffer_memory_binds
926             .map(|(buffer, bind_iter)| {
927                 let binds_before = buffer_memory_binds_vec.len();
928                 buffer_memory_binds_vec.extend(bind_iter.into_iter().map(|bind| {
929                     let mut bind_builder = vk::SparseMemoryBind::builder()
930                         .resource_offset(bind.resource_offset as u64)
931                         .size(bind.size as u64);
932                     if let Some((memory, memory_offset)) = bind.memory {
933                         bind_builder = bind_builder.memory(memory.raw);
934                         bind_builder = bind_builder.memory_offset(memory_offset as u64);
935                     }
936 
937                     bind_builder.build()
938                 }));
939 
940                 vk::SparseBufferMemoryBindInfo {
941                     buffer: buffer.raw,
942                     bind_count: (buffer_memory_binds_vec.len() - binds_before) as u32,
943                     p_binds: std::ptr::null(),
944                 }
945             })
946             .collect::<Vec<_>>();
947         // Set buffer bindings
948         buffer_binds.iter_mut().fold(0u32, |idx, bind| {
949             (*bind).p_binds = &buffer_memory_binds_vec[idx as usize];
950             idx + bind.bind_count
951         });
952 
953         let mut image_opaque_memory_binds_vec = Vec::new();
954         let mut image_opaque_binds = image_opaque_memory_binds
955             .map(|(image, bind_iter)| {
956                 let binds_before = image_opaque_memory_binds_vec.len();
957                 image_opaque_memory_binds_vec.extend(bind_iter.into_iter().map(|bind| {
958                     let mut bind_builder = vk::SparseMemoryBind::builder()
959                         .resource_offset(bind.resource_offset as u64)
960                         .size(bind.size as u64);
961                     if let Some((memory, memory_offset)) = bind.memory {
962                         bind_builder = bind_builder.memory(memory.raw);
963                         bind_builder = bind_builder.memory_offset(memory_offset as u64);
964                     }
965 
966                     bind_builder.build()
967                 }));
968 
969                 vk::SparseImageOpaqueMemoryBindInfo {
970                     image: image.raw,
971                     bind_count: (image_opaque_memory_binds_vec.len() - binds_before) as u32,
972                     p_binds: std::ptr::null(),
973                 }
974             })
975             .collect::<Vec<_>>();
976         // Set opaque image bindings
977         image_opaque_binds.iter_mut().fold(0u32, |idx, bind| {
978             (*bind).p_binds = &image_opaque_memory_binds_vec[idx as usize];
979             idx + bind.bind_count
980         });
981 
982         let mut image_memory_binds_vec = Vec::new();
983         let mut image_binds = image_memory_binds
984             .map(|(image, bind_iter)| {
985                 let binds_before = image_memory_binds_vec.len();
986                 image_memory_binds_vec.extend(bind_iter.into_iter().map(|bind| {
987                     let mut bind_builder = vk::SparseImageMemoryBind::builder()
988                         .subresource(conv::map_subresource(&bind.subresource))
989                         .offset(conv::map_offset(bind.offset))
990                         .extent(conv::map_extent(bind.extent));
991                     if let Some((memory, memory_offset)) = bind.memory {
992                         bind_builder = bind_builder.memory(memory.raw);
993                         bind_builder = bind_builder.memory_offset(memory_offset as u64);
994                     }
995 
996                     bind_builder.build()
997                 }));
998 
999                 vk::SparseImageMemoryBindInfo {
1000                     image: image.raw,
1001                     bind_count: (image_memory_binds_vec.len() - binds_before) as u32,
1002                     p_binds: std::ptr::null(),
1003                 }
1004             })
1005             .collect::<Vec<_>>();
1006         // Set image bindings
1007         image_binds.iter_mut().fold(0u32, |idx, bind| {
1008             (*bind).p_binds = &image_memory_binds_vec[idx as usize];
1009             idx + bind.bind_count
1010         });
1011 
1012         let info = vk::BindSparseInfo::builder()
1013             .wait_semaphores(&waits)
1014             .signal_semaphores(&signals)
1015             .buffer_binds(&buffer_binds)
1016             .image_opaque_binds(&image_opaque_binds)
1017             .image_binds(&image_binds);
1018 
1019         let info = info.build();
1020         let fence_raw = fence.map(|fence| fence.0).unwrap_or(vk::Fence::null());
1021 
1022         // TODO temporary hack as method is not yet exposed, https://github.com/MaikKlein/ash/issues/342
1023         assert_eq!(
1024             vk::Result::SUCCESS,
1025             device
1026                 .shared
1027                 .raw
1028                 .fp_v1_0()
1029                 .queue_bind_sparse(*self.raw, 1, &info, fence_raw)
1030         );
1031     }
1032 
present( &mut self, surface: &mut window::Surface, image: window::SurfaceImage, wait_semaphore: Option<&mut native::Semaphore>, ) -> Result<Option<Suboptimal>, PresentError>1033     unsafe fn present(
1034         &mut self,
1035         surface: &mut window::Surface,
1036         image: window::SurfaceImage,
1037         wait_semaphore: Option<&mut native::Semaphore>,
1038     ) -> Result<Option<Suboptimal>, PresentError> {
1039         let ssc = surface.swapchain.as_ref().unwrap();
1040         let wait_semaphore = if let Some(wait_semaphore) = wait_semaphore {
1041             wait_semaphore.0
1042         } else {
1043             let signals = &[ssc.semaphore.0];
1044             let submit_info = vk::SubmitInfo::builder().signal_semaphores(signals);
1045             self.device
1046                 .raw
1047                 .queue_submit(*self.raw, &[*submit_info], vk::Fence::null())
1048                 .unwrap();
1049             ssc.semaphore.0
1050         };
1051 
1052         let wait_semaphores = &[wait_semaphore];
1053         let swapchains = &[ssc.swapchain.raw];
1054         let image_indices = &[image.index];
1055         let present_info = vk::PresentInfoKHR::builder()
1056             .wait_semaphores(wait_semaphores)
1057             .swapchains(swapchains)
1058             .image_indices(image_indices);
1059 
1060         match self.swapchain_fn.queue_present(*self.raw, &present_info) {
1061             Ok(false) => Ok(None),
1062             Ok(true) => Ok(Some(Suboptimal)),
1063             Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => Err(OutOfMemory::Host.into()),
1064             Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => Err(OutOfMemory::Device.into()),
1065             Err(vk::Result::ERROR_DEVICE_LOST) => Err(DeviceLost.into()),
1066             Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => Err(OutOfDate.into()),
1067             Err(vk::Result::ERROR_SURFACE_LOST_KHR) => Err(SurfaceLost.into()),
1068             _ => panic!("Failed to present frame"),
1069         }
1070     }
1071 
wait_idle(&mut self) -> Result<(), OutOfMemory>1072     fn wait_idle(&mut self) -> Result<(), OutOfMemory> {
1073         match unsafe { self.device.raw.queue_wait_idle(*self.raw) } {
1074             Ok(()) => Ok(()),
1075             Err(vk::Result::ERROR_OUT_OF_HOST_MEMORY) => Err(OutOfMemory::Host),
1076             Err(vk::Result::ERROR_OUT_OF_DEVICE_MEMORY) => Err(OutOfMemory::Device),
1077             Err(_) => unreachable!(),
1078         }
1079     }
1080 
timestamp_period(&self) -> f321081     fn timestamp_period(&self) -> f32 {
1082         self.device.timestamp_period
1083     }
1084 }
1085 
1086 #[derive(Debug)]
1087 pub struct Device {
1088     shared: Arc<RawDevice>,
1089     vendor_id: u32,
1090     valid_ash_memory_types: u32,
1091     #[cfg(feature = "naga")]
1092     naga_options: naga::back::spv::Options,
1093 }
1094 
1095 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
1096 pub enum Backend {}
1097 impl hal::Backend for Backend {
1098     type Instance = Instance;
1099     type PhysicalDevice = PhysicalDevice;
1100     type Device = Device;
1101     type Surface = window::Surface;
1102 
1103     type QueueFamily = QueueFamily;
1104     type Queue = Queue;
1105     type CommandBuffer = command::CommandBuffer;
1106 
1107     type Memory = native::Memory;
1108     type CommandPool = pool::RawCommandPool;
1109 
1110     type ShaderModule = native::ShaderModule;
1111     type RenderPass = native::RenderPass;
1112     type Framebuffer = native::Framebuffer;
1113 
1114     type Buffer = native::Buffer;
1115     type BufferView = native::BufferView;
1116     type Image = native::Image;
1117     type ImageView = native::ImageView;
1118     type Sampler = native::Sampler;
1119 
1120     type ComputePipeline = native::ComputePipeline;
1121     type GraphicsPipeline = native::GraphicsPipeline;
1122     type PipelineLayout = native::PipelineLayout;
1123     type PipelineCache = native::PipelineCache;
1124     type DescriptorSetLayout = native::DescriptorSetLayout;
1125     type DescriptorPool = native::DescriptorPool;
1126     type DescriptorSet = native::DescriptorSet;
1127 
1128     type Fence = native::Fence;
1129     type Semaphore = native::Semaphore;
1130     type Event = native::Event;
1131     type QueryPool = native::QueryPool;
1132 }
1133