1use ash::vk::Handle as _;
2use ash::{amd, ext, khr, vk};
3use naga::back::spv;
4use std::{ffi, sync::Mutex};
5
6use crate::NotSupportedError;
7
8mod db {
9 pub mod intel {
10 pub const VENDOR: u32 = 0x8086;
11 }
12 pub mod nvidia {
13 pub const VENDOR: u32 = 0x10DE;
14 }
15 pub mod qualcomm {
16 pub const VENDOR: u32 = 0x5143;
17 }
18 pub mod pci_class {
19 pub const VGA: &str = "0x0300";
21 pub const DISPLAY_3D: &str = "0x0302";
23 }
24}
25mod layer {
26 use std::ffi::CStr;
27 pub const KHRONOS_VALIDATION: &CStr = c"VK_LAYER_KHRONOS_validation";
28 pub const MESA_OVERLAY: &CStr = c"VK_LAYER_MESA_overlay";
29}
30
31const REQUIRED_DEVICE_EXTENSIONS: &[&ffi::CStr] = &[
32 vk::KHR_TIMELINE_SEMAPHORE_NAME,
33 vk::KHR_DESCRIPTOR_UPDATE_TEMPLATE_NAME,
34 vk::KHR_DYNAMIC_RENDERING_NAME,
35];
36
37fn is_promoted_instance_extension(name: &ffi::CStr, api_version: u32) -> bool {
38 if api_version < vk::API_VERSION_1_1 {
39 return false;
40 }
41
42 name == vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_NAME
43 || name == vk::KHR_GET_SURFACE_CAPABILITIES2_NAME
44}
45
46#[derive(Debug)]
47struct RayTracingCapabilities {
48 min_scratch_buffer_alignment: u64,
49}
50
51#[derive(Debug)]
52struct SystemBugs {
53 intel_fix_descriptor_pool_leak: bool,
55}
56
57#[derive(Debug)]
58struct AdapterCapabilities {
59 api_version: u32,
60 properties: vk::PhysicalDeviceProperties,
61 device_information: crate::DeviceInformation,
62 queue_family_index: u32,
63 layered: bool,
64 binding_array: bool,
65 ray_tracing: Option<RayTracingCapabilities>,
66 buffer_device_address: bool,
67 inline_uniform_blocks: bool,
68 buffer_marker: bool,
69 shader_info: bool,
70 full_screen_exclusive: bool,
71 external_memory: bool,
72 timing: bool,
73 dual_source_blending: bool,
74 shader_float16: bool,
75 cooperative_matrix: crate::CooperativeMatrix,
76 memory_budget: bool,
77 bugs: SystemBugs,
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83enum DisplayServer {
84 X11,
85 Wayland,
86 Other,
87}
88
89fn detect_display_server() -> DisplayServer {
91 if std::env::var_os("WAYLAND_DISPLAY").is_some() {
93 return DisplayServer::Wayland;
94 }
95 if std::env::var_os("DISPLAY").is_some() {
97 return DisplayServer::X11;
98 }
99 DisplayServer::Other
100}
101
102fn detect_gpu_vendors() -> Vec<u32> {
108 let mut vendors = Vec::new();
109 let entries = match std::fs::read_dir("/sys/bus/pci/devices") {
110 Ok(entries) => entries,
111 Err(_) => return vendors,
112 };
113 for entry in entries.flatten() {
114 let path = entry.path();
115 let class = match std::fs::read_to_string(path.join("class")) {
116 Ok(c) => c,
117 Err(_) => continue,
118 };
119 let class = class.trim();
120 let is_gpu =
121 class.starts_with(db::pci_class::VGA) || class.starts_with(db::pci_class::DISPLAY_3D);
122 if !is_gpu {
123 continue;
124 }
125 let vendor = match std::fs::read_to_string(path.join("vendor")) {
126 Ok(v) => v,
127 Err(_) => continue,
128 };
129 if let Ok(id) = u32::from_str_radix(vendor.trim().trim_start_matches("0x"), 16)
130 && !vendors.contains(&id)
131 {
132 vendors.push(id);
133 }
134 }
135 vendors
136}
137
138fn is_presentation_broken(
146 vendor_id: u32,
147 gpu_vendors: &[u32],
148 display_server: DisplayServer,
149) -> bool {
150 let has_intel = gpu_vendors.contains(&db::intel::VENDOR);
151 let has_nvidia = gpu_vendors.contains(&db::nvidia::VENDOR);
152 if !has_intel || !has_nvidia {
153 return false;
154 }
155 match (display_server, vendor_id) {
156 (DisplayServer::X11, db::intel::VENDOR) => true,
158 (DisplayServer::Wayland, db::nvidia::VENDOR) => true,
160 _ => false,
161 }
162}
163
164fn inspect_adapter(
165 phd: vk::PhysicalDevice,
166 instance: &super::Instance,
167 driver_api_version: u32,
168 desc: &crate::ContextDesc,
169 gpu_vendors: &[u32],
170 display_server: DisplayServer,
171) -> Option<AdapterCapabilities> {
172 let mut inline_uniform_block_properties =
173 vk::PhysicalDeviceInlineUniformBlockPropertiesEXT::default();
174 let mut timeline_semaphore_properties =
175 vk::PhysicalDeviceTimelineSemaphorePropertiesKHR::default();
176 let mut descriptor_indexing_properties =
177 vk::PhysicalDeviceDescriptorIndexingPropertiesEXT::default();
178 let mut acceleration_structure_properties =
179 vk::PhysicalDeviceAccelerationStructurePropertiesKHR::default();
180 let mut portability_subset_properties =
181 vk::PhysicalDevicePortabilitySubsetPropertiesKHR::default();
182
183 let mut driver_properties = vk::PhysicalDeviceDriverPropertiesKHR::default();
184 let mut properties2_khr = vk::PhysicalDeviceProperties2KHR::default()
185 .push_next(&mut inline_uniform_block_properties)
186 .push_next(&mut timeline_semaphore_properties)
187 .push_next(&mut descriptor_indexing_properties)
188 .push_next(&mut acceleration_structure_properties)
189 .push_next(&mut portability_subset_properties)
190 .push_next(&mut driver_properties);
191 unsafe {
192 instance
193 .get_physical_device_properties2
194 .get_physical_device_properties2(phd, &mut properties2_khr);
195 }
196
197 let properties = properties2_khr.properties;
198 let name = unsafe { ffi::CStr::from_ptr(properties.device_name.as_ptr()) };
199 log::info!("Adapter: {:?}", name);
200
201 if let Some(device_id) = desc.device_id
202 && device_id != properties.device_id
203 {
204 log::info!("Rejected device ID 0x{:X}", properties.device_id);
205 return None;
206 }
207
208 let api_version = properties.api_version.min(driver_api_version);
209 if api_version < vk::API_VERSION_1_1 {
210 log::warn!("\tRejected for API version {}", api_version);
211 return None;
212 }
213
214 let supported_extension_properties = unsafe {
215 instance
216 .core
217 .enumerate_device_extension_properties(phd)
218 .unwrap()
219 };
220 let supported_extensions = supported_extension_properties
221 .iter()
222 .map(|ext_prop| unsafe { ffi::CStr::from_ptr(ext_prop.extension_name.as_ptr()) })
223 .collect::<Vec<_>>();
224 for extension in REQUIRED_DEVICE_EXTENSIONS {
225 if !supported_extensions.contains(extension) {
226 log::warn!(
227 "Rejected for device extension {:?} not supported. Please update the driver!",
228 extension
229 );
230 return None;
231 }
232 }
233
234 let bugs = SystemBugs {
235 intel_fix_descriptor_pool_leak: cfg!(windows) && properties.vendor_id == db::intel::VENDOR,
236 };
237
238 let queue_family_index = 0; if desc.presentation
240 && is_presentation_broken(properties.vendor_id, gpu_vendors, display_server)
241 {
242 log::warn!(
243 "Rejecting adapter {:?} (vendor 0x{:X}): cannot present on {:?} in Intel+NVIDIA PRIME configuration",
244 name,
245 properties.vendor_id,
246 display_server,
247 );
248 return None;
249 }
250
251 let mut inline_uniform_block_features =
252 vk::PhysicalDeviceInlineUniformBlockFeaturesEXT::default();
253 let mut timeline_semaphore_features = vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::default();
254 let mut dynamic_rendering_features = vk::PhysicalDeviceDynamicRenderingFeaturesKHR::default();
255 let mut descriptor_indexing_features =
256 vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::default();
257 let mut buffer_device_address_features =
258 vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR::default();
259 let mut acceleration_structure_features =
260 vk::PhysicalDeviceAccelerationStructureFeaturesKHR::default();
261 let mut ray_query_features = vk::PhysicalDeviceRayQueryFeaturesKHR::default();
262 let mut cooperative_matrix_features = vk::PhysicalDeviceCooperativeMatrixFeaturesKHR::default();
263 let mut vulkan_memory_model_features = vk::PhysicalDeviceVulkanMemoryModelFeatures::default();
264 let mut float16_int8_features = vk::PhysicalDeviceShaderFloat16Int8Features::default();
265 let mut storage_16bit_features = vk::PhysicalDevice16BitStorageFeatures::default();
266 let mut features2_khr = vk::PhysicalDeviceFeatures2::default()
267 .push_next(&mut inline_uniform_block_features)
268 .push_next(&mut timeline_semaphore_features)
269 .push_next(&mut dynamic_rendering_features)
270 .push_next(&mut descriptor_indexing_features)
271 .push_next(&mut buffer_device_address_features)
272 .push_next(&mut acceleration_structure_features)
273 .push_next(&mut ray_query_features)
274 .push_next(&mut cooperative_matrix_features)
275 .push_next(&mut vulkan_memory_model_features)
276 .push_next(&mut float16_int8_features)
277 .push_next(&mut storage_16bit_features);
278 unsafe {
279 instance
280 .get_physical_device_properties2
281 .get_physical_device_features2(phd, &mut features2_khr)
282 };
283
284 let dual_source_blending = features2_khr.features.dual_src_blend != 0;
285 let shader_float16 = float16_int8_features.shader_float16 != 0;
286
287 let has_inline_ub = supported_extensions.contains(&vk::EXT_INLINE_UNIFORM_BLOCK_NAME)
288 && inline_uniform_block_properties.max_inline_uniform_block_size
289 >= crate::limits::PLAIN_DATA_SIZE
290 && inline_uniform_block_properties.max_descriptor_set_inline_uniform_blocks > 0
291 && inline_uniform_block_features.inline_uniform_block != 0;
292 let inline_uniform_blocks = has_inline_ub && properties.vendor_id != db::qualcomm::VENDOR;
295 if !inline_uniform_blocks {
296 log::info!(
297 "Inline uniform blocks disabled (supported={}, vendor=0x{:X}). Using UBO fallback.",
298 has_inline_ub,
299 properties.vendor_id,
300 );
301 }
302
303 if timeline_semaphore_features.timeline_semaphore == 0 {
304 log::warn!(
305 "\tRejected for timeline semaphore. Properties = {:?}, Features = {:?}",
306 timeline_semaphore_properties,
307 timeline_semaphore_features,
308 );
309 return None;
310 }
311
312 if dynamic_rendering_features.dynamic_rendering == 0 {
313 log::warn!(
314 "\tRejected for dynamic rendering. Features = {:?}",
315 dynamic_rendering_features,
316 );
317 return None;
318 }
319
320 let external_memory = supported_extensions.contains(&vk::KHR_EXTERNAL_MEMORY_NAME);
321 let external_memory = external_memory
322 && supported_extensions.contains(if cfg!(target_os = "windows") {
323 &vk::KHR_EXTERNAL_MEMORY_WIN32_NAME
324 } else {
325 &vk::KHR_EXTERNAL_MEMORY_FD_NAME
326 });
327
328 let timing = if properties.limits.timestamp_compute_and_graphics == vk::FALSE {
329 log::info!("No timing because of queue support");
330 false
331 } else {
332 true
333 };
334
335 let buffer_device_address = buffer_device_address_features.buffer_device_address == vk::TRUE
336 && (properties.api_version >= vk::API_VERSION_1_2
337 || supported_extensions.contains(&vk::KHR_BUFFER_DEVICE_ADDRESS_NAME));
338
339 let supports_descriptor_indexing = api_version >= vk::API_VERSION_1_2
340 || supported_extensions.contains(&vk::EXT_DESCRIPTOR_INDEXING_NAME);
341 let binding_array = supports_descriptor_indexing
342 && descriptor_indexing_features.descriptor_binding_partially_bound == vk::TRUE
343 && descriptor_indexing_features.shader_storage_buffer_array_non_uniform_indexing
344 == vk::TRUE
345 && descriptor_indexing_features.shader_sampled_image_array_non_uniform_indexing == vk::TRUE;
346
347 let ray_tracing = if !desc.ray_tracing {
348 log::info!("Ray tracing disabled by configuration");
349 None
350 } else if !supported_extensions.contains(&vk::KHR_ACCELERATION_STRUCTURE_NAME)
351 || !supported_extensions.contains(&vk::KHR_RAY_QUERY_NAME)
352 {
353 log::info!("No ray tracing extensions are supported");
354 None
355 } else if descriptor_indexing_properties.max_per_stage_update_after_bind_resources == vk::FALSE
356 || descriptor_indexing_features.descriptor_binding_partially_bound == vk::FALSE
357 || descriptor_indexing_features.shader_storage_buffer_array_non_uniform_indexing
358 == vk::FALSE
359 || descriptor_indexing_features.shader_sampled_image_array_non_uniform_indexing == vk::FALSE
360 {
361 log::info!(
362 "No ray tracing because of the descriptor indexing. Properties = {:?}. Features = {:?}",
363 descriptor_indexing_properties,
364 descriptor_indexing_features
365 );
366 None
367 } else if buffer_device_address_features.buffer_device_address == vk::FALSE {
368 log::info!(
369 "No ray tracing because of the buffer device address. Features = {:?}",
370 buffer_device_address_features
371 );
372 None
373 } else if acceleration_structure_properties.max_geometry_count == 0
374 || acceleration_structure_features.acceleration_structure == vk::FALSE
375 {
376 log::info!(
377 "No ray tracing because of the acceleration structure. Properties = {:?}. Features = {:?}",
378 acceleration_structure_properties,
379 acceleration_structure_features
380 );
381 None
382 } else if ray_query_features.ray_query == vk::FALSE {
383 log::info!(
384 "No ray tracing because of the ray query. Features = {:?}",
385 ray_query_features
386 );
387 None
388 } else {
389 log::info!("Ray tracing is supported");
390 log::debug!("Ray tracing properties: {acceleration_structure_properties:#?}");
391 Some(RayTracingCapabilities {
392 min_scratch_buffer_alignment: acceleration_structure_properties
393 .min_acceleration_structure_scratch_offset_alignment
394 as u64,
395 })
396 };
397
398 let cooperative_matrix = if !supported_extensions.contains(&vk::KHR_COOPERATIVE_MATRIX_NAME) {
399 log::info!("No cooperative matrix extension support");
400 crate::CooperativeMatrix::default()
401 } else if cooperative_matrix_features.cooperative_matrix == vk::FALSE {
402 log::info!(
403 "No cooperative matrix feature support. Features = {:?}",
404 cooperative_matrix_features
405 );
406 crate::CooperativeMatrix::default()
407 } else if vulkan_memory_model_features.vulkan_memory_model == vk::FALSE {
408 log::info!(
409 "No Vulkan memory model support (required for cooperative matrix). Features = {:?}",
410 vulkan_memory_model_features
411 );
412 crate::CooperativeMatrix::default()
413 } else {
414 let coop_props = unsafe {
417 instance
418 .cooperative_matrix
419 .get_physical_device_cooperative_matrix_properties(phd)
420 .unwrap_or_default()
421 };
422 let find_tile = |a_type, b_type, c_type, result_type| {
423 [8u32, 16].into_iter().find(|&size| {
424 coop_props.iter().any(|p| {
425 p.m_size == size
426 && p.n_size == size
427 && p.k_size == size
428 && p.a_type == a_type
429 && p.b_type == b_type
430 && p.c_type == c_type
431 && p.result_type == result_type
432 && p.scope == vk::ScopeKHR::SUBGROUP
433 })
434 })
435 };
436 let f32t = vk::ComponentTypeKHR::FLOAT32;
437 let f16t = vk::ComponentTypeKHR::FLOAT16;
438 let f32_tile = find_tile(f32t, f32t, f32t, f32t).unwrap_or(0);
439 let f16_tile = if float16_int8_features.shader_float16 != 0
440 && storage_16bit_features.storage_buffer16_bit_access != 0
441 {
442 find_tile(f16t, f16t, f32t, f32t).unwrap_or(0)
443 } else {
444 0
445 };
446 let cm = crate::CooperativeMatrix { f32_tile, f16_tile };
447 if cm.is_supported() {
448 log::info!(
449 "Cooperative matrix: f32 tile={}, f16 tile={}",
450 cm.f32_tile,
451 cm.f16_tile,
452 );
453 } else {
454 log::info!(
455 "Cooperative matrix extension present but no usable config. Properties: {:?}",
456 coop_props
457 );
458 }
459 cm
460 };
461 let shader_float16 = shader_float16 || cooperative_matrix.f16_tile > 0;
463
464 let buffer_marker = supported_extensions.contains(&vk::AMD_BUFFER_MARKER_NAME);
465 let shader_info = supported_extensions.contains(&vk::AMD_SHADER_INFO_NAME);
466 let full_screen_exclusive = supported_extensions.contains(&vk::EXT_FULL_SCREEN_EXCLUSIVE_NAME);
467 let memory_budget = supported_extensions.contains(&vk::EXT_MEMORY_BUDGET_NAME);
468
469 let device_information = unsafe {
470 crate::DeviceInformation {
471 is_software_emulated: properties.device_type == vk::PhysicalDeviceType::CPU,
472 device_name: ffi::CStr::from_ptr(properties.device_name.as_ptr())
473 .to_string_lossy()
474 .to_string(),
475 driver_name: ffi::CStr::from_ptr(driver_properties.driver_name.as_ptr())
476 .to_string_lossy()
477 .to_string(),
478 driver_info: ffi::CStr::from_ptr(driver_properties.driver_info.as_ptr())
479 .to_string_lossy()
480 .to_string(),
481 }
482 };
483
484 Some(AdapterCapabilities {
485 api_version,
486 properties,
487 device_information,
488 queue_family_index,
489 layered: portability_subset_properties.min_vertex_input_binding_stride_alignment != 0,
490 binding_array,
491 ray_tracing,
492 buffer_device_address,
493 inline_uniform_blocks,
494 buffer_marker,
495 shader_info,
496 full_screen_exclusive,
497 external_memory,
498 timing,
499 dual_source_blending,
500 shader_float16,
501 cooperative_matrix,
502 memory_budget,
503 bugs,
504 })
505}
506
507impl super::Context {
508 pub unsafe fn init(desc: crate::ContextDesc) -> Result<Self, NotSupportedError> {
509 let entry = match unsafe { ash::Entry::load() } {
510 Ok(entry) => entry,
511 Err(err) => {
512 log::error!("Missing Vulkan entry points: {:?}", err);
513 return Err(crate::PlatformError::loading(err).into());
514 }
515 };
516 let driver_api_version = match unsafe { entry.try_enumerate_instance_version() } {
517 Ok(Some(version)) => version,
519 Ok(None) => return Err(NotSupportedError::NoSupportedDeviceFound),
520 Err(err) => {
521 log::error!("try_enumerate_instance_version: {:?}", err);
522 return Err(crate::PlatformError::init(err).into());
523 }
524 };
525
526 if let Some(ref xr) = desc.xr {
527 let reqs = xr
528 .instance
529 .graphics_requirements::<openxr::Vulkan>(xr.system_id)
530 .unwrap();
531 let driver_api_version_xr = openxr::Version::new(
532 vk::api_version_major(driver_api_version) as u16,
533 vk::api_version_minor(driver_api_version) as u16,
534 vk::api_version_patch(driver_api_version),
535 );
536 if driver_api_version_xr < reqs.min_api_version_supported
537 || driver_api_version_xr.major() > reqs.max_api_version_supported.major()
538 {
539 return Err(NotSupportedError::NoSupportedDeviceFound);
540 }
541 }
542
543 let supported_layers = match unsafe { entry.enumerate_instance_layer_properties() } {
544 Ok(layers) => layers,
545 Err(err) => {
546 log::error!("enumerate_instance_layer_properties: {:?}", err);
547 return Err(crate::PlatformError::init(err).into());
548 }
549 };
550 let supported_layer_names = supported_layers
551 .iter()
552 .map(|properties| unsafe { ffi::CStr::from_ptr(properties.layer_name.as_ptr()) })
553 .collect::<Vec<_>>();
554
555 let mut layers: Vec<&'static ffi::CStr> = Vec::new();
556 let mut requested_layers = Vec::<&ffi::CStr>::new();
557 if desc.validation {
558 requested_layers.push(layer::KHRONOS_VALIDATION);
559 }
560 if desc.overlay {
561 requested_layers.push(layer::MESA_OVERLAY);
562 }
563 for name in requested_layers {
564 if supported_layer_names.contains(&name) {
565 layers.push(name);
566 } else {
567 log::warn!("Requested layer is not found: {:?}", name);
568 }
569 }
570
571 let supported_instance_extension_properties =
572 match unsafe { entry.enumerate_instance_extension_properties(None) } {
573 Ok(extensions) => extensions,
574 Err(err) => {
575 log::error!("enumerate_instance_extension_properties: {:?}", err);
576 return Err(crate::PlatformError::init(err).into());
577 }
578 };
579 let supported_instance_extensions = supported_instance_extension_properties
580 .iter()
581 .map(|ext_prop| unsafe { ffi::CStr::from_ptr(ext_prop.extension_name.as_ptr()) })
582 .collect::<Vec<_>>();
583
584 let core_instance = {
585 let mut create_flags = vk::InstanceCreateFlags::empty();
586
587 let mut instance_extensions = vec![
588 vk::EXT_DEBUG_UTILS_NAME,
589 vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_NAME,
590 ];
591 if desc.presentation {
592 instance_extensions.push(vk::KHR_SURFACE_NAME);
593 instance_extensions.push(vk::KHR_GET_SURFACE_CAPABILITIES2_NAME);
594 let candidates = [
595 vk::KHR_WAYLAND_SURFACE_NAME,
596 vk::KHR_XCB_SURFACE_NAME,
597 vk::KHR_XLIB_SURFACE_NAME,
598 vk::KHR_WIN32_SURFACE_NAME,
599 vk::KHR_ANDROID_SURFACE_NAME,
600 vk::EXT_SWAPCHAIN_COLORSPACE_NAME,
601 ];
602 for candidate in candidates.iter() {
603 if supported_instance_extensions.contains(candidate) {
604 log::info!("Presentation support: {:?}", candidate);
605 instance_extensions.push(candidate);
606 }
607 }
608 }
609
610 let mut enabled_instance_extensions = Vec::with_capacity(instance_extensions.len());
611 for inst_ext in instance_extensions.drain(..) {
612 if supported_instance_extensions.contains(&inst_ext) {
613 enabled_instance_extensions.push(inst_ext);
614 } else if is_promoted_instance_extension(inst_ext, driver_api_version) {
615 log::info!(
616 "Skipping promoted instance extension {:?} (core version {:x})",
617 inst_ext,
618 driver_api_version
619 );
620 } else {
621 log::error!("Instance extension {:?} is not supported", inst_ext);
622 return Err(NotSupportedError::NoSupportedDeviceFound);
623 }
624 }
625 if supported_instance_extensions.contains(&vk::KHR_PORTABILITY_ENUMERATION_NAME) {
626 log::info!("Enabling Vulkan Portability");
627 enabled_instance_extensions.push(vk::KHR_PORTABILITY_ENUMERATION_NAME);
628 create_flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
629 }
630
631 let app_info = vk::ApplicationInfo::default()
632 .engine_name(c"blade")
633 .engine_version(1)
634 .api_version(vk::HEADER_VERSION_COMPLETE);
635 let str_pointers = layers
636 .iter()
637 .chain(enabled_instance_extensions.iter())
638 .map(|&s| s.as_ptr())
639 .collect::<Vec<_>>();
640 let (layer_strings, extension_strings) = str_pointers.split_at(layers.len());
641 let create_info = vk::InstanceCreateInfo::default()
642 .application_info(&app_info)
643 .flags(create_flags)
644 .enabled_layer_names(layer_strings)
645 .enabled_extension_names(extension_strings);
646 if let Some(ref xr_desc) = desc.xr {
647 let get_instance_proc_addr: openxr::sys::platform::VkGetInstanceProcAddr =
648 unsafe { std::mem::transmute(entry.static_fn().get_instance_proc_addr) };
649 let raw_instance = unsafe {
650 xr_desc
651 .instance
652 .create_vulkan_instance(
653 xr_desc.system_id,
654 get_instance_proc_addr,
655 &create_info as *const _ as *const _,
656 )
657 .map_err(|_| NotSupportedError::NoSupportedDeviceFound)?
658 .map_err(|raw| crate::PlatformError::init(vk::Result::from_raw(raw)))?
659 };
660 unsafe {
661 ash::Instance::load(
662 entry.static_fn(),
663 vk::Instance::from_raw(raw_instance as _),
664 )
665 }
666 } else {
667 unsafe { entry.create_instance(&create_info, None) }
668 .map_err(crate::PlatformError::init)?
669 }
670 };
671
672 let instance =
673 super::Instance {
674 _debug_utils: ext::debug_utils::Instance::new(&entry, &core_instance),
675 get_physical_device_properties2:
676 khr::get_physical_device_properties2::Instance::new(&entry, &core_instance),
677 cooperative_matrix: khr::cooperative_matrix::Instance::new(&entry, &core_instance),
678 get_surface_capabilities2: if desc.presentation {
679 Some(khr::get_surface_capabilities2::Instance::new(
680 &entry,
681 &core_instance,
682 ))
683 } else {
684 None
685 },
686 surface: if desc.presentation {
687 Some(khr::surface::Instance::new(&entry, &core_instance))
688 } else {
689 None
690 },
691 core: core_instance,
692 };
693
694 let gpu_vendors = detect_gpu_vendors();
697 let display_server = detect_display_server();
698 log::info!(
699 "PCI GPU vendors: {:?}, display server: {:?}",
700 gpu_vendors
701 .iter()
702 .map(|v| format!("0x{v:04X}"))
703 .collect::<Vec<_>>(),
704 display_server,
705 );
706
707 let (physical_device, capabilities) = if let Some(ref xr_desc) = desc.xr {
708 let xr_physical_device = unsafe {
709 xr_desc
710 .instance
711 .vulkan_graphics_device(xr_desc.system_id, instance.core.handle().as_raw() as _)
712 .map_err(|_| NotSupportedError::NoSupportedDeviceFound)?
713 };
714 let physical_device = vk::PhysicalDevice::from_raw(xr_physical_device as _);
715 let capabilities = inspect_adapter(
716 physical_device,
717 &instance,
718 driver_api_version,
719 &desc,
720 &gpu_vendors,
721 display_server,
722 )
723 .ok_or(NotSupportedError::NoSupportedDeviceFound)?;
724 (physical_device, capabilities)
725 } else {
726 unsafe { instance.core.enumerate_physical_devices() }
727 .map_err(crate::PlatformError::init)?
728 .into_iter()
729 .find_map(|phd| {
730 inspect_adapter(
731 phd,
732 &instance,
733 driver_api_version,
734 &desc,
735 &gpu_vendors,
736 display_server,
737 )
738 .map(|caps| (phd, caps))
739 })
740 .ok_or(NotSupportedError::NoSupportedDeviceFound)?
741 };
742
743 log::debug!("Adapter {:#?}", capabilities);
744 let mut min_buffer_alignment = 1;
745 if let Some(ref rt) = capabilities.ray_tracing {
746 min_buffer_alignment = min_buffer_alignment.max(rt.min_scratch_buffer_alignment);
747 }
748
749 let device_core = {
750 let family_info = vk::DeviceQueueCreateInfo::default()
751 .queue_family_index(capabilities.queue_family_index)
752 .queue_priorities(&[1.0]);
753 let family_infos = [family_info];
754
755 let mut device_extensions = REQUIRED_DEVICE_EXTENSIONS.to_vec();
756 if capabilities.inline_uniform_blocks {
757 device_extensions.push(vk::EXT_INLINE_UNIFORM_BLOCK_NAME);
758 }
759 if desc.presentation {
760 device_extensions.push(vk::KHR_SWAPCHAIN_NAME);
761 }
762 if capabilities.layered {
763 log::info!("Enabling Vulkan Portability");
764 device_extensions.push(vk::KHR_PORTABILITY_SUBSET_NAME);
765 }
766 let needs_descriptor_indexing =
767 capabilities.binding_array || capabilities.ray_tracing.is_some();
768 if needs_descriptor_indexing && capabilities.api_version < vk::API_VERSION_1_2 {
769 device_extensions.push(vk::EXT_DESCRIPTOR_INDEXING_NAME);
770 }
771 if capabilities.ray_tracing.is_some() {
772 if capabilities.api_version < vk::API_VERSION_1_2 {
773 device_extensions.push(vk::KHR_BUFFER_DEVICE_ADDRESS_NAME);
774 device_extensions.push(vk::KHR_SHADER_FLOAT_CONTROLS_NAME);
775 device_extensions.push(vk::KHR_SPIRV_1_4_NAME);
776 }
777 device_extensions.push(vk::KHR_DEFERRED_HOST_OPERATIONS_NAME);
778 device_extensions.push(vk::KHR_ACCELERATION_STRUCTURE_NAME);
779 device_extensions.push(vk::KHR_RAY_QUERY_NAME);
780 } else if capabilities.buffer_device_address
781 && capabilities.api_version < vk::API_VERSION_1_2
782 {
783 device_extensions.push(vk::KHR_BUFFER_DEVICE_ADDRESS_NAME);
784 }
785 if capabilities.buffer_marker {
786 device_extensions.push(vk::AMD_BUFFER_MARKER_NAME);
787 }
788 if capabilities.shader_info {
789 device_extensions.push(vk::AMD_SHADER_INFO_NAME);
790 }
791 if capabilities.full_screen_exclusive {
792 device_extensions.push(vk::EXT_FULL_SCREEN_EXCLUSIVE_NAME);
793 }
794 if capabilities.external_memory {
795 device_extensions.push(vk::KHR_EXTERNAL_MEMORY_NAME);
796 device_extensions.push(if cfg!(target_os = "windows") {
797 vk::KHR_EXTERNAL_MEMORY_WIN32_NAME
798 } else {
799 vk::KHR_EXTERNAL_MEMORY_FD_NAME
800 });
801 }
802 if capabilities.cooperative_matrix.is_supported() {
803 device_extensions.push(vk::KHR_COOPERATIVE_MATRIX_NAME);
804 if capabilities.api_version < vk::API_VERSION_1_2 {
805 device_extensions.push(vk::KHR_VULKAN_MEMORY_MODEL_NAME);
806 }
807 }
808 if capabilities.memory_budget {
809 device_extensions.push(vk::EXT_MEMORY_BUDGET_NAME);
810 }
811
812 let str_pointers = device_extensions
813 .iter()
814 .map(|&s| s.as_ptr())
815 .collect::<Vec<_>>();
816
817 let mut ext_inline_uniform_block = vk::PhysicalDeviceInlineUniformBlockFeaturesEXT {
818 inline_uniform_block: vk::TRUE,
819 ..Default::default()
820 };
821 let mut khr_timeline_semaphore = vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR {
822 timeline_semaphore: vk::TRUE,
823 ..Default::default()
824 };
825 let mut khr_dynamic_rendering = vk::PhysicalDeviceDynamicRenderingFeaturesKHR {
826 dynamic_rendering: vk::TRUE,
827 ..Default::default()
828 };
829 let mut device_create_info = vk::DeviceCreateInfo::default()
830 .queue_create_infos(&family_infos)
831 .enabled_extension_names(&str_pointers)
832 .push_next(&mut khr_timeline_semaphore)
833 .push_next(&mut khr_dynamic_rendering);
834 if capabilities.inline_uniform_blocks {
835 device_create_info = device_create_info.push_next(&mut ext_inline_uniform_block);
836 }
837
838 let mut ext_descriptor_indexing;
839 if needs_descriptor_indexing {
840 ext_descriptor_indexing = vk::PhysicalDeviceDescriptorIndexingFeaturesEXT {
841 shader_storage_buffer_array_non_uniform_indexing: vk::TRUE,
842 shader_sampled_image_array_non_uniform_indexing: vk::TRUE,
843 descriptor_binding_partially_bound: vk::TRUE,
844 ..Default::default()
845 };
846 device_create_info = device_create_info.push_next(&mut ext_descriptor_indexing);
847 }
848
849 let mut khr_buffer_device_address;
850 if capabilities.buffer_device_address {
851 khr_buffer_device_address = vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR {
852 buffer_device_address: vk::TRUE,
853 ..Default::default()
854 };
855 device_create_info = device_create_info.push_next(&mut khr_buffer_device_address);
856 }
857
858 let mut khr_acceleration_structure;
859 let mut khr_ray_query;
860 if capabilities.ray_tracing.is_some() {
861 khr_acceleration_structure = vk::PhysicalDeviceAccelerationStructureFeaturesKHR {
862 acceleration_structure: vk::TRUE,
863 ..Default::default()
864 };
865 khr_ray_query = vk::PhysicalDeviceRayQueryFeaturesKHR {
866 ray_query: vk::TRUE,
867 ..Default::default()
868 };
869 device_create_info = device_create_info
870 .push_next(&mut khr_acceleration_structure)
871 .push_next(&mut khr_ray_query);
872 }
873
874 let mut khr_float16_int8;
875 let mut storage_16bit;
876 if capabilities.shader_float16 {
877 khr_float16_int8 = vk::PhysicalDeviceShaderFloat16Int8Features {
878 shader_float16: vk::TRUE,
879 ..Default::default()
880 };
881 device_create_info = device_create_info.push_next(&mut khr_float16_int8);
882 }
883 if capabilities.cooperative_matrix.f16_tile > 0 {
884 storage_16bit = vk::PhysicalDevice16BitStorageFeatures {
885 storage_buffer16_bit_access: vk::TRUE,
886 uniform_and_storage_buffer16_bit_access: vk::TRUE,
887 ..Default::default()
888 };
889 device_create_info = device_create_info.push_next(&mut storage_16bit);
890 }
891
892 let mut khr_cooperative_matrix;
893 let mut vulkan_memory_model;
894 if capabilities.cooperative_matrix.is_supported() {
895 khr_cooperative_matrix = vk::PhysicalDeviceCooperativeMatrixFeaturesKHR {
896 cooperative_matrix: vk::TRUE,
897 ..Default::default()
898 };
899 vulkan_memory_model = vk::PhysicalDeviceVulkanMemoryModelFeatures {
900 vulkan_memory_model: vk::TRUE,
901 ..Default::default()
902 };
903 device_create_info = device_create_info
904 .push_next(&mut khr_cooperative_matrix)
905 .push_next(&mut vulkan_memory_model);
906 }
907
908 let mut core_features = vk::PhysicalDeviceFeatures::default();
909 if capabilities.dual_source_blending {
910 core_features.dual_src_blend = vk::TRUE;
911 }
912
913 let mut device_features2 =
914 vk::PhysicalDeviceFeatures2::default().features(core_features);
915
916 device_create_info = device_create_info.push_next(&mut device_features2);
917
918 if let Some(ref xr_desc) = desc.xr {
919 let get_instance_proc_addr: openxr::sys::platform::VkGetInstanceProcAddr =
920 unsafe { std::mem::transmute(entry.static_fn().get_instance_proc_addr) };
921 unsafe {
922 let raw_device = xr_desc
923 .instance
924 .create_vulkan_device(
925 xr_desc.system_id,
926 get_instance_proc_addr,
927 physical_device.as_raw() as _,
928 &device_create_info as *const _ as *const _,
929 )
930 .map_err(|_| NotSupportedError::NoSupportedDeviceFound)?
931 .map_err(|raw| crate::PlatformError::init(vk::Result::from_raw(raw)))?;
932 ash::Device::load(
933 instance.core.fp_v1_0(),
934 vk::Device::from_raw(raw_device as _),
935 )
936 }
937 } else {
938 unsafe {
939 instance
940 .core
941 .create_device(physical_device, &device_create_info, None)
942 .map_err(crate::PlatformError::init)?
943 }
944 }
945 };
946
947 let device = super::Device {
948 swapchain: if desc.presentation {
949 Some(khr::swapchain::Device::new(&instance.core, &device_core))
950 } else {
951 None
952 },
953 debug_utils: ext::debug_utils::Device::new(&instance.core, &device_core),
954 timeline_semaphore: khr::timeline_semaphore::Device::new(&instance.core, &device_core),
955 dynamic_rendering: khr::dynamic_rendering::Device::new(&instance.core, &device_core),
956 ray_tracing: if let Some(ref caps) = capabilities.ray_tracing {
957 Some(super::RayTracingDevice {
958 acceleration_structure: khr::acceleration_structure::Device::new(
959 &instance.core,
960 &device_core,
961 ),
962 scratch_buffer_alignment: caps.min_scratch_buffer_alignment,
963 })
964 } else {
965 None
966 },
967 buffer_device_address: capabilities.buffer_device_address,
968 inline_uniform_blocks: capabilities.inline_uniform_blocks,
969 buffer_marker: if capabilities.buffer_marker && desc.validation {
970 Some(amd::buffer_marker::Device::new(
971 &instance.core,
972 &device_core,
973 ))
974 } else {
975 None
976 },
977 shader_info: if capabilities.shader_info {
978 Some(amd::shader_info::Device::new(&instance.core, &device_core))
979 } else {
980 None
981 },
982 full_screen_exclusive: if desc.presentation && capabilities.full_screen_exclusive {
983 Some(ext::full_screen_exclusive::Device::new(
984 &instance.core,
985 &device_core,
986 ))
987 } else {
988 None
989 },
990 external_memory: if capabilities.external_memory {
991 #[cfg(not(target_os = "windows"))]
992 use khr::external_memory_fd::Device;
993 #[cfg(target_os = "windows")]
994 use khr::external_memory_win32::Device;
995
996 Some(Device::new(&instance.core, &device_core))
997 } else {
998 None
999 },
1000 core: device_core,
1001 device_information: capabilities.device_information,
1002 command_scope: if desc.capture {
1003 Some(super::CommandScopeDevice {})
1004 } else {
1005 None
1006 },
1007 timing: if desc.timing && capabilities.timing {
1008 Some(super::TimingDevice {
1009 period: capabilities.properties.limits.timestamp_period,
1010 })
1011 } else {
1012 None
1013 },
1014 workarounds: super::Workarounds {
1016 extra_sync_src_access: vk::AccessFlags::TRANSFER_WRITE,
1017 extra_sync_dst_access: vk::AccessFlags::TRANSFER_WRITE
1018 | vk::AccessFlags::TRANSFER_READ
1019 | if capabilities.ray_tracing.is_some() {
1020 vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR
1021 } else {
1022 vk::AccessFlags::NONE
1023 },
1024 extra_descriptor_pool_create_flags: if capabilities
1025 .bugs
1026 .intel_fix_descriptor_pool_leak
1027 {
1028 vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET
1029 } else {
1030 vk::DescriptorPoolCreateFlags::empty()
1031 },
1032 },
1033 };
1034
1035 let memory_manager = {
1036 let mem_properties = unsafe {
1037 instance
1038 .core
1039 .get_physical_device_memory_properties(physical_device)
1040 };
1041 let memory_types =
1042 &mem_properties.memory_types[..mem_properties.memory_type_count as usize];
1043 let limits = &capabilities.properties.limits;
1044 let config = gpu_alloc::Config::i_am_prototyping(); let properties = gpu_alloc::DeviceProperties {
1047 max_memory_allocation_count: limits.max_memory_allocation_count,
1048 max_memory_allocation_size: u64::MAX, non_coherent_atom_size: limits.non_coherent_atom_size,
1050 memory_types: memory_types
1051 .iter()
1052 .map(|memory_type| gpu_alloc::MemoryType {
1053 props: gpu_alloc::MemoryPropertyFlags::from_bits_truncate(
1054 memory_type.property_flags.as_raw() as u8,
1055 ),
1056 heap: memory_type.heap_index,
1057 })
1058 .collect(),
1059 memory_heaps: mem_properties.memory_heaps
1060 [..mem_properties.memory_heap_count as usize]
1061 .iter()
1062 .map(|&memory_heap| gpu_alloc::MemoryHeap {
1063 size: memory_heap.size,
1064 })
1065 .collect(),
1066 buffer_device_address: capabilities.buffer_device_address,
1067 };
1068
1069 let known_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL
1070 | vk::MemoryPropertyFlags::HOST_VISIBLE
1071 | vk::MemoryPropertyFlags::HOST_COHERENT
1072 | vk::MemoryPropertyFlags::HOST_CACHED
1073 | vk::MemoryPropertyFlags::LAZILY_ALLOCATED;
1074 let valid_ash_memory_types = memory_types.iter().enumerate().fold(0, |u, (i, mem)| {
1075 if !known_memory_flags.contains(mem.property_flags) {
1076 log::debug!(
1077 "Skipping memory type={} for having unknown flags: {:?}",
1078 i,
1079 mem.property_flags & !known_memory_flags
1080 );
1081 u
1082 } else if mem
1083 .property_flags
1084 .contains(vk::MemoryPropertyFlags::HOST_VISIBLE)
1085 && !mem
1086 .property_flags
1087 .contains(vk::MemoryPropertyFlags::HOST_COHERENT)
1088 {
1089 log::debug!("Skipping memory type={} for lack of host coherency", i);
1091 u
1092 } else {
1093 u | (1 << i)
1094 }
1095 });
1096 super::MemoryManager {
1097 allocator: gpu_alloc::GpuAllocator::new(config, properties),
1098 slab: slab::Slab::new(),
1099 valid_ash_memory_types,
1100 }
1101 };
1102
1103 let queue = unsafe {
1104 device
1105 .core
1106 .get_device_queue(capabilities.queue_family_index, 0)
1107 };
1108 let last_progress = 0;
1109 let mut timeline_info = vk::SemaphoreTypeCreateInfo {
1110 semaphore_type: vk::SemaphoreType::TIMELINE,
1111 initial_value: last_progress,
1112 ..Default::default()
1113 };
1114 let timeline_semaphore_create_info =
1115 vk::SemaphoreCreateInfo::default().push_next(&mut timeline_info);
1116 let timeline_semaphore = unsafe {
1117 device
1118 .core
1119 .create_semaphore(&timeline_semaphore_create_info, None)
1120 .unwrap()
1121 };
1122
1123 let mut naga_flags = spv::WriterFlags::FORCE_POINT_SIZE;
1124 let shader_debug_path = if desc.validation || desc.capture {
1125 use std::{env, fs};
1126 naga_flags |= spv::WriterFlags::DEBUG;
1127 let dir = env::temp_dir().join("blade");
1128 let _ = fs::create_dir(&dir);
1129 Some(dir)
1130 } else {
1131 None
1132 };
1133
1134 let xr = if let Some(ref xr_desc) = desc.xr {
1135 let session_info = openxr::vulkan::SessionCreateInfo {
1136 instance: instance.core.handle().as_raw() as _,
1137 physical_device: physical_device.as_raw() as _,
1138 device: device.core.handle().as_raw() as _,
1139 queue_family_index: capabilities.queue_family_index,
1140 queue_index: 0,
1141 };
1142 match unsafe {
1143 xr_desc
1144 .instance
1145 .create_session::<openxr::Vulkan>(xr_desc.system_id, &session_info)
1146 } {
1147 Ok((session, frame_wait, frame_stream)) => {
1148 let view_type = openxr::ViewConfigurationType::PRIMARY_STEREO;
1149 let environment_blend_mode = xr_desc
1150 .instance
1151 .enumerate_environment_blend_modes(xr_desc.system_id, view_type)
1152 .ok()
1153 .and_then(|modes| modes.first().copied())
1154 .unwrap_or(openxr::EnvironmentBlendMode::OPAQUE);
1155 let space = match session.create_reference_space(
1156 openxr::ReferenceSpaceType::LOCAL,
1157 openxr::Posef::IDENTITY,
1158 ) {
1159 Ok(space) => space,
1160 Err(e) => {
1161 log::error!("Failed to create OpenXR local space: {e}");
1162 return Err(NotSupportedError::NoSupportedDeviceFound);
1163 }
1164 };
1165 Some(Mutex::new(super::XrSessionState {
1166 instance: xr_desc.instance.clone(),
1167 system_id: xr_desc.system_id,
1168 session,
1169 frame_wait,
1170 frame_stream,
1171 view_type,
1172 environment_blend_mode,
1173 space: Some(space),
1174 predicted_display_time: None,
1175 }))
1176 }
1177 Err(e) => {
1178 log::error!("Failed to create OpenXR session: {e}");
1179 return Err(NotSupportedError::NoSupportedDeviceFound);
1180 }
1181 }
1182 } else {
1183 None
1184 };
1185
1186 Ok(super::Context {
1187 memory: Mutex::new(memory_manager),
1188 device,
1189 queue_family_index: capabilities.queue_family_index,
1190 queue: Mutex::new(super::Queue {
1191 raw: queue,
1192 timeline_semaphore,
1193 last_progress,
1194 }),
1195 physical_device,
1196 naga_flags,
1197 shader_debug_path,
1198 min_buffer_alignment,
1199 min_uniform_buffer_offset_alignment: capabilities
1200 .properties
1201 .limits
1202 .min_uniform_buffer_offset_alignment,
1203 sample_count_flags: capabilities
1204 .properties
1205 .limits
1206 .framebuffer_color_sample_counts
1207 & capabilities
1208 .properties
1209 .limits
1210 .framebuffer_depth_sample_counts,
1211 dual_source_blending: capabilities.dual_source_blending,
1212 shader_float16: capabilities.shader_float16,
1213 cooperative_matrix: capabilities.cooperative_matrix,
1214 binding_array: capabilities.binding_array,
1215 memory_budget: capabilities.memory_budget,
1216 instance,
1217 entry,
1218 xr,
1219 })
1220 }
1221
1222 pub(super) fn set_object_name<T: vk::Handle>(&self, object: T, name: &str) {
1223 let name_cstr = ffi::CString::new(name).unwrap();
1224 let name_info = vk::DebugUtilsObjectNameInfoEXT::default()
1225 .object_handle(object)
1226 .object_name(&name_cstr);
1227 let _ = unsafe {
1228 self.device
1229 .debug_utils
1230 .set_debug_utils_object_name(&name_info)
1231 };
1232 }
1233
1234 pub fn capabilities(&self) -> crate::Capabilities {
1235 crate::Capabilities {
1236 binding_array: self.binding_array,
1237 ray_query: match self.device.ray_tracing {
1238 Some(_) => crate::ShaderVisibility::all(),
1239 None => crate::ShaderVisibility::empty(),
1240 },
1241 sample_count_mask: self.sample_count_flags.as_raw(),
1242 dual_source_blending: self.dual_source_blending,
1243 shader_float16: self.shader_float16,
1244 cooperative_matrix: self.cooperative_matrix,
1245 }
1246 }
1247
1248 pub fn device_information(&self) -> &crate::DeviceInformation {
1249 &self.device.device_information
1250 }
1251
1252 pub fn memory_stats(&self) -> crate::MemoryStats {
1253 if !self.memory_budget {
1254 return crate::MemoryStats::default();
1255 }
1256
1257 let mut budget_properties = vk::PhysicalDeviceMemoryBudgetPropertiesEXT::default();
1258 let mut mem_properties2 =
1259 vk::PhysicalDeviceMemoryProperties2::default().push_next(&mut budget_properties);
1260
1261 unsafe {
1262 self.instance
1263 .get_physical_device_properties2
1264 .get_physical_device_memory_properties2(self.physical_device, &mut mem_properties2);
1265 }
1266
1267 let heap_count = mem_properties2.memory_properties.memory_heap_count as usize;
1269 let heap_flags: Vec<_> = mem_properties2.memory_properties.memory_heaps[..heap_count]
1270 .iter()
1271 .map(|h| h.flags)
1272 .collect();
1273 let _ = mem_properties2;
1275
1276 let mut total_budget = 0u64;
1277 let mut total_usage = 0u64;
1278 for (i, flags) in heap_flags.iter().enumerate() {
1279 if flags.contains(vk::MemoryHeapFlags::DEVICE_LOCAL) {
1280 total_budget += budget_properties.heap_budget[i];
1281 total_usage += budget_properties.heap_usage[i];
1282 }
1283 }
1284
1285 crate::MemoryStats {
1286 budget: total_budget,
1287 usage: total_usage,
1288 }
1289 }
1290}
1291
1292impl Drop for super::Context {
1293 fn drop(&mut self) {
1294 if std::thread::panicking() {
1295 return;
1296 }
1297 unsafe {
1298 self.xr = None;
1299 if let Ok(queue) = self.queue.lock() {
1300 let _ = self.device.core.queue_wait_idle(queue.raw);
1301 self.device
1302 .core
1303 .destroy_semaphore(queue.timeline_semaphore, None);
1304 }
1305 self.device.core.destroy_device(None);
1306 self.instance.core.destroy_instance(None);
1307 }
1308 }
1309}