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