1use ash::{amd, ext, khr, vk};
2use naga::back::spv;
3use std::{ffi, fs, sync::Mutex};
4
5use crate::NotSupportedError;
6
7mod db {
8 pub mod intel {
9 pub const VENDOR: u32 = 0x8086;
10 }
11}
12mod layer {
13 use std::ffi::CStr;
14 pub const KHRONOS_VALIDATION: &CStr =
15 unsafe { CStr::from_bytes_with_nul_unchecked(b"VK_LAYER_KHRONOS_validation\0") };
16 pub const MESA_OVERLAY: &CStr =
17 unsafe { CStr::from_bytes_with_nul_unchecked(b"VK_LAYER_MESA_overlay\0") };
18}
19
20const REQUIRED_DEVICE_EXTENSIONS: &[&ffi::CStr] = &[
21 vk::EXT_INLINE_UNIFORM_BLOCK_NAME,
22 vk::KHR_TIMELINE_SEMAPHORE_NAME,
23 vk::KHR_DESCRIPTOR_UPDATE_TEMPLATE_NAME,
24 vk::KHR_DYNAMIC_RENDERING_NAME,
25];
26
27fn is_promoted_instance_extension(name: &ffi::CStr, api_version: u32) -> bool {
28 if api_version < vk::API_VERSION_1_1 {
29 return false;
30 }
31
32 name == vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_NAME
33 || name == vk::KHR_GET_SURFACE_CAPABILITIES2_NAME
34}
35
36#[derive(Debug)]
37struct RayTracingCapabilities {
38 min_scratch_buffer_alignment: u64,
39}
40
41#[derive(Debug)]
42struct SystemBugs {
43 intel_unable_to_present: bool,
45 intel_fix_descriptor_pool_leak: bool,
47}
48
49#[derive(Debug)]
50struct AdapterCapabilities {
51 api_version: u32,
52 properties: vk::PhysicalDeviceProperties,
53 device_information: crate::DeviceInformation,
54 queue_family_index: u32,
55 layered: bool,
56 ray_tracing: Option<RayTracingCapabilities>,
57 buffer_marker: bool,
58 shader_info: bool,
59 full_screen_exclusive: bool,
60 external_memory: bool,
61 timing: bool,
62 bugs: SystemBugs,
63}
64
65fn is_nvidia_prime_forced() -> bool {
67 match fs::read_to_string("/etc/prime-discrete") {
68 Ok(contents) => contents == "on\n",
69 Err(_) => false,
70 }
71}
72
73unsafe fn inspect_adapter(
74 phd: vk::PhysicalDevice,
75 instance: &super::Instance,
76 driver_api_version: u32,
77 desc: &crate::ContextDesc,
78) -> Option<AdapterCapabilities> {
79 let mut inline_uniform_block_properties =
80 vk::PhysicalDeviceInlineUniformBlockPropertiesEXT::default();
81 let mut timeline_semaphore_properties =
82 vk::PhysicalDeviceTimelineSemaphorePropertiesKHR::default();
83 let mut descriptor_indexing_properties =
84 vk::PhysicalDeviceDescriptorIndexingPropertiesEXT::default();
85 let mut acceleration_structure_properties =
86 vk::PhysicalDeviceAccelerationStructurePropertiesKHR::default();
87 let mut portability_subset_properties =
88 vk::PhysicalDevicePortabilitySubsetPropertiesKHR::default();
89
90 let mut driver_properties = vk::PhysicalDeviceDriverPropertiesKHR::default();
91 let mut properties2_khr = vk::PhysicalDeviceProperties2KHR::default()
92 .push_next(&mut inline_uniform_block_properties)
93 .push_next(&mut timeline_semaphore_properties)
94 .push_next(&mut descriptor_indexing_properties)
95 .push_next(&mut acceleration_structure_properties)
96 .push_next(&mut portability_subset_properties)
97 .push_next(&mut driver_properties);
98 instance
99 .get_physical_device_properties2
100 .get_physical_device_properties2(phd, &mut properties2_khr);
101
102 let properties = properties2_khr.properties;
103 let name = ffi::CStr::from_ptr(properties.device_name.as_ptr());
104 log::info!("Adapter: {:?}", name);
105
106 if desc.device_id != 0 && desc.device_id != properties.device_id {
107 log::info!("Rejected device ID 0x{:X}", properties.device_id);
108 return None;
109 }
110
111 let api_version = properties.api_version.min(driver_api_version);
112 if api_version < vk::API_VERSION_1_1 {
113 log::warn!("\tRejected for API version {}", api_version);
114 return None;
115 }
116
117 let supported_extension_properties = instance
118 .core
119 .enumerate_device_extension_properties(phd)
120 .unwrap();
121 let supported_extensions = supported_extension_properties
122 .iter()
123 .map(|ext_prop| ffi::CStr::from_ptr(ext_prop.extension_name.as_ptr()))
124 .collect::<Vec<_>>();
125 for extension in REQUIRED_DEVICE_EXTENSIONS {
126 if !supported_extensions.contains(extension) {
127 log::warn!(
128 "Rejected for device extension {:?} not supported. Please update the driver!",
129 extension
130 );
131 return None;
132 }
133 }
134
135 let bugs = SystemBugs {
136 intel_unable_to_present: is_nvidia_prime_forced()
140 && properties.vendor_id == db::intel::VENDOR,
141 intel_fix_descriptor_pool_leak: cfg!(windows) && properties.vendor_id == db::intel::VENDOR,
142 };
143
144 let queue_family_index = 0; if desc.presentation && bugs.intel_unable_to_present {
146 log::warn!("Rejecting Intel for not presenting when Nvidia is present (on Linux)");
147 return None;
148 }
149
150 let mut inline_uniform_block_features =
151 vk::PhysicalDeviceInlineUniformBlockFeaturesEXT::default();
152 let mut timeline_semaphore_features = vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR::default();
153 let mut dynamic_rendering_features = vk::PhysicalDeviceDynamicRenderingFeaturesKHR::default();
154 let mut descriptor_indexing_features =
155 vk::PhysicalDeviceDescriptorIndexingFeaturesEXT::default();
156 let mut buffer_device_address_features =
157 vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR::default();
158 let mut acceleration_structure_features =
159 vk::PhysicalDeviceAccelerationStructureFeaturesKHR::default();
160 let mut ray_query_features = vk::PhysicalDeviceRayQueryFeaturesKHR::default();
161 let mut features2_khr = vk::PhysicalDeviceFeatures2::default()
162 .push_next(&mut inline_uniform_block_features)
163 .push_next(&mut timeline_semaphore_features)
164 .push_next(&mut dynamic_rendering_features)
165 .push_next(&mut descriptor_indexing_features)
166 .push_next(&mut buffer_device_address_features)
167 .push_next(&mut acceleration_structure_features)
168 .push_next(&mut ray_query_features);
169 instance
170 .get_physical_device_properties2
171 .get_physical_device_features2(phd, &mut features2_khr);
172
173 if inline_uniform_block_properties.max_inline_uniform_block_size
174 < crate::limits::PLAIN_DATA_SIZE
175 || inline_uniform_block_properties.max_descriptor_set_inline_uniform_blocks == 0
176 || inline_uniform_block_features.inline_uniform_block == 0
177 {
178 log::warn!(
179 "\tRejected for inline uniform blocks. Properties = {:?}, Features = {:?}",
180 inline_uniform_block_properties,
181 inline_uniform_block_features,
182 );
183 return None;
184 }
185
186 if timeline_semaphore_features.timeline_semaphore == 0 {
187 log::warn!(
188 "\tRejected for timeline semaphore. Properties = {:?}, Features = {:?}",
189 timeline_semaphore_properties,
190 timeline_semaphore_features,
191 );
192 return None;
193 }
194
195 if dynamic_rendering_features.dynamic_rendering == 0 {
196 log::warn!(
197 "\tRejected for dynamic rendering. Features = {:?}",
198 dynamic_rendering_features,
199 );
200 return None;
201 }
202
203 let external_memory = supported_extensions.contains(&vk::KHR_EXTERNAL_MEMORY_NAME);
204 let external_memory = external_memory
205 && supported_extensions.contains(if cfg!(target_os = "windows") {
206 &vk::KHR_EXTERNAL_MEMORY_WIN32_NAME
207 } else {
208 &vk::KHR_EXTERNAL_MEMORY_FD_NAME
209 });
210
211 let timing = if properties.limits.timestamp_compute_and_graphics == vk::FALSE {
212 log::info!("No timing because of queue support");
213 false
214 } else {
215 true
216 };
217
218 let ray_tracing = if !supported_extensions.contains(&vk::KHR_ACCELERATION_STRUCTURE_NAME)
219 || !supported_extensions.contains(&vk::KHR_RAY_QUERY_NAME)
220 {
221 log::info!("No ray tracing extensions are supported");
222 None
223 } else if descriptor_indexing_properties.max_per_stage_update_after_bind_resources == vk::FALSE
224 || descriptor_indexing_features.descriptor_binding_partially_bound == vk::FALSE
225 || descriptor_indexing_features.shader_storage_buffer_array_non_uniform_indexing
226 == vk::FALSE
227 || descriptor_indexing_features.shader_sampled_image_array_non_uniform_indexing == vk::FALSE
228 {
229 log::info!(
230 "No ray tracing because of the descriptor indexing. Properties = {:?}. Features = {:?}",
231 descriptor_indexing_properties,
232 descriptor_indexing_features
233 );
234 None
235 } else if buffer_device_address_features.buffer_device_address == vk::FALSE {
236 log::info!(
237 "No ray tracing because of the buffer device address. Features = {:?}",
238 buffer_device_address_features
239 );
240 None
241 } else if acceleration_structure_properties.max_geometry_count == 0
242 || acceleration_structure_features.acceleration_structure == vk::FALSE
243 {
244 log::info!("No ray tracing because of the acceleration structure. Properties = {:?}. Features = {:?}",
245 acceleration_structure_properties, acceleration_structure_features);
246 None
247 } else if ray_query_features.ray_query == vk::FALSE {
248 log::info!(
249 "No ray tracing because of the ray query. Features = {:?}",
250 ray_query_features
251 );
252 None
253 } else {
254 log::info!("Ray tracing is supported");
255 log::debug!("Ray tracing properties: {acceleration_structure_properties:#?}");
256 Some(RayTracingCapabilities {
257 min_scratch_buffer_alignment: acceleration_structure_properties
258 .min_acceleration_structure_scratch_offset_alignment
259 as u64,
260 })
261 };
262
263 let buffer_marker = supported_extensions.contains(&vk::AMD_BUFFER_MARKER_NAME);
264 let shader_info = supported_extensions.contains(&vk::AMD_SHADER_INFO_NAME);
265 let full_screen_exclusive = supported_extensions.contains(&vk::EXT_FULL_SCREEN_EXCLUSIVE_NAME);
266
267 let device_information = crate::DeviceInformation {
268 is_software_emulated: properties.device_type == vk::PhysicalDeviceType::CPU,
269 device_name: ffi::CStr::from_ptr(properties.device_name.as_ptr())
270 .to_string_lossy()
271 .to_string(),
272 driver_name: ffi::CStr::from_ptr(driver_properties.driver_name.as_ptr())
273 .to_string_lossy()
274 .to_string(),
275 driver_info: ffi::CStr::from_ptr(driver_properties.driver_info.as_ptr())
276 .to_string_lossy()
277 .to_string(),
278 };
279
280 Some(AdapterCapabilities {
281 api_version,
282 properties,
283 device_information,
284 queue_family_index,
285 layered: portability_subset_properties.min_vertex_input_binding_stride_alignment != 0,
286 ray_tracing,
287 buffer_marker,
288 shader_info,
289 full_screen_exclusive,
290 external_memory,
291 timing,
292 bugs,
293 })
294}
295
296impl super::Context {
297 pub unsafe fn init(desc: crate::ContextDesc) -> Result<Self, NotSupportedError> {
298 let entry = match ash::Entry::load() {
299 Ok(entry) => entry,
300 Err(err) => {
301 log::error!("Missing Vulkan entry points: {:?}", err);
302 return Err(super::PlatformError::Loading(err).into());
303 }
304 };
305 let driver_api_version = match entry.try_enumerate_instance_version() {
306 Ok(Some(version)) => version,
308 Ok(None) => return Err(NotSupportedError::NoSupportedDeviceFound),
309 Err(err) => {
310 log::error!("try_enumerate_instance_version: {:?}", err);
311 return Err(super::PlatformError::Init(err).into());
312 }
313 };
314
315 let supported_layers = match entry.enumerate_instance_layer_properties() {
316 Ok(layers) => layers,
317 Err(err) => {
318 log::error!("enumerate_instance_layer_properties: {:?}", err);
319 return Err(super::PlatformError::Init(err).into());
320 }
321 };
322 let supported_layer_names = supported_layers
323 .iter()
324 .map(|properties| ffi::CStr::from_ptr(properties.layer_name.as_ptr()))
325 .collect::<Vec<_>>();
326
327 let mut layers: Vec<&'static ffi::CStr> = Vec::new();
328 let mut requested_layers = Vec::<&ffi::CStr>::new();
329 if desc.validation {
330 requested_layers.push(layer::KHRONOS_VALIDATION);
331 }
332 if desc.overlay {
333 requested_layers.push(layer::MESA_OVERLAY);
334 }
335 for name in requested_layers {
336 if supported_layer_names.contains(&name) {
337 layers.push(name);
338 } else {
339 log::warn!("Requested layer is not found: {:?}", name);
340 }
341 }
342
343 let supported_instance_extension_properties =
344 match entry.enumerate_instance_extension_properties(None) {
345 Ok(extensions) => extensions,
346 Err(err) => {
347 log::error!("enumerate_instance_extension_properties: {:?}", err);
348 return Err(super::PlatformError::Init(err).into());
349 }
350 };
351 let supported_instance_extensions = supported_instance_extension_properties
352 .iter()
353 .map(|ext_prop| ffi::CStr::from_ptr(ext_prop.extension_name.as_ptr()))
354 .collect::<Vec<_>>();
355
356 let core_instance = {
357 let mut create_flags = vk::InstanceCreateFlags::empty();
358
359 let mut instance_extensions = vec![
360 vk::EXT_DEBUG_UTILS_NAME,
361 vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_NAME,
362 ];
363 if desc.presentation {
364 instance_extensions.push(vk::KHR_SURFACE_NAME);
365 instance_extensions.push(vk::KHR_GET_SURFACE_CAPABILITIES2_NAME);
366 let candidates = [
367 vk::KHR_WAYLAND_SURFACE_NAME,
368 vk::KHR_XCB_SURFACE_NAME,
369 vk::KHR_XLIB_SURFACE_NAME,
370 vk::KHR_WIN32_SURFACE_NAME,
371 vk::KHR_ANDROID_SURFACE_NAME,
372 vk::EXT_SWAPCHAIN_COLORSPACE_NAME,
373 ];
374 for candidate in candidates.iter() {
375 if supported_instance_extensions.contains(candidate) {
376 log::info!("Presentation support: {:?}", candidate);
377 instance_extensions.push(candidate);
378 }
379 }
380 }
381
382 let mut enabled_instance_extensions = Vec::with_capacity(instance_extensions.len());
383 for inst_ext in instance_extensions.drain(..) {
384 if supported_instance_extensions.contains(&inst_ext) {
385 enabled_instance_extensions.push(inst_ext);
386 } else if is_promoted_instance_extension(inst_ext, driver_api_version) {
387 log::info!(
388 "Skipping promoted instance extension {:?} (core version {:x})",
389 inst_ext,
390 driver_api_version
391 );
392 } else {
393 log::error!("Instance extension {:?} is not supported", inst_ext);
394 return Err(NotSupportedError::NoSupportedDeviceFound);
395 }
396 }
397 if supported_instance_extensions.contains(&vk::KHR_PORTABILITY_ENUMERATION_NAME) {
398 log::info!("Enabling Vulkan Portability");
399 enabled_instance_extensions.push(vk::KHR_PORTABILITY_ENUMERATION_NAME);
400 create_flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
401 }
402
403 let app_info = vk::ApplicationInfo::default()
404 .engine_name(ffi::CStr::from_bytes_with_nul(b"blade\0").unwrap())
405 .engine_version(1)
406 .api_version(vk::HEADER_VERSION_COMPLETE);
407 let str_pointers = layers
408 .iter()
409 .chain(enabled_instance_extensions.iter())
410 .map(|&s| s.as_ptr())
411 .collect::<Vec<_>>();
412 let (layer_strings, extension_strings) = str_pointers.split_at(layers.len());
413 let create_info = vk::InstanceCreateInfo::default()
414 .application_info(&app_info)
415 .flags(create_flags)
416 .enabled_layer_names(layer_strings)
417 .enabled_extension_names(extension_strings);
418 unsafe { entry.create_instance(&create_info, None) }
419 .map_err(super::PlatformError::Init)?
420 };
421
422 let instance =
423 super::Instance {
424 _debug_utils: ext::debug_utils::Instance::new(&entry, &core_instance),
425 get_physical_device_properties2:
426 khr::get_physical_device_properties2::Instance::new(&entry, &core_instance),
427 get_surface_capabilities2: if desc.presentation {
428 Some(khr::get_surface_capabilities2::Instance::new(
429 &entry,
430 &core_instance,
431 ))
432 } else {
433 None
434 },
435 surface: if desc.presentation {
436 Some(khr::surface::Instance::new(&entry, &core_instance))
437 } else {
438 None
439 },
440 core: core_instance,
441 };
442
443 let physical_devices = instance
444 .core
445 .enumerate_physical_devices()
446 .map_err(super::PlatformError::Init)?;
447 let (physical_device, capabilities) = physical_devices
448 .into_iter()
449 .find_map(|phd| {
450 inspect_adapter(phd, &instance, driver_api_version, &desc).map(|caps| (phd, caps))
451 })
452 .ok_or_else(|| NotSupportedError::NoSupportedDeviceFound)?;
453
454 log::debug!("Adapter {:#?}", capabilities);
455 let mut min_buffer_alignment = 1;
456 if let Some(ref rt) = capabilities.ray_tracing {
457 min_buffer_alignment = min_buffer_alignment.max(rt.min_scratch_buffer_alignment);
458 }
459
460 let device_core = {
461 let family_info = vk::DeviceQueueCreateInfo::default()
462 .queue_family_index(capabilities.queue_family_index)
463 .queue_priorities(&[1.0]);
464 let family_infos = [family_info];
465
466 let mut device_extensions = REQUIRED_DEVICE_EXTENSIONS.to_vec();
467 if desc.presentation {
468 device_extensions.push(vk::KHR_SWAPCHAIN_NAME);
469 }
470 if capabilities.layered {
471 log::info!("Enabling Vulkan Portability");
472 device_extensions.push(vk::KHR_PORTABILITY_SUBSET_NAME);
473 }
474 if capabilities.ray_tracing.is_some() {
475 if capabilities.api_version < vk::API_VERSION_1_2 {
476 device_extensions.push(vk::EXT_DESCRIPTOR_INDEXING_NAME);
477 device_extensions.push(vk::KHR_BUFFER_DEVICE_ADDRESS_NAME);
478 device_extensions.push(vk::KHR_SHADER_FLOAT_CONTROLS_NAME);
479 device_extensions.push(vk::KHR_SPIRV_1_4_NAME);
480 }
481 device_extensions.push(vk::KHR_DEFERRED_HOST_OPERATIONS_NAME);
482 device_extensions.push(vk::KHR_ACCELERATION_STRUCTURE_NAME);
483 device_extensions.push(vk::KHR_RAY_QUERY_NAME);
484 }
485 if capabilities.buffer_marker {
486 device_extensions.push(vk::AMD_BUFFER_MARKER_NAME);
487 }
488 if capabilities.shader_info {
489 device_extensions.push(vk::AMD_SHADER_INFO_NAME);
490 }
491 if capabilities.full_screen_exclusive {
492 device_extensions.push(vk::EXT_FULL_SCREEN_EXCLUSIVE_NAME);
493 }
494 if capabilities.external_memory {
495 device_extensions.push(vk::KHR_EXTERNAL_MEMORY_NAME);
496 device_extensions.push(if cfg!(target_os = "windows") {
497 vk::KHR_EXTERNAL_MEMORY_WIN32_NAME
498 } else {
499 vk::KHR_EXTERNAL_MEMORY_FD_NAME
500 });
501 }
502
503 let str_pointers = device_extensions
504 .iter()
505 .map(|&s| s.as_ptr())
506 .collect::<Vec<_>>();
507
508 let mut ext_inline_uniform_block = vk::PhysicalDeviceInlineUniformBlockFeaturesEXT {
509 inline_uniform_block: vk::TRUE,
510 ..Default::default()
511 };
512 let mut khr_timeline_semaphore = vk::PhysicalDeviceTimelineSemaphoreFeaturesKHR {
513 timeline_semaphore: vk::TRUE,
514 ..Default::default()
515 };
516 let mut khr_dynamic_rendering = vk::PhysicalDeviceDynamicRenderingFeaturesKHR {
517 dynamic_rendering: vk::TRUE,
518 ..Default::default()
519 };
520 let mut device_create_info = vk::DeviceCreateInfo::default()
521 .queue_create_infos(&family_infos)
522 .enabled_extension_names(&str_pointers)
523 .push_next(&mut ext_inline_uniform_block)
524 .push_next(&mut khr_timeline_semaphore)
525 .push_next(&mut khr_dynamic_rendering);
526
527 let mut ext_descriptor_indexing;
528 let mut khr_buffer_device_address;
529 let mut khr_acceleration_structure;
530 let mut khr_ray_query;
531 if capabilities.ray_tracing.is_some() {
532 ext_descriptor_indexing = vk::PhysicalDeviceDescriptorIndexingFeaturesEXT {
533 shader_storage_buffer_array_non_uniform_indexing: vk::TRUE,
534 shader_sampled_image_array_non_uniform_indexing: vk::TRUE,
535 descriptor_binding_partially_bound: vk::TRUE,
536 ..Default::default()
537 };
538 khr_buffer_device_address = vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR {
539 buffer_device_address: vk::TRUE,
540 ..Default::default()
541 };
542 khr_acceleration_structure = vk::PhysicalDeviceAccelerationStructureFeaturesKHR {
543 acceleration_structure: vk::TRUE,
544 ..Default::default()
545 };
546 khr_ray_query = vk::PhysicalDeviceRayQueryFeaturesKHR {
547 ray_query: vk::TRUE,
548 ..Default::default()
549 };
550 device_create_info = device_create_info
551 .push_next(&mut ext_descriptor_indexing)
552 .push_next(&mut khr_buffer_device_address)
553 .push_next(&mut khr_acceleration_structure)
554 .push_next(&mut khr_ray_query);
555 }
556
557 instance
558 .core
559 .create_device(physical_device, &device_create_info, None)
560 .map_err(super::PlatformError::Init)?
561 };
562
563 let device = super::Device {
564 swapchain: if desc.presentation {
565 Some(khr::swapchain::Device::new(&instance.core, &device_core))
566 } else {
567 None
568 },
569 debug_utils: ext::debug_utils::Device::new(&instance.core, &device_core),
570 timeline_semaphore: khr::timeline_semaphore::Device::new(&instance.core, &device_core),
571 dynamic_rendering: khr::dynamic_rendering::Device::new(&instance.core, &device_core),
572 ray_tracing: if let Some(ref caps) = capabilities.ray_tracing {
573 Some(super::RayTracingDevice {
574 acceleration_structure: khr::acceleration_structure::Device::new(
575 &instance.core,
576 &device_core,
577 ),
578 scratch_buffer_alignment: caps.min_scratch_buffer_alignment,
579 })
580 } else {
581 None
582 },
583 buffer_marker: if capabilities.buffer_marker && desc.validation {
584 Some(amd::buffer_marker::Device::new(
585 &instance.core,
586 &device_core,
587 ))
588 } else {
589 None
590 },
591 shader_info: if capabilities.shader_info {
592 Some(amd::shader_info::Device::new(&instance.core, &device_core))
593 } else {
594 None
595 },
596 full_screen_exclusive: if desc.presentation && capabilities.full_screen_exclusive {
597 Some(ext::full_screen_exclusive::Device::new(
598 &instance.core,
599 &device_core,
600 ))
601 } else {
602 None
603 },
604 external_memory: if capabilities.external_memory {
605 #[cfg(not(target_os = "windows"))]
606 use khr::external_memory_fd::Device;
607 #[cfg(target_os = "windows")]
608 use khr::external_memory_win32::Device;
609
610 Some(Device::new(&instance.core, &device_core))
611 } else {
612 None
613 },
614 core: device_core,
615 device_information: capabilities.device_information,
616 command_scope: if desc.capture {
617 Some(super::CommandScopeDevice {})
618 } else {
619 None
620 },
621 timing: if desc.timing && capabilities.timing {
622 Some(super::TimingDevice {
623 period: capabilities.properties.limits.timestamp_period,
624 })
625 } else {
626 None
627 },
628 workarounds: super::Workarounds {
630 extra_sync_src_access: vk::AccessFlags::TRANSFER_WRITE,
631 extra_sync_dst_access: vk::AccessFlags::TRANSFER_WRITE
632 | vk::AccessFlags::TRANSFER_READ
633 | if capabilities.ray_tracing.is_some() {
634 vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR
635 } else {
636 vk::AccessFlags::NONE
637 },
638 extra_descriptor_pool_create_flags: if capabilities
639 .bugs
640 .intel_fix_descriptor_pool_leak
641 {
642 vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET
643 } else {
644 vk::DescriptorPoolCreateFlags::empty()
645 },
646 },
647 };
648
649 let memory_manager = {
650 let mem_properties = instance
651 .core
652 .get_physical_device_memory_properties(physical_device);
653 let memory_types =
654 &mem_properties.memory_types[..mem_properties.memory_type_count as usize];
655 let limits = &capabilities.properties.limits;
656 let config = gpu_alloc::Config::i_am_prototyping(); let properties = gpu_alloc::DeviceProperties {
659 max_memory_allocation_count: limits.max_memory_allocation_count,
660 max_memory_allocation_size: u64::max_value(), non_coherent_atom_size: limits.non_coherent_atom_size,
662 memory_types: memory_types
663 .iter()
664 .map(|memory_type| gpu_alloc::MemoryType {
665 props: gpu_alloc::MemoryPropertyFlags::from_bits_truncate(
666 memory_type.property_flags.as_raw() as u8,
667 ),
668 heap: memory_type.heap_index,
669 })
670 .collect(),
671 memory_heaps: mem_properties.memory_heaps
672 [..mem_properties.memory_heap_count as usize]
673 .iter()
674 .map(|&memory_heap| gpu_alloc::MemoryHeap {
675 size: memory_heap.size,
676 })
677 .collect(),
678 buffer_device_address: capabilities.ray_tracing.is_some(),
679 };
680
681 let known_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL
682 | vk::MemoryPropertyFlags::HOST_VISIBLE
683 | vk::MemoryPropertyFlags::HOST_COHERENT
684 | vk::MemoryPropertyFlags::HOST_CACHED
685 | vk::MemoryPropertyFlags::LAZILY_ALLOCATED;
686 let valid_ash_memory_types = memory_types.iter().enumerate().fold(0, |u, (i, mem)| {
687 if !known_memory_flags.contains(mem.property_flags) {
688 log::debug!(
689 "Skipping memory type={} for having unknown flags: {:?}",
690 i,
691 mem.property_flags & !known_memory_flags
692 );
693 u
694 } else if mem
695 .property_flags
696 .contains(vk::MemoryPropertyFlags::HOST_VISIBLE)
697 && !mem
698 .property_flags
699 .contains(vk::MemoryPropertyFlags::HOST_COHERENT)
700 {
701 log::debug!("Skipping memory type={} for lack of host coherency", i);
703 u
704 } else {
705 u | (1 << i)
706 }
707 });
708 super::MemoryManager {
709 allocator: gpu_alloc::GpuAllocator::new(config, properties),
710 slab: slab::Slab::new(),
711 valid_ash_memory_types,
712 }
713 };
714
715 let queue = device
716 .core
717 .get_device_queue(capabilities.queue_family_index, 0);
718 let last_progress = 0;
719 let mut timeline_info = vk::SemaphoreTypeCreateInfo {
720 semaphore_type: vk::SemaphoreType::TIMELINE,
721 initial_value: last_progress,
722 ..Default::default()
723 };
724 let timeline_semaphore_create_info =
725 vk::SemaphoreCreateInfo::default().push_next(&mut timeline_info);
726 let timeline_semaphore = device
727 .core
728 .create_semaphore(&timeline_semaphore_create_info, None)
729 .unwrap();
730
731 let mut naga_flags = spv::WriterFlags::FORCE_POINT_SIZE;
732 let shader_debug_path = if desc.validation || desc.capture {
733 use std::{env, fs};
734 naga_flags |= spv::WriterFlags::DEBUG;
735 let dir = env::temp_dir().join("blade");
736 let _ = fs::create_dir(&dir);
737 Some(dir)
738 } else {
739 None
740 };
741
742 Ok(super::Context {
743 memory: Mutex::new(memory_manager),
744 device,
745 queue_family_index: capabilities.queue_family_index,
746 queue: Mutex::new(super::Queue {
747 raw: queue,
748 timeline_semaphore,
749 last_progress,
750 }),
751 physical_device,
752 naga_flags,
753 shader_debug_path,
754 min_buffer_alignment,
755 sample_count_flags: capabilities
756 .properties
757 .limits
758 .framebuffer_color_sample_counts
759 & capabilities
760 .properties
761 .limits
762 .framebuffer_depth_sample_counts,
763 instance,
764 entry,
765 })
766 }
767
768 pub(super) fn set_object_name<T: vk::Handle>(&self, object: T, name: &str) {
769 let name_cstr = ffi::CString::new(name).unwrap();
770 let name_info = vk::DebugUtilsObjectNameInfoEXT::default()
771 .object_handle(object)
772 .object_name(&name_cstr);
773 let _ = unsafe {
774 self.device
775 .debug_utils
776 .set_debug_utils_object_name(&name_info)
777 };
778 }
779
780 pub fn capabilities(&self) -> crate::Capabilities {
781 crate::Capabilities {
782 ray_query: match self.device.ray_tracing {
783 Some(_) => crate::ShaderVisibility::all(),
784 None => crate::ShaderVisibility::empty(),
785 },
786 sample_count_mask: self.sample_count_flags.as_raw(),
787 }
788 }
789
790 pub fn device_information(&self) -> &crate::DeviceInformation {
791 &self.device.device_information
792 }
793}
794
795impl Drop for super::Context {
796 fn drop(&mut self) {
797 if std::thread::panicking() {
798 return;
799 }
800 unsafe {
801 if let Ok(queue) = self.queue.lock() {
802 let _ = self.device.core.queue_wait_idle(queue.raw);
803 self.device
804 .core
805 .destroy_semaphore(queue.timeline_semaphore, None);
806 }
807 self.device.core.destroy_device(None);
808 self.instance.core.destroy_instance(None);
809 }
810 }
811}