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