1
2use crate::prelude::*;
3use std::{
4 ffi::CStr,
5 fmt::{self, Debug, Formatter},
6 mem::MaybeUninit,
7 ptr::{null, null_mut},
8 sync::Arc,
9};
10
11#[derive(Debug, Clone)]
13pub struct VulkanGpuInfo {
14 pub(crate) gpu: VkPhysicalDevice,
16
17 pub(crate) properties: VkPhysicalDeviceProperties,
19
20 pub(crate) mem_properties: VkPhysicalDeviceMemoryProperties,
22
23 pub(crate) queue_families: Vec<VkQueueFamilyProperties>,
25
26 pub(crate) extension_properties: Vec<VkExtensionProperties>,
28}
29
30impl VulkanGpuInfo {
31 pub fn get_gpu_info(vkcore: &VkCore) -> Result<Vec<VulkanGpuInfo>, VulkanError> {
33 let mut num_gpus = 0u32;
34 vkcore.vkEnumeratePhysicalDevices(vkcore.get_instance(), &mut num_gpus, null_mut())?;
35 let mut gpus = Vec::<VkPhysicalDevice>::with_capacity(num_gpus as usize);
36 vkcore.vkEnumeratePhysicalDevices(vkcore.get_instance(), &mut num_gpus, gpus.as_mut_ptr())?;
37 unsafe {gpus.set_len(num_gpus as usize)};
38 let mut ret = Vec::<VulkanGpuInfo>::with_capacity(num_gpus as usize);
39 for gpu in gpus {
40 let mut properties: VkPhysicalDeviceProperties = unsafe {MaybeUninit::zeroed().assume_init()};
41 vkcore.vkGetPhysicalDeviceProperties(gpu, &mut properties)?;
42 let mut mem_properties: VkPhysicalDeviceMemoryProperties = unsafe {MaybeUninit::zeroed().assume_init()};
43 vkcore.vkGetPhysicalDeviceMemoryProperties(gpu, &mut mem_properties)?;
44 let mut num_queue_families = 0u32;
45 vkcore.vkGetPhysicalDeviceQueueFamilyProperties(gpu, &mut num_queue_families, null_mut())?;
46 let mut queue_families = Vec::<VkQueueFamilyProperties>::with_capacity(num_queue_families as usize);
47 vkcore.vkGetPhysicalDeviceQueueFamilyProperties(gpu, &mut num_queue_families, queue_families.as_mut_ptr())?;
48 unsafe {queue_families.set_len(num_queue_families as usize)};
49 let mut num_extension_properties = 0u32;
50 vkcore.vkEnumerateDeviceExtensionProperties(gpu, null(), &mut num_extension_properties, null_mut())?;
51 let mut extension_properties = Vec::<VkExtensionProperties>::with_capacity(num_extension_properties as usize);
52 vkcore.vkEnumerateDeviceExtensionProperties(gpu, null(), &mut num_extension_properties, extension_properties.as_mut_ptr())?;
53 unsafe {extension_properties.set_len(num_extension_properties as usize)};
54 ret.push(VulkanGpuInfo {
55 gpu,
56 properties,
57 mem_properties,
58 queue_families,
59 extension_properties,
60 });
61 }
62 Ok(ret)
63 }
64
65 pub(crate) fn get_vk_physical_device(&self) -> VkPhysicalDevice {
67 self.gpu
68 }
69
70 pub fn get_queue_families(&self) -> &[VkQueueFamilyProperties] {
72 self.queue_families.as_ref()
73 }
74
75 pub fn get_queue_family_index_by_flags(&self, queue_flag_match: u32) -> u32 {
77 for i in 0..self.queue_families.len() {
78 if (self.queue_families[i].queueFlags & queue_flag_match) == queue_flag_match {
79 return i as u32;
80 }
81 }
82 u32::MAX
83 }
84
85 pub fn get_properties(&self) -> &VkPhysicalDeviceProperties {
87 &self.properties
88 }
89
90 pub fn get_extension_properties(&self) -> &[VkExtensionProperties] {
92 self.extension_properties.as_ref()
93 }
94
95 pub fn get_memory_type_index(&self, mut type_bits: u32, properties: VkMemoryPropertyFlags) -> Result<u32, VulkanError> {
97 for i in 0..self.mem_properties.memoryTypeCount {
98 if (type_bits & 1) == 1
99 && (self.mem_properties.memoryTypes[i as usize].propertyFlags & properties) == properties {
100 return Ok(i)
101 }
102 type_bits >>= 1;
103 }
104 Err(VulkanError::NoSuitableMemoryType)
105 }
106}
107
108unsafe impl Send for VulkanGpuInfo {}
109unsafe impl Sync for VulkanGpuInfo {}
110
111pub struct VulkanDevice {
113 pub(crate) vkcore: Arc<VkCore>,
115
116 queue_family_index: u32,
118
119 gpu: VulkanGpuInfo,
121
122 device: VkDevice,
124
125 pub(crate) queue: VkQueue,
127}
128
129impl VulkanDevice {
130 pub fn new(vkcore: Arc<VkCore>, gpu: VulkanGpuInfo, queue_family_index: u32) -> Result<Self, VulkanError> {
132 fn remove_c_string_from_vec(v: &mut Vec<*const i8>, to_remove: &str) {
133 let mut found_index = None;
134 for (i, &ptr) in v.iter().enumerate() {
135 unsafe {
136 let c_str = CStr::from_ptr(ptr);
137 if c_str.to_bytes() == to_remove.as_bytes() {
139 found_index = Some(i);
140 break;
141 }
142 }
143 }
144 found_index.map(|i| v.swap_remove(i));
145 }
146 let priorities = [1.0_f32];
147 let queue_ci = VkDeviceQueueCreateInfo {
148 sType: VkStructureType::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
149 pNext: null(),
150 flags: 0,
151 queueFamilyIndex: queue_family_index,
152 queueCount: 1,
153 pQueuePriorities: priorities.as_ptr(),
154 };
155 let mut extensions: Vec<*const i8> = Vec::with_capacity(gpu.extension_properties.len());
156 let mut has_vk_khr_buffer_device_address = false;
157 let mut has_vk_ext_buffer_device_address = false;
158 for ext in gpu.extension_properties.iter() {
159 let ext_ptr = ext.extensionName.as_ptr();
160 let ext_str = unsafe {CStr::from_ptr(ext_ptr)}.to_string_lossy();
161 if ext_str == "VK_KHR_buffer_device_address" {
162 has_vk_khr_buffer_device_address = true;
163 } else if ext_str == "VK_EXT_buffer_device_address" {
164 has_vk_ext_buffer_device_address = true;
165 } else if ext_str == "VK_NV_disk_cache_utils" || ext_str == "VK_NV_internal_nvpresent" {
166 continue;
168 }
169 extensions.push(ext_ptr)
170 }
171 if has_vk_khr_buffer_device_address && has_vk_ext_buffer_device_address {
172 remove_c_string_from_vec(&mut extensions, "VK_EXT_buffer_device_address");
173 }
174
175 let device_ci = VkDeviceCreateInfo {
176 sType: VkStructureType::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
177 pNext: null(),
178 flags: 0,
179 queueCreateInfoCount: 1,
180 pQueueCreateInfos: &queue_ci,
181 enabledLayerCount: 0,
182 ppEnabledLayerNames: null(),
183 enabledExtensionCount: extensions.len() as u32,
184 ppEnabledExtensionNames: extensions.as_ptr(),
185 pEnabledFeatures: null(),
186 };
187
188 let mut device: VkDevice = null();
189 vkcore.vkCreateDevice(gpu.get_vk_physical_device(), &device_ci, null(), &mut device)?;
190 let device = ResourceGuard::new(device, |&d|proceed_run(vkcore.vkDestroyDevice(d, null())));
191
192 let mut queue: VkQueue = null();
193 vkcore.vkGetDeviceQueue(*device, queue_family_index, 0, &mut queue)?;
194 let device = device.release();
195
196 Ok(Self {
197 vkcore,
198 queue_family_index,
199 gpu,
200 device,
201 queue,
202 })
203 }
204
205 pub fn choose_gpu_by_flags(vkcore: Arc<VkCore>, flags: VkQueueFlags, name_substr: &str) -> Result<Self, VulkanError> {
208 for gpu in VulkanGpuInfo::get_gpu_info(&vkcore)?.iter() {
209 if !unsafe{CStr::from_ptr(gpu.properties.deviceName.as_ptr())}.to_str().unwrap().contains(name_substr) {
210 continue;
211 }
212 let index = gpu.get_queue_family_index_by_flags(flags);
213 if index != u32::MAX {
214 return Self::new(vkcore, gpu.clone(), index);
215 }
216 }
217 Err(VulkanError::ChooseGpuFailed)
218 }
219
220 pub fn choose_gpu_with_graphics(vkcore: Arc<VkCore>, name_substr: &str) -> Result<Self, VulkanError> {
223 Self::choose_gpu_by_flags(vkcore, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT as VkQueueFlags, name_substr)
224 }
225
226 pub fn choose_gpu_with_compute(vkcore: Arc<VkCore>, name_substr: &str) -> Result<Self, VulkanError> {
229 Self::choose_gpu_by_flags(vkcore, VkQueueFlagBits::VK_QUEUE_COMPUTE_BIT as VkQueueFlags, name_substr)
230 }
231
232 pub fn choose_gpu_with_graphics_and_compute(vkcore: Arc<VkCore>, name_substr: &str) -> Result<Self, VulkanError> {
235 Self::choose_gpu_by_flags(vkcore,
236 VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT as VkQueueFlags |
237 VkQueueFlagBits::VK_QUEUE_COMPUTE_BIT as VkQueueFlags, name_substr)
238 }
239
240 pub fn choose_gpu_anyway(vkcore: Arc<VkCore>, name_substr: &str) -> Result<Self, VulkanError> {
243 Self::choose_gpu_by_flags(vkcore, 0, name_substr)
244 }
245
246 pub fn get_queue_family_index(&self) -> u32 {
248 self.queue_family_index
249 }
250
251 pub fn get_gpu(&self) -> &VulkanGpuInfo {
253 &self.gpu
254 }
255
256 pub fn get_supported_by_surface(&self, queue_index: usize, surface: VkSurfaceKHR) -> Result<bool, VulkanError> {
258 let mut result: VkBool32 = 0;
259 self.vkcore.vkGetPhysicalDeviceSurfaceSupportKHR(self.get_vk_physical_device(), queue_index as u32, surface, &mut result)?;
260 Ok(result != 0)
261 }
262
263 pub fn wait_idle(&self) -> Result<(), VulkanError> {
265 self.vkcore.vkDeviceWaitIdle(self.device)?;
266 Ok(())
267 }
268
269 pub(crate) fn get_vk_physical_device(&self) -> VkPhysicalDevice {
271 self.gpu.get_vk_physical_device()
272 }
273
274 pub(crate) fn get_vk_device(&self) -> VkDevice {
276 self.device
277 }
278
279 pub(crate) fn get_vk_queue(&self) -> VkQueue {
281 self.queue
282 }
283}
284
285impl Debug for VulkanDevice {
286 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
287 f.debug_struct("VulkanDevice")
288 .field("queue_family_index", &self.queue_family_index)
289 .field("gpu", &self.gpu)
290 .field("device", &self.device)
291 .field("queue", &self.queue)
292 .finish()
293 }
294}
295
296impl Clone for VulkanDevice {
297 fn clone(&self) -> Self {
298 Self::new(self.vkcore.clone(), self.gpu.clone(), self.queue_family_index).unwrap()
299 }
300}
301
302impl Drop for VulkanDevice {
303 fn drop(&mut self) {
304 proceed_run(self.vkcore.vkDestroyDevice(self.device, null()))
305 }
306}
307
308unsafe impl Send for VulkanDevice {}
309unsafe impl Sync for VulkanDevice {}