bort_vk/
physical_device.rs

1use crate::{c_string_to_string, ApiVersion, Instance};
2use ash::vk::{self, api_version_major, api_version_minor};
3use std::{
4    error,
5    ffi::{CStr, CString},
6    fmt,
7    str::Utf8Error,
8    sync::Arc,
9};
10
11#[derive(Clone)]
12pub struct PhysicalDevice {
13    handle: vk::PhysicalDevice,
14    properties: vk::PhysicalDeviceProperties,
15    name: String,
16
17    queue_family_properties: Vec<vk::QueueFamilyProperties>,
18    memory_properties: vk::PhysicalDeviceMemoryProperties,
19    extension_properties: Vec<ExtensionProperties>,
20
21    // dependencies
22    instance: Arc<Instance>,
23}
24
25impl PhysicalDevice {
26    pub fn new(
27        instance: Arc<Instance>,
28        handle: vk::PhysicalDevice,
29    ) -> Result<Self, PhysicalDeviceError> {
30        let properties = unsafe { instance.inner().get_physical_device_properties(handle) };
31        let name = unsafe { c_string_to_string(properties.device_name.as_ptr()) }
32            .map_err(|e| PhysicalDeviceError::NameStringConversion(e))?;
33
34        let queue_family_properties = unsafe {
35            instance
36                .inner()
37                .get_physical_device_queue_family_properties(handle)
38        };
39
40        let memory_properties = unsafe {
41            instance
42                .inner()
43                .get_physical_device_memory_properties(handle)
44        };
45
46        let vk_extension_properties = unsafe {
47            instance
48                .inner()
49                .enumerate_device_extension_properties(handle)
50        }
51        .map_err(|e| PhysicalDeviceError::EnumerateExtensionProperties(e))?;
52
53        let extension_properties: Vec<ExtensionProperties> = vk_extension_properties
54            .into_iter()
55            .map(|props| ExtensionProperties::new(props))
56            .collect();
57
58        Ok(Self {
59            handle,
60            properties,
61            name,
62
63            queue_family_properties,
64            memory_properties,
65            extension_properties,
66
67            instance,
68        })
69    }
70
71    pub fn supports_min_api_ver(&self, api_version: ApiVersion) -> bool {
72        let supported_major = api_version_major(self.properties.api_version);
73        let supported_minor = api_version_minor(self.properties.api_version);
74        if supported_major < api_version.major {
75            return false;
76        }
77        if supported_minor < api_version.minor {
78            return false;
79        }
80        return true;
81    }
82
83    /// Returns any of the provided `extension_names` that are unsupported by this device.
84    pub fn any_unsupported_extensions<'a>(
85        &self,
86        mut extension_names: Vec<CString>,
87    ) -> Vec<CString> {
88        extension_names.retain(|extension_name| !self.supports_extension(extension_name.clone()));
89        extension_names
90    }
91
92    pub fn supports_extension(&self, extension_name: CString) -> bool {
93        self.extension_properties
94            .iter()
95            .any(|props| props.extension_name == extension_name)
96    }
97
98    // Getters
99
100    pub fn handle(&self) -> vk::PhysicalDevice {
101        self.handle
102    }
103
104    pub fn properties(&self) -> &vk::PhysicalDeviceProperties {
105        &self.properties
106    }
107
108    pub fn name(&self) -> String {
109        self.name.clone()
110    }
111
112    pub fn queue_family_properties(&self) -> &Vec<vk::QueueFamilyProperties> {
113        &self.queue_family_properties
114    }
115
116    pub fn memory_properties(&self) -> &vk::PhysicalDeviceMemoryProperties {
117        &self.memory_properties
118    }
119
120    pub fn extension_properties(&self) -> &Vec<ExtensionProperties> {
121        &self.extension_properties
122    }
123
124    pub fn instance(&self) -> &Arc<Instance> {
125        &self.instance
126    }
127}
128
129/// Properties of an extension in the loader or a physical device.
130#[derive(Clone, Debug)]
131pub struct ExtensionProperties {
132    pub extension_name: CString,
133    pub spec_version: u32,
134}
135
136impl ExtensionProperties {
137    fn new(value: vk::ExtensionProperties) -> Self {
138        let c_str = unsafe { CStr::from_ptr(value.extension_name.as_ptr()) };
139        Self {
140            extension_name: c_str.to_owned(),
141            spec_version: value.spec_version,
142        }
143    }
144}
145
146#[derive(Debug, Clone)]
147pub enum PhysicalDeviceError {
148    NameStringConversion(Utf8Error),
149    EnumerateExtensionProperties(vk::Result),
150}
151
152impl fmt::Display for PhysicalDeviceError {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        match self {
155            Self::NameStringConversion(e) => {
156                write!(f, "failed to convert device name to string: {}", e)
157            }
158            Self::EnumerateExtensionProperties(e) => write!(
159                f,
160                "call to vkEnumerateInstanceExtensionProperties failed: {}",
161                e
162            ),
163        }
164    }
165}
166
167impl error::Error for PhysicalDeviceError {
168    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
169        match self {
170            Self::NameStringConversion(e) => Some(e),
171            Self::EnumerateExtensionProperties(e) => Some(e),
172        }
173    }
174}