ferroui_vulkan/
vulkan_options.rs1use crate::{IVulkanDevice, IVulkanInstance, IVulkanKhrSurfacePlatformSurfaceFactory, VulkanException};
2use std::any::{Any, TypeId};
3use std::collections::HashMap;
4use std::fmt;
5use std::sync::Arc;
6
7pub type VkGetInstanceProcAddressDelegate = Arc<dyn Fn(isize, &str) -> isize + Send + Sync>;
11
12pub type VulkanDeviceCheckSurfaceFactory =
16 Arc<dyn Fn(&Arc<dyn IVulkanInstance>) -> Result<u64, VulkanException> + Send + Sync>;
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct Version {
21 pub major: i32,
22 pub minor: i32,
23 pub build: i32,
24}
25
26impl Version {
27 pub const fn new(major: i32, minor: i32, build: i32) -> Self {
28 Self { major, minor, build }
29 }
30}
31
32impl fmt::Display for Version {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 write!(f, "{}.{}.{}", self.major, self.minor, self.build)
35 }
36}
37
38#[derive(Clone, Default)]
40pub struct VulkanOptions {
41 pub vulkan_instance_creation_options: VulkanInstanceCreationOptions,
42 pub vulkan_device_creation_options: VulkanDeviceCreationOptions,
43 pub custom_shared_device: Option<Arc<dyn IVulkanDevice>>,
46}
47
48#[derive(Clone)]
49pub struct VulkanInstanceCreationOptions {
50 pub custom_get_proc_address_delegate: Option<VkGetInstanceProcAddressDelegate>,
52
53 pub application_name: Option<String>,
55
56 pub vulkan_version: Version,
58
59 pub instance_extensions: Vec<String>,
61
62 pub enabled_layers: Vec<String>,
64
65 pub use_debug: bool,
67
68 pub require_surface_extension: bool,
71}
72
73impl Default for VulkanInstanceCreationOptions {
74 fn default() -> Self {
75 Self {
76 custom_get_proc_address_delegate: None,
77 application_name: None,
78 vulkan_version: Version::new(1, 1, 0),
79 instance_extensions: Vec::new(),
80 enabled_layers: Vec::new(),
81 use_debug: false,
82 require_surface_extension: true,
83 }
84 }
85}
86
87#[derive(Clone, Debug, PartialEq, Eq)]
88pub struct VulkanDeviceCreationOptions {
89 pub device_extensions: Vec<String>,
91
92 pub prefer_discrete_gpu: bool,
94
95 pub require_compute_bit: bool,
96
97 pub require_swapchain_extension: bool,
100}
101
102impl Default for VulkanDeviceCreationOptions {
103 fn default() -> Self {
104 Self {
105 device_extensions: Vec::new(),
106 prefer_discrete_gpu: false,
107 require_compute_bit: false,
108 require_swapchain_extension: true,
109 }
110 }
111}
112
113#[derive(Clone, Default)]
115pub struct VulkanPlatformSpecificOptions {
116 pub required_instance_extensions: Vec<String>,
118
119 pub get_proc_address_delegate: Option<VkGetInstanceProcAddressDelegate>,
121
122 pub device_check_surface_factory: Option<VulkanDeviceCheckSurfaceFactory>,
125
126 pub platform_features: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
130}
131
132impl VulkanPlatformSpecificOptions {
133 pub fn set_khr_surface_factory(&mut self, factory: Arc<dyn IVulkanKhrSurfacePlatformSurfaceFactory>) {
136 self.platform_features
137 .insert(TypeId::of::<dyn IVulkanKhrSurfacePlatformSurfaceFactory>(), Arc::new(factory));
138 }
139
140 pub fn khr_surface_factory(&self) -> Option<Arc<dyn IVulkanKhrSurfacePlatformSurfaceFactory>> {
142 khr_surface_factory_of(&self.platform_features)
143 }
144}
145
146pub(crate) fn khr_surface_factory_of(
148 platform_features: &HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
149) -> Option<Arc<dyn IVulkanKhrSurfacePlatformSurfaceFactory>> {
150 platform_features
151 .get(&TypeId::of::<dyn IVulkanKhrSurfacePlatformSurfaceFactory>())?
152 .downcast_ref::<Arc<dyn IVulkanKhrSurfacePlatformSurfaceFactory>>()
153 .cloned()
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::{IVulkanKhrSurfacePlatformSurface, IVulkanPlatformGraphicsContext};
160 use ferroui_base::platform::surfaces::IPlatformRenderSurface;
161 use std::rc::Rc;
162
163 #[test]
164 fn the_defaults_are_those_of_the_reference() {
165 let options = VulkanOptions::default();
166 let instance = &options.vulkan_instance_creation_options;
167 assert!(instance.custom_get_proc_address_delegate.is_none());
168 assert_eq!(instance.application_name, None);
169 assert_eq!(instance.vulkan_version, Version::new(1, 1, 0));
170 assert!(instance.instance_extensions.is_empty());
171 assert!(instance.enabled_layers.is_empty());
172 assert!(!instance.use_debug);
173 assert!(instance.require_surface_extension);
174
175 let device = &options.vulkan_device_creation_options;
176 assert!(device.device_extensions.is_empty());
177 assert!(!device.prefer_discrete_gpu);
178 assert!(!device.require_compute_bit);
179 assert!(device.require_swapchain_extension);
180
181 assert!(options.custom_shared_device.is_none());
182
183 let platform = VulkanPlatformSpecificOptions::default();
184 assert!(platform.required_instance_extensions.is_empty());
185 assert!(platform.get_proc_address_delegate.is_none());
186 assert!(platform.device_check_surface_factory.is_none());
187 assert!(platform.platform_features.is_empty());
188 assert!(platform.khr_surface_factory().is_none());
189 }
190
191 #[test]
192 fn a_version_prints_its_three_parts() {
193 assert_eq!(Version::new(1, 1, 0).to_string(), "1.1.0");
194 }
195
196 struct Factory;
197
198 impl IVulkanKhrSurfacePlatformSurfaceFactory for Factory {
199 fn can_render_to_surface(
200 &self,
201 _context: &dyn IVulkanPlatformGraphicsContext,
202 _surface: &Arc<dyn IPlatformRenderSurface>,
203 ) -> bool {
204 false
205 }
206
207 fn create_surface(
208 &self,
209 _context: &dyn IVulkanPlatformGraphicsContext,
210 _surface: &Arc<dyn IPlatformRenderSurface>,
211 ) -> Rc<dyn IVulkanKhrSurfacePlatformSurface> {
212 unreachable!()
213 }
214 }
215
216 #[test]
217 fn the_surface_factory_is_a_platform_feature() {
218 let mut platform = VulkanPlatformSpecificOptions::default();
219 let factory: Arc<dyn IVulkanKhrSurfacePlatformSurfaceFactory> = Arc::new(Factory);
220 platform.set_khr_surface_factory(factory.clone());
221
222 assert_eq!(platform.platform_features.len(), 1);
223 let found = platform.khr_surface_factory().expect("the factory is registered");
224 assert!(Arc::ptr_eq(&found, &factory));
225
226 let copy = platform.clone();
228 assert!(Arc::ptr_eq(©.khr_surface_factory().unwrap(), &factory));
229 }
230}