|
| 1 | +use ash::{prelude::VkResult, vk}; |
| 2 | +use std::{collections::HashMap, ffi::CStr}; |
| 3 | + |
| 4 | +pub struct Vulkan { |
| 5 | + instance: ash::Instance, |
| 6 | + // TODO purge cache at some point |
| 7 | + device_name_cache: HashMap<u64, VkResult<Option<String>>>, |
| 8 | +} |
| 9 | + |
| 10 | +impl Vulkan { |
| 11 | + pub fn new() -> Option<Self> { |
| 12 | + let entry = unsafe { ash::Entry::load().ok()? }; |
| 13 | + let app_info = vk::ApplicationInfo { |
| 14 | + api_version: vk::make_api_version(0, 1, 1, 0), |
| 15 | + ..Default::default() |
| 16 | + }; |
| 17 | + let create_info = vk::InstanceCreateInfo { |
| 18 | + p_application_info: &app_info, |
| 19 | + ..Default::default() |
| 20 | + }; |
| 21 | + let instance = unsafe { entry.create_instance(&create_info, None).ok()? }; |
| 22 | + Some(Self { |
| 23 | + instance, |
| 24 | + device_name_cache: HashMap::new(), |
| 25 | + }) |
| 26 | + } |
| 27 | + |
| 28 | + pub fn device_name(&mut self, dev: u64) -> VkResult<Option<&str>> { |
| 29 | + if !self.device_name_cache.contains_key(&dev) { |
| 30 | + let value = self.device_name_uncached(dev); |
| 31 | + self.device_name_cache.insert(dev, value); |
| 32 | + } |
| 33 | + self.device_name_cache |
| 34 | + .get(&dev) |
| 35 | + .unwrap() |
| 36 | + .as_ref() |
| 37 | + .map(|x| x.as_deref()) |
| 38 | + .map_err(|err| err.clone()) |
| 39 | + } |
| 40 | + |
| 41 | + fn device_name_uncached(&mut self, dev: u64) -> VkResult<Option<String>> { |
| 42 | + let devices = unsafe { self.instance.enumerate_physical_devices()? }; |
| 43 | + for device in devices { |
| 44 | + // Check extension is supported |
| 45 | + let supported = unsafe { |
| 46 | + self.instance |
| 47 | + .enumerate_device_extension_properties(device)? |
| 48 | + }; |
| 49 | + if !supported.iter().any(|ext| { |
| 50 | + CStr::from_bytes_until_nul(bytemuck::cast_slice(&ext.extension_name)) |
| 51 | + == Ok(ash::ext::physical_device_drm::NAME) |
| 52 | + }) { |
| 53 | + continue; |
| 54 | + } |
| 55 | + |
| 56 | + let mut drm_props = vk::PhysicalDeviceDrmPropertiesEXT::default(); |
| 57 | + let mut props = vk::PhysicalDeviceProperties2::default().push_next(&mut drm_props); |
| 58 | + unsafe { |
| 59 | + self.instance |
| 60 | + .get_physical_device_properties2(device, &mut props) |
| 61 | + }; |
| 62 | + |
| 63 | + let device_name = |
| 64 | + CStr::from_bytes_until_nul(bytemuck::cast_slice(&props.properties.device_name)); |
| 65 | + |
| 66 | + let major = rustix::fs::major(dev) as _; |
| 67 | + let minor = rustix::fs::minor(dev) as _; |
| 68 | + if (drm_props.primary_major, drm_props.primary_minor) == (major, minor) |
| 69 | + || (drm_props.render_major, drm_props.render_minor) == (major, minor) |
| 70 | + { |
| 71 | + return Ok(device_name |
| 72 | + .ok() |
| 73 | + .and_then(|x| Some(x.to_str().ok()?.to_owned()))); |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + Ok(None) |
| 78 | + } |
| 79 | +} |
0 commit comments