1use crate::system_info::{DEBUG_UTILS_EXT_NAME, SystemInfo, VALIDATION_LAYER_NAME};
2use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
3use std::borrow::Cow;
4use std::ffi;
5use std::ffi::c_void;
6use std::fmt::Debug;
7use std::sync::Arc;
8use vulkanalia::vk::{
9 self, EntryV1_1, ExtDebugUtilsExtension, HasBuilder, InstanceV1_0, KhrSurfaceExtension,
10};
11use vulkanalia::vk::{AllocationCallbacks, DebugUtilsMessengerEXT};
12use vulkanalia::{Version, window as vk_window};
13
14pub trait WindowTraits: HasDisplayHandle + HasWindowHandle + Debug {}
15impl<T> WindowTraits for T where T: HasDisplayHandle + HasWindowHandle + Debug {}
16
17unsafe extern "system" fn vulkan_debug_callback(
18 message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
19 message_type: vk::DebugUtilsMessageTypeFlagsEXT,
20 p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
21 _user_data: *mut std::os::raw::c_void,
22) -> vk::Bool32 {
23 unsafe {
24 let callback_data = *p_callback_data;
25 let message_id_number = callback_data.message_id_number;
26
27 let message_id_name = if callback_data.message_id_name.is_null() {
28 Cow::from("")
29 } else {
30 ffi::CStr::from_ptr(callback_data.message_id_name).to_string_lossy()
31 };
32
33 let message = if callback_data.message.is_null() {
34 Cow::from("")
35 } else {
36 ffi::CStr::from_ptr(callback_data.message).to_string_lossy()
37 };
38
39 println!(
40 "{message_severity:?}:\n{message_type:?} [{message_id_name} ({message_id_number})] : {message}\n",
41 );
42
43 vk::FALSE
44 }
45}
46
47#[derive(Debug)]
48pub struct DebugUserData(*mut c_void);
49
50impl Default for DebugUserData {
51 fn default() -> Self {
52 Self(std::ptr::null_mut())
53 }
54}
55
56impl DebugUserData {
57 pub unsafe fn new(data: *mut c_void) -> Self {
59 Self(data)
60 }
61}
62
63impl DebugUserData {
64 pub fn into_inner(self) -> *mut c_void {
65 self.0
66 }
67}
68
69#[derive(Debug)]
70pub struct InstanceBuilder {
71 app_name: String,
73 engine_name: String,
74 application_version: Version,
75 engine_version: Version,
76 minimum_instance_version: Version,
77 required_instance_version: Version,
78
79 layers: Vec<vk::ExtensionName>,
81 extensions: Vec<vk::ExtensionName>,
82 flags: vk::InstanceCreateFlags,
83
84 debug_callback: vk::PFN_vkDebugUtilsMessengerCallbackEXT,
86 debug_message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
87 debug_message_type: vk::DebugUtilsMessageTypeFlagsEXT,
88 debug_user_data: DebugUserData,
89
90 disabled_validation_checks: Vec<vk::ValidationCheckEXT>,
92 enabled_validation_features: Vec<vk::ValidationFeatureEnableEXT>,
93 disabled_validation_features: Vec<vk::ValidationFeatureDisableEXT>,
94
95 allocation_callbacks: Option<vk::AllocationCallbacks>,
96
97 request_validation_layers: bool,
98 enable_validation_layers: bool,
99 use_debug_messenger: bool,
101 headless_context: bool,
102
103 window: Option<Arc<dyn WindowTraits>>,
104}
105
106impl InstanceBuilder {
107 pub fn new(window: Option<Arc<dyn WindowTraits>>) -> Self {
108 Self {
109 app_name: "".to_string(),
110 engine_name: "".to_string(),
111 application_version: Version::new(0, 0, 0),
112 engine_version: Version::new(0, 0, 0),
113 minimum_instance_version: Version::new(0, 0, 0),
114 required_instance_version: Version::new(0, 0, 0),
115 layers: vec![],
116 extensions: vec![],
117 flags: Default::default(),
118 debug_callback: None,
119 debug_message_severity: vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
120 | vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
121 debug_message_type: vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
122 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
123 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
124 debug_user_data: Default::default(),
125 disabled_validation_checks: vec![],
126 enabled_validation_features: vec![],
127 disabled_validation_features: vec![],
128 allocation_callbacks: None,
129 request_validation_layers: false,
130 enable_validation_layers: false,
131 use_debug_messenger: false,
132 headless_context: false,
133 window,
134 }
135 }
136
137 pub fn app_name(mut self, app_name: impl Into<String>) -> Self {
138 self.app_name = app_name.into();
139 self
140 }
141
142 pub fn engine_name(mut self, engine_name: impl Into<String>) -> Self {
143 self.engine_name = engine_name.into();
144 self
145 }
146
147 pub fn app_version(mut self, version: Version) -> Self {
148 self.application_version = version;
149 self
150 }
151
152 pub fn engine_version(mut self, version: Version) -> Self {
153 self.engine_version = version;
154 self
155 }
156
157 pub fn require_api_version(mut self, version: Version) -> Self {
158 self.required_instance_version = version;
159 self
160 }
161
162 pub fn minimum_instance_version(mut self, version: Version) -> Self {
163 self.minimum_instance_version = version;
164 self
165 }
166
167 pub fn enable_layer(mut self, layer: vk::ExtensionName) -> Self {
168 self.layers.push(layer.into());
169 self
170 }
171
172 pub fn enable_extension(mut self, extension: vk::ExtensionName) -> Self {
173 self.extensions.push(extension);
174 self
175 }
176
177 pub fn enable_validation_layers(mut self, enable: bool) -> Self {
178 self.enable_validation_layers = enable;
179 self
180 }
181
182 pub fn request_validation_layers(mut self, request: bool) -> Self {
183 self.request_validation_layers = request;
184 self
185 }
186
187 pub fn use_default_debug_messenger(mut self) -> Self {
188 self.use_debug_messenger = true;
189 self.debug_callback = Some(vulkan_debug_callback);
190 self
191 }
192
193 #[cfg(feature = "enable_tracing")]
194 pub fn use_default_tracing_messenger(mut self) -> Self {
195 self.use_debug_messenger = true;
196 self.debug_callback = Some(crate::tracing::vulkan_tracing_callback);
197 self
198 }
199
200 pub fn set_debug_messenger(
201 mut self,
202 callback: vk::PFN_vkDebugUtilsMessengerCallbackEXT,
203 ) -> Self {
204 self.use_debug_messenger = true;
205 self.debug_callback = callback;
206 self
207 }
208
209 pub fn debug_user_data(mut self, debug_user_data: DebugUserData) -> Self {
210 self.debug_user_data = debug_user_data;
211 self
212 }
213
214 pub fn headless(mut self, headless: bool) -> Self {
215 self.headless_context = headless;
216 self
217 }
218
219 pub fn debug_messenger_severity(
220 mut self,
221 severity: vk::DebugUtilsMessageSeverityFlagsEXT,
222 ) -> Self {
223 self.debug_message_severity = severity;
224 self
225 }
226
227 pub fn add_debug_messenger_severity(
228 mut self,
229 severity: vk::DebugUtilsMessageSeverityFlagsEXT,
230 ) -> Self {
231 self.debug_message_severity |= severity;
232 self
233 }
234
235 pub fn debug_messenger_type(mut self, message_type: vk::DebugUtilsMessageTypeFlagsEXT) -> Self {
236 self.debug_message_type = message_type;
237 self
238 }
239
240 pub fn add_debug_messenger_type(
241 mut self,
242 message_type: vk::DebugUtilsMessageTypeFlagsEXT,
243 ) -> Self {
244 self.debug_message_type |= message_type;
245 self
246 }
247
248 #[cfg_attr(feature = "enable_tracing", tracing::instrument(skip(self)))]
249 pub fn build(self) -> crate::Result<Arc<Instance>> {
250 let system_info = SystemInfo::get_system_info()?;
251
252 let instance_version = {
253 if self.minimum_instance_version > Version::V1_0_0
254 || self.required_instance_version > Version::V1_0_0
255 {
256 let version = unsafe { system_info.entry.enumerate_instance_version() }
257 .map_or(Version::V1_0_0, Version::from);
258
259 if version < self.minimum_instance_version
260 || (self.minimum_instance_version == Version::V1_0_0
261 && version < self.required_instance_version)
262 {
263 return match self
264 .required_instance_version
265 .max(self.minimum_instance_version)
266 .minor
267 {
268 3 => Err(crate::InstanceError::VulkanVersion13Unavailable.into()),
269 2 => Err(crate::InstanceError::VulkanVersion12Unavailable.into()),
270 1 => Err(crate::InstanceError::VulkanVersion11Unavailable.into()),
271 minor => Err(crate::InstanceError::VulkanVersionUnavailable(format!(
272 "1.{minor}"
273 ))
274 .into()),
275 };
276 } else {
277 version
278 }
279 } else {
280 Version::V1_0_0
281 }
282 };
283
284 #[cfg(feature = "enable_tracing")]
285 {
286 tracing::info!(
287 "Instance version: {}.{}.{}",
288 instance_version.major,
289 instance_version.minor,
290 instance_version.patch
291 );
292 }
293
294 let api_version = if instance_version < Version::V1_1_0
295 || self.required_instance_version < self.minimum_instance_version
296 {
297 instance_version
298 } else {
299 self.required_instance_version
300 .max(self.minimum_instance_version)
301 };
302 #[cfg(feature = "enable_tracing")]
303 {
304 tracing::info!("api_version: {}", api_version);
305 }
306
307 let app_name = self.app_name;
308 let engine_name = self.engine_name;
309
310 let app_info = vk::ApplicationInfo {
311 application_name: app_name.as_bytes().as_ptr() as _,
312 application_version: self.application_version.into(),
313 engine_name: engine_name.as_bytes().as_ptr() as _,
314 engine_version: self.engine_version.into(),
315 api_version: api_version.into(),
316 ..Default::default()
317 };
318
319 #[cfg(feature = "enable_tracing")]
320 {
321 tracing::info!("Creating vkInstance with application info...");
322 tracing::debug!(
323 r#"
324Application info: {{
325 name: {:?},
326 version: {}.{}.{},
327 engine_name: {:?},
328 engine_version: {}.{}.{},
329 api_version: {}.{}.{},
330}}
331 "#,
332 app_name,
333 self.application_version.major,
334 self.application_version.minor,
335 self.application_version.patch,
336 engine_name,
337 self.engine_version.major,
338 self.engine_version.minor,
339 self.engine_version.patch,
340 api_version.major,
341 api_version.minor,
342 api_version.patch,
343 )
344 }
345
346 let mut enabled_extensions: Vec<vk::ExtensionName> = vec![];
347 let mut enabled_layers: Vec<vk::ExtensionName> = vec![];
348
349 enabled_extensions.extend_from_slice(self.extensions.as_slice());
350
351 if self.debug_callback.is_some()
352 && self.use_debug_messenger
353 && system_info.debug_utils_available
354 {
355 enabled_extensions.push(DEBUG_UTILS_EXT_NAME);
356 }
357
358 let properties2_ext_enabled = api_version < Version::V1_1_0
359 && system_info
360 .is_extension_available(&vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name)?;
361
362 if properties2_ext_enabled {
363 enabled_extensions.push(vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name);
364 }
365
366 #[cfg(feature = "portability")]
367 let portability_enumeration_support =
368 system_info.is_extension_available(&vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name)?;
369 #[cfg(feature = "portability")]
370 if portability_enumeration_support {
371 enabled_extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name);
372 }
373
374 if !self.headless_context {
375 if let Some(window) = self.window.clone() {
376 let surface_extensions: Vec<vk::ExtensionName> =
377 vk_window::get_required_instance_extensions(window.as_ref())
378 .into_iter()
379 .map(|ext| **ext)
380 .collect();
381
382 if !system_info.are_extensions_available(&surface_extensions)? {
383 return Err(crate::InstanceError::WindowingExtensionsNotPresent(
384 surface_extensions,
385 )
386 .into());
387 };
388
389 enabled_extensions.extend_from_slice(&surface_extensions);
390 }
391 }
392
393 #[cfg(feature = "enable_tracing")]
394 tracing::trace!(?enabled_extensions);
395
396 let all_extensions_supported = system_info.are_extensions_available(&enabled_extensions)?;
397 if !all_extensions_supported {
398 return Err(
399 crate::InstanceError::RequestedExtensionsNotPresent(enabled_extensions).into(),
400 );
401 };
402
403 enabled_layers.extend_from_slice(&self.layers);
404
405 if self.enable_validation_layers
406 || (self.request_validation_layers && system_info.validation_layers_available)
407 {
408 enabled_layers.push(VALIDATION_LAYER_NAME)
409 };
410
411 let all_layers_supported = system_info.are_layers_available(self.layers)?;
412
413 if !all_layers_supported {
414 return Err(crate::InstanceError::RequestedLayersNotPresent(enabled_layers).into());
415 };
416
417 let instance_create_flags = if cfg!(feature = "portability") {
418 self.flags | vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
419 } else {
420 self.flags
421 };
422
423 let enabled_extension_ptr = enabled_extensions
424 .iter()
425 .map(|e| e.as_ptr())
426 .collect::<Vec<_>>();
427
428 let enabled_layers_ptr = enabled_layers
429 .iter()
430 .map(|e| e.as_ptr())
431 .collect::<Vec<_>>();
432
433 let mut instance_create_info = vk::InstanceCreateInfo::builder()
434 .flags(instance_create_flags)
435 .application_info(&app_info)
436 .enabled_extension_names(&enabled_extension_ptr)
437 .enabled_layer_names(&enabled_layers_ptr);
438
439 let mut features = vk::ValidationFeaturesEXT::builder()
440 .disabled_validation_features(&self.disabled_validation_features)
441 .enabled_validation_features(&self.enabled_validation_features);
442
443 if !self.enabled_validation_features.is_empty()
444 || !self.disabled_validation_features.is_empty()
445 {
446 instance_create_info = instance_create_info.push_next(&mut features);
447 };
448
449 let mut checks = vk::ValidationFlagsEXT::builder();
450 if !self.disabled_validation_checks.is_empty() {
451 checks = checks.disabled_validation_checks(&self.disabled_validation_checks);
452
453 instance_create_info = instance_create_info.push_next(&mut checks);
454 };
455
456 let instance = unsafe {
457 system_info
458 .entry
459 .create_instance(&instance_create_info, self.allocation_callbacks.as_ref())
460 }
461 .map_err(|_| crate::InstanceError::FailedCreateInstance)?;
462
463 #[cfg(feature = "enable_tracing")]
464 tracing::info!("Created vkInstance");
465
466 let mut debug_messenger = None;
467 let mut debug_user_data = self.debug_user_data.into_inner();
468
469 if self.use_debug_messenger {
470 let messenger_create_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
471 .message_severity(self.debug_message_severity)
472 .message_type(self.debug_message_type)
473 .user_callback(self.debug_callback)
474 .user_data(&mut debug_user_data);
475
476 #[cfg(feature = "enable_tracing")]
477 tracing::trace!(?self.debug_callback, "Using debug messenger");
478
479 let messenger =
480 unsafe { instance.create_debug_utils_messenger_ext(&messenger_create_info, None) }?;
481
482 debug_messenger.replace(messenger);
483 };
484
485 let mut surface = None;
486 if let Some(window) = self.window.clone() {
487 surface = Some(unsafe {
488 vk_window::create_surface(&instance, window.as_ref(), window.as_ref())?
489 });
490 #[cfg(feature = "enable_tracing")]
491 tracing::info!("Created vkSurfaceKhr")
492 };
493
494 Ok(Arc::new(Instance {
495 instance,
496 surface,
497 allocation_callbacks: self.allocation_callbacks,
498 instance_version,
499 api_version,
500 properties2_ext_enabled,
501 debug_messenger,
502 _system_info: system_info,
503 }))
504 }
505}
506
507pub struct Instance {
508 pub(crate) instance: vulkanalia::Instance,
509 pub(crate) allocation_callbacks: Option<AllocationCallbacks>,
510 pub(crate) surface: Option<vk::SurfaceKHR>,
511 pub(crate) instance_version: Version,
512 pub api_version: Version,
513 pub(crate) properties2_ext_enabled: bool,
514 pub(crate) debug_messenger: Option<DebugUtilsMessengerEXT>,
515 _system_info: SystemInfo,
516}
517
518impl Instance {
519 pub fn destroy(&self) {
520 unsafe {
521 if let Some(debug_messenger) = self.debug_messenger {
522 self.instance.destroy_debug_utils_messenger_ext(
523 debug_messenger,
524 self.allocation_callbacks.as_ref(),
525 );
526 }
527 if let Some(surface) = self.surface {
528 self.instance
529 .destroy_surface_khr(surface, self.allocation_callbacks.as_ref());
530 }
531 self.instance
532 .destroy_instance(self.allocation_callbacks.as_ref());
533 }
534 }
535}
536
537impl AsRef<vulkanalia::Instance> for Instance {
538 fn as_ref(&self) -> &vulkanalia::Instance {
539 &self.instance
540 }
541}
542
543#[cfg(test)]
544mod tests {
545
546 #[test]
547 fn compiles() {}
548}