vkobject_rs/
device.rs

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/// The physical device info
12#[derive(Debug, Clone)]
13pub struct VulkanGpuInfo {
14	/// The physical device
15	pub(crate) gpu: VkPhysicalDevice,
16
17	/// The properties of the physical device
18	pub(crate) properties: VkPhysicalDeviceProperties,
19
20	/// The properties of the physical device memory
21	pub(crate) mem_properties: VkPhysicalDeviceMemoryProperties,
22
23	/// The queue families
24	pub(crate) queue_families: Vec<VkQueueFamilyProperties>,
25
26	/// The extension properties
27	pub(crate) extension_properties: Vec<VkExtensionProperties>,
28}
29
30impl VulkanGpuInfo {
31	/// Create a list of all the GPUs info
32	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	/// Get the `VkPhysicalDevice`
66	pub(crate) fn get_vk_physical_device(&self) -> VkPhysicalDevice {
67		self.gpu
68	}
69
70	/// Get the `VkQueueFamilyProperties` list
71	pub fn get_queue_families(&self) -> &[VkQueueFamilyProperties] {
72		self.queue_families.as_ref()
73	}
74
75	/// Find a queue family index that matches the flags
76	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	/// Get the `VkPhysicalDeviceProperties`
86	pub fn get_properties(&self) -> &VkPhysicalDeviceProperties {
87		&self.properties
88	}
89
90	/// Get the list of the `VkExtensionProperties`
91	pub fn get_extension_properties(&self) -> &[VkExtensionProperties] {
92		self.extension_properties.as_ref()
93	}
94
95	/// Get memory type index by the memory properties flags
96	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
111/// The Vulkan device with its queues to submit the rendering commands
112pub struct VulkanDevice {
113	/// The Vulkan driver
114	pub(crate) vkcore: Arc<VkCore>,
115
116	/// The current queue family index
117	queue_family_index: u32,
118
119	/// The info of the GPU
120	gpu: VulkanGpuInfo,
121
122	/// The handle to the device
123	device: VkDevice,
124
125	/// The queues of the device. Submit commands to the queue to control GPU.
126	pub(crate) queue: VkQueue,
127}
128
129impl VulkanDevice {
130	/// Create the `VulkanDevice` by the given `VkPhysicalDevice` and the queue family index
131	pub fn new(vkcore: Arc<VkCore>, gpu: VulkanGpuInfo, queue_family_index: u32) -> Result<Self, VulkanError> {
132		let priorities = [1.0_f32];
133		let queue_ci = VkDeviceQueueCreateInfo {
134			sType: VkStructureType::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
135			pNext: null(),
136			flags: 0,
137			queueFamilyIndex: queue_family_index,
138			queueCount: 1,
139			pQueuePriorities: priorities.as_ptr(),
140		};
141		let mut extensions: Vec<*const i8> = Vec::with_capacity(gpu.extension_properties.len());
142		let mut has_vk_khr_buffer_device_address = false;
143		let mut has_vk_ext_buffer_device_address = false;
144		for ext in gpu.extension_properties.iter() {
145			let ext_ptr = ext.extensionName.as_ptr();
146			let ext_str = unsafe {CStr::from_ptr(ext_ptr)}.to_string_lossy();
147			if ext_str == "VK_KHR_buffer_device_address" {
148				has_vk_khr_buffer_device_address = true;
149			} else if ext_str == "VK_EXT_buffer_device_address" {
150				has_vk_ext_buffer_device_address = true;
151			}
152			extensions.push(ext_ptr)
153		}
154		if has_vk_khr_buffer_device_address && has_vk_ext_buffer_device_address {
155			let len = extensions.len();
156			for i in 0..len {
157				let ext_ptr = extensions[i];
158				let ext_str = unsafe {CStr::from_ptr(ext_ptr)}.to_string_lossy();
159				if ext_str == "VK_EXT_buffer_device_address" {
160					extensions[i] = extensions[len - 1];
161					extensions.pop();
162					break;
163				}
164			}
165		}
166
167		let device_ci = VkDeviceCreateInfo {
168			sType: VkStructureType::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
169			pNext: null(),
170			flags: 0,
171			queueCreateInfoCount: 1,
172			pQueueCreateInfos: &queue_ci,
173			enabledLayerCount: 0,
174			ppEnabledLayerNames: null(),
175			enabledExtensionCount: extensions.len() as u32,
176			ppEnabledExtensionNames: extensions.as_ptr(),
177			pEnabledFeatures: null(),
178		};
179
180		let mut device: VkDevice = null();
181		vkcore.vkCreateDevice(gpu.get_vk_physical_device(), &device_ci, null(), &mut device)?;
182		let device = ResourceGuard::new(device, |&d|proceed_run(vkcore.vkDestroyDevice(d, null())));
183
184		let mut queue: VkQueue = null();
185		vkcore.vkGetDeviceQueue(*device, queue_family_index, 0, &mut queue)?;
186		let device = device.release();
187
188		Ok(Self {
189			vkcore,
190			queue_family_index,
191			gpu,
192			device,
193			queue,
194		})
195	}
196
197	/// Choose a GPU that matches the `VkQueueFlags`
198	/// * `flags`: The flags you want to match
199	/// * `queue_count`: see `VulkanDevice::new()`
200	pub fn choose_gpu(vkcore: Arc<VkCore>, flags: VkQueueFlags) -> Result<Self, VulkanError> {
201		for gpu in VulkanGpuInfo::get_gpu_info(&vkcore)?.iter() {
202			let index = gpu.get_queue_family_index_by_flags(flags);
203			if index != u32::MAX {
204				return Self::new(vkcore, gpu.clone(), index);
205			}
206		}
207		Err(VulkanError::ChooseGpuFailed)
208	}
209
210	/// Choose a GPU that must support graphics
211	/// * `queue_count`: see `VulkanDevice::new()`
212	pub fn choose_gpu_with_graphics(vkcore: Arc<VkCore>) -> Result<Self, VulkanError> {
213		Self::choose_gpu(vkcore, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT as VkQueueFlags)
214	}
215
216	/// Choose a GPU that must support compute
217	/// * `queue_count`: see `VulkanDevice::new()`
218	pub fn choose_gpu_with_compute(vkcore: Arc<VkCore>) -> Result<Self, VulkanError> {
219		Self::choose_gpu(vkcore, VkQueueFlagBits::VK_QUEUE_COMPUTE_BIT as VkQueueFlags)
220	}
221
222	/// Choose a GPU that must support both graphics and compute
223	/// * `queue_count`: see `VulkanDevice::new()`
224	pub fn choose_gpu_with_graphics_and_compute(vkcore: Arc<VkCore>) -> Result<Self, VulkanError> {
225		Self::choose_gpu(vkcore,
226			VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT as VkQueueFlags |
227			VkQueueFlagBits::VK_QUEUE_COMPUTE_BIT as VkQueueFlags)
228	}
229
230	/// Choose a GPU that is, anyway, a GPU regardless of can do graphics/compute or not.
231	/// * `queue_count`: see `VulkanDevice::new()`
232	pub fn choose_gpu_anyway(vkcore: Arc<VkCore>) -> Result<Self, VulkanError> {
233		Self::choose_gpu(vkcore, 0)
234	}
235
236	/// Get the current queue family index
237	pub fn get_queue_family_index(&self) -> u32 {
238		self.queue_family_index
239	}
240
241	/// Get the GPU info
242	pub fn get_gpu(&self) -> &VulkanGpuInfo {
243		&self.gpu
244	}
245
246	/// Check if the `queue_index` and the `VkSurfaceKHR` were supported by the `VkPhysicalDevice`
247	pub fn get_supported_by_surface(&self, queue_index: usize, surface: VkSurfaceKHR) -> Result<bool, VulkanError> {
248		let mut result: VkBool32 = 0;
249		self.vkcore.vkGetPhysicalDeviceSurfaceSupportKHR(self.get_vk_physical_device(), queue_index as u32, surface, &mut result)?;
250		Ok(result != 0)
251	}
252
253	/// A wrapper for `vkDeviceWaitIdle`
254	pub fn wait_idle(&self) -> Result<(), VulkanError> {
255		self.vkcore.vkDeviceWaitIdle(self.device)?;
256		Ok(())
257	}
258
259	/// Get the `VkPhysicalDevice`
260	pub(crate) fn get_vk_physical_device(&self) -> VkPhysicalDevice {
261		self.gpu.get_vk_physical_device()
262	}
263
264	/// Get the `VkDevice`
265	pub(crate) fn get_vk_device(&self) -> VkDevice {
266		self.device
267	}
268
269	/// Get a queue for the current device
270	pub(crate) fn get_vk_queue(&self) -> VkQueue {
271		self.queue
272	}
273}
274
275impl Debug for VulkanDevice {
276	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
277		f.debug_struct("VulkanDevice")
278		.field("queue_family_index", &self.queue_family_index)
279		.field("gpu", &self.gpu)
280		.field("device", &self.device)
281		.field("queue", &self.queue)
282		.finish()
283	}
284}
285
286impl Clone for VulkanDevice {
287	fn clone(&self) -> Self {
288		Self::new(self.vkcore.clone(), self.gpu.clone(), self.queue_family_index).unwrap()
289	}
290}
291
292impl Drop for VulkanDevice {
293	fn drop(&mut self) {
294		proceed_run(self.vkcore.vkDestroyDevice(self.device, null()))
295	}
296}
297
298unsafe impl Send for VulkanDevice {}
299unsafe impl Sync for VulkanDevice {}