bort_vk/
physical_device.rs1use 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 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 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 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#[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}