vkobject_rs/
surface.rs

1
2use crate::prelude::*;
3use std::{
4	fmt::{self, Debug, Formatter},
5	ptr::{null, null_mut},
6	sync::Arc,
7};
8
9/// The wrapper for `VkSurfaceKHR`
10pub struct VulkanSurface {
11	/// The Vulkan driver
12	pub(crate) vkcore: Arc<VkCore>,
13
14	/// The handle to the surface
15	surface: VkSurfaceKHR,
16
17	/// The format of the surface
18	format: VkSurfaceFormatKHR,
19}
20
21unsafe impl Send for VulkanSurface {}
22unsafe impl Sync for VulkanSurface {}
23
24impl VulkanSurface {
25	/// Create a new `VulkanSurface` by the given `VkSurfaceKHR` and `VkSurfaceFormatKHR`
26	pub fn new_from(vkcore: Arc<VkCore>, surface: VkSurfaceKHR, format: VkSurfaceFormatKHR) -> Self {
27		Self {
28			vkcore,
29			surface,
30			format,
31		}
32	}
33	/// Create a new `VulkanSurface` from the generic type `surface_ci` by calling the given function pointer of `vkCreateSurfaceXxxx()`
34	#[allow(dead_code)]
35	fn new_from_ci<T>(function_name: &'static str, vkcore: Arc<VkCore>, device: &VulkanDevice, vk_create_surface: fn(VkInstance, &T, *const VkAllocationCallbacks, *mut VkSurfaceKHR) -> VkResult, surface_ci: &T) -> Result<Self, VulkanError> {
36		let gpu_info = device.get_gpu();
37		let mut surface: VkSurfaceKHR = null();
38		vk_result_conv(function_name, vk_create_surface(vkcore.get_instance(), surface_ci, null(), &mut surface))?;
39		let surface = ResourceGuard::new(surface, |&s|{let vkcore = vkcore.clone(); vkcore.vkDestroySurfaceKHR(vkcore.get_instance(), s, null()).unwrap()});
40
41		let queue_families = gpu_info.get_queue_families();
42		let mut supported = Vec::<bool>::with_capacity(queue_families.len());
43		for i in 0..queue_families.len() {
44			supported.push(device.get_supported_by_surface(i, *surface)?);
45		}
46		let mut graphics_queue_node_index = u32::MAX;
47		let mut present_queue_node_index = u32::MAX;
48		for (i, queue_family) in queue_families.iter().enumerate() {
49			if (queue_family.queueFlags & VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT as VkQueueFlags) == VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT as VkQueueFlags {
50				graphics_queue_node_index = i as u32;
51				if supported[i] {
52					present_queue_node_index = i as u32;
53					break;
54				}
55			}
56		}
57		if present_queue_node_index == u32::MAX {
58			for (i, s) in supported.iter().enumerate() {
59				if *s {
60					present_queue_node_index = i as u32;
61					break;
62				}
63			}
64		}
65		if graphics_queue_node_index == u32::MAX && present_queue_node_index == u32::MAX {
66			return Err(VulkanError::NoGoodQueueForSurface("Could not find a graphics and/or presenting queue!"));
67		}
68		if graphics_queue_node_index != present_queue_node_index {
69			return Err(VulkanError::NoGoodQueueForSurface("Separate graphics and presenting queues are not supported yet!"));
70		}
71		let mut num_formats: u32 = 0;
72		vkcore.vkGetPhysicalDeviceSurfaceFormatsKHR(gpu_info.get_vk_physical_device(), *surface, &mut num_formats, null_mut())?;
73		let mut formats = Vec::<VkSurfaceFormatKHR>::with_capacity(num_formats as usize);
74		vkcore.vkGetPhysicalDeviceSurfaceFormatsKHR(gpu_info.get_vk_physical_device(), *surface, &mut num_formats, formats.as_mut_ptr())?;
75		unsafe {formats.set_len(num_formats as usize)};
76
77		let mut selected_format = formats[0];
78
79		const PREFERRED_FORMAT: [VkFormat; 3] = [
80			VkFormat::VK_FORMAT_B8G8R8A8_UNORM,
81			VkFormat::VK_FORMAT_R8G8B8A8_UNORM,
82			VkFormat::VK_FORMAT_A8B8G8R8_UNORM_PACK32,
83		];
84
85		'find_format: {
86			for pf in PREFERRED_FORMAT.iter() {
87				for f in formats.iter() {
88					if f.format == *pf {
89						selected_format = *f;
90						break 'find_format;
91					}
92				}
93			}
94		}
95		let surface = surface.release();
96		Ok(Self::new_from(vkcore, surface, selected_format))
97	}
98	/// Create a `VulkanSurface` by using the GLFW API
99	#[cfg(any(feature = "glfw", test))]
100	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, window: &glfw::PWindow) -> Result<Self, VulkanError> {
101		Self::new_from_ci("vkCreateWindowSurfaceGLFW", vkcore, device, vkCreateWindowSurfaceGLFW, window)
102	}
103	/// Create a `VulkanSurface` by using the Win32 API
104	#[cfg(feature = "win32_khr")]
105	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, hwnd: HWND, hinstance: HINSTANCE) -> Result<Self, VulkanError> {
106		let surface_ci = VkWin32SurfaceCreateInfoKHR {
107			sType: VkStructureType::VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
108			pNext: null(),
109			flags: 0,
110			hinstance,
111			hwnd,
112		};
113		Self::new_from_ci("vkCreateWin32SurfaceKHR", vkcore, device, vkCreateWin32SurfaceKHR, &surface_ci)
114	}
115	/// Create a `VulkanSurface` for Android
116	#[cfg(feature = "android_khr")]
117	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, window: *const ANativeWindow) -> Result<Self, VulkanError> {
118		let surface_ci = VkAndroidSurfaceCreateInfoKHR {
119			sType: VkStructureType::VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
120			pNext: null(),
121			flags: 0,
122			window,
123		};
124		Self::new_from_ci("vkCreateAndroidSurfaceKHR", vkcore, device, vkCreateAndroidSurfaceKHR, &surface_ci)
125	}
126	/// Create a `VulkanSurface` for IOS
127	#[cfg(feature = "ios_mvk")]
128	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, view: *const c_void) -> Result<Self, VulkanError> {
129		let surface_ci = VkIOSSurfaceCreateInfoMVK {
130			sType: VkStructureType::VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK,
131			pNext: null(),
132			flags: 0,
133			pView: view,
134		};
135		Self::new_from_ci("vkCreateIOSSurfaceMVK", vkcore, device, vkCreateIOSSurfaceMVK, &surface_ci)
136	}
137	/// Create a `VulkanSurface` for MacOS
138	#[cfg(feature = "macos_mvk")]
139	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, view: *const c_void) -> Result<Self, VulkanError> {
140		let surface_ci = VkMacOSSurfaceCreateInfoMVK {
141			sType: VkStructureType::VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
142			pNext: null(),
143			flags: 0,
144			pView: view,
145		};
146		Self::new_from_ci("vkCreateMacOSSurfaceMVK", vkcore, device, vkCreateMacOSSurfaceMVK, &surface_ci)
147	}
148	/// Create a `VulkanSurface` for Metal
149	#[cfg(feature = "metal_ext")]
150	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, metal_layer: *const CAMetalLayer) -> Result<Self, VulkanError> {
151		let surface_ci = VkMetalSurfaceCreateInfoEXT {
152			sType: VkStructureType::VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
153			pNext: null(),
154			flags: 0,
155			pLayer: metal_layer,
156		};
157		Self::new_from_ci("vkCreateMetalSurfaceEXT", vkcore, device, vkCreateMetalSurfaceEXT, &surface_ci)
158	}
159	/// Create a `VulkanSurface` for Wayland
160	#[cfg(feature = "wayland_khr")]
161	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, display: *const c_void, surface: *const c_void) -> Result<Self, VulkanError> {
162		let surface_ci = VkWaylandSurfaceCreateInfoKHR {
163			sType: VkStructureType::VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
164			pNext: null(),
165			flags: 0,
166			display,
167			surface,
168		};
169		Self::new_from_ci("vkCreateWaylandSurfaceKHR", vkcore, device, vkCreateWaylandSurfaceKHR, &surface_ci)
170	}
171	/// Create a `VulkanSurface` for XCB
172	#[cfg(feature = "xcb_khr")]
173	pub fn new(vkcore: Arc<VkCore>, device: &VulkanDevice, connection: *const c_void, window: xcb_window_t) -> Result<Self, VulkanError> {
174		let surface_ci = VkXcbSurfaceCreateInfoKHR {
175			sType: VkStructureType::VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
176			pNext: null(),
177			flags: 0,
178			connection,
179			window,
180		};
181		Self::new_from_ci("vkCreateXcbSurfaceKHR", vkcore, device, vkCreateXcbSurfaceKHR, &surface_ci)
182	}
183
184	/// Get the current `VkSurfaceKHR`
185	pub(crate) fn get_vk_surface(&self) -> VkSurfaceKHR {
186		self.surface
187	}
188
189	/// Get the `VkSurfaceFormatKHR`
190	pub(crate) fn get_vk_surface_format(&self) -> &VkSurfaceFormatKHR {
191		&self.format
192	}
193}
194
195impl Debug for VulkanSurface {
196	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
197		f.debug_struct("VulkanSurface")
198		.field("surface", &self.surface)
199		.field("format", &self.format)
200		.finish()
201	}
202}
203
204impl Drop for VulkanSurface {
205	fn drop(&mut self) {
206		self.vkcore.vkDestroySurfaceKHR(self.vkcore.get_instance(), self.surface, null()).unwrap();
207	}
208}