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