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