1use std::sync::Arc;
2
3use ash::{Entry, vk};
4
5use crate::{
6 VulkanInitError,
7 adapter::{VulkanAdapter, VulkanAdapterDescriptor},
8 wrappers::*,
9};
10
11pub struct VulkanInstance {
13 #[cfg(feature = "wgpu")]
14 pub(crate) wgpu_instance: wgpu::Instance,
15
16 _entry: Arc<Entry>,
17 pub(crate) instance: Arc<Instance>,
18 _debug_messenger: Option<DebugMessenger>,
19}
20
21impl VulkanInstance {
22 pub fn new() -> Result<Arc<Self>, VulkanInitError> {
23 let entry = Arc::new(unsafe { Entry::load()? });
24 Self::new_from_entry(entry)
25 }
26
27 pub fn new_from(
28 vulkan_library_path: impl AsRef<std::ffi::OsStr>,
29 ) -> Result<Arc<Self>, VulkanInitError> {
30 let entry = Arc::new(unsafe { Entry::load_from(vulkan_library_path)? });
31 Self::new_from_entry(entry)
32 }
33
34 fn new_from_entry(entry: Arc<Entry>) -> Result<Arc<Self>, VulkanInitError> {
35 let api_version = vk::make_api_version(0, 1, 3, 0);
36 let app_info = vk::ApplicationInfo {
37 api_version,
38 ..Default::default()
39 };
40
41 let mut requested_layers = Vec::new();
42
43 if cfg!(feature = "vk-validation") {
44 requested_layers.push(c"VK_LAYER_KHRONOS_validation");
45 }
46
47 if cfg!(feature = "vk-api-dump") {
48 requested_layers.push(c"VK_LAYER_LUNARG_api_dump");
49 }
50
51 let instance_layer_properties = unsafe { entry.enumerate_instance_layer_properties()? };
52 let instance_layer_names = instance_layer_properties
53 .iter()
54 .map(|layer| layer.layer_name_as_c_str())
55 .collect::<Result<Vec<_>, _>>()?;
56
57 let layers = requested_layers
58 .into_iter()
59 .filter(|requested_layer_name| {
60 instance_layer_names
61 .iter()
62 .any(|instance_layer_name| instance_layer_name == requested_layer_name)
63 })
64 .map(|layer| layer.as_ptr())
65 .collect::<Vec<_>>();
66
67 let extensions = vec![vk::EXT_DEBUG_UTILS_NAME];
68
69 let extensions = extensions.into_iter().collect::<Vec<_>>();
70 #[cfg(feature = "wgpu")]
71 let extensions = merge_with_wgpu_instance_extensions(&entry, api_version, extensions)?;
72
73 let extension_ptrs = extensions.iter().map(|e| e.as_ptr()).collect::<Vec<_>>();
74
75 let create_info = vk::InstanceCreateInfo::default()
76 .application_info(&app_info)
77 .enabled_layer_names(&layers)
78 .enabled_extension_names(&extension_ptrs);
79
80 let instance = unsafe { entry.create_instance(&create_info, None) }?;
81 let video_queue_instance_ext = ash::khr::video_queue::Instance::new(&entry, &instance);
82 let video_encode_queue_instance_ext =
83 ash::khr::video_encode_queue::Instance::new(&entry, &instance);
84 let debug_utils_instance_ext = ash::ext::debug_utils::Instance::new(&entry, &instance);
85
86 let instance = Arc::new(Instance {
87 instance,
88 _entry: entry.clone(),
89 video_queue_instance_ext,
90 debug_utils_instance_ext,
91 video_encode_queue_instance_ext,
92 });
93
94 let debug_messenger = if cfg!(debug_assertions) {
95 Some(DebugMessenger::new(instance.clone())?)
96 } else {
97 None
98 };
99
100 #[cfg(feature = "wgpu")]
101 let wgpu_instance =
102 create_wgpu_instance(&entry, instance.clone(), api_version, extensions)?;
103
104 Ok(Self {
105 _entry: entry,
106 instance,
107 _debug_messenger: debug_messenger,
108
109 #[cfg(feature = "wgpu")]
110 wgpu_instance,
111 }
112 .into())
113 }
114
115 #[cfg(feature = "wgpu")]
116 pub fn wgpu_instance(&self) -> wgpu::Instance {
117 self.wgpu_instance.clone()
118 }
119
120 pub fn create_adapter<'a>(
122 &'a self,
123 descriptor: &VulkanAdapterDescriptor,
124 ) -> Result<VulkanAdapter<'a>, VulkanInitError> {
125 self.iter_adapters()?
126 .find(|adapter| {
127 if (descriptor.supports_decoding && !adapter.supports_decoding())
128 || (descriptor.supports_encoding && !adapter.supports_encoding())
129 {
130 return false;
131 }
132
133 #[cfg(feature = "wgpu")]
134 if let Some(surface) = descriptor.compatible_surface
135 && !adapter.supports_surface(surface)
136 {
137 return false;
138 }
139
140 true
141 })
142 .ok_or(VulkanInitError::NoDevice)
143 }
144
145 pub fn iter_adapters<'a>(
147 &'a self,
148 ) -> Result<impl Iterator<Item = VulkanAdapter<'a>> + 'a, VulkanInitError> {
149 crate::adapter::iter_adapters(self)
150 }
151}
152
153impl std::fmt::Debug for VulkanInstance {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 f.debug_struct("VulkanInstance").finish()
156 }
157}
158
159#[cfg(feature = "wgpu")]
160fn merge_with_wgpu_instance_extensions(
161 entry: &Entry,
162 api_version: u32,
163 extensions: Vec<&'static std::ffi::CStr>,
164) -> Result<Vec<&'static std::ffi::CStr>, crate::WgpuInitError> {
165 let wgpu_extensions = wgpu::hal::vulkan::Instance::desired_extensions(
166 entry,
167 api_version,
168 wgpu::InstanceFlags::empty(),
169 )?;
170
171 Ok([extensions, wgpu_extensions].concat())
172}
173
174#[cfg(feature = "wgpu")]
175fn create_wgpu_instance(
176 entry: &Entry,
177 instance: Arc<Instance>,
178 api_version: u32,
179 extensions: Vec<&'static std::ffi::CStr>,
180) -> Result<wgpu::Instance, crate::WgpuInitError> {
181 let wgpu_instance = unsafe {
182 wgpu::hal::vulkan::Instance::from_raw(
183 (*entry).clone(),
184 instance.instance.clone(),
185 api_version,
186 0,
187 None,
188 extensions,
189 wgpu::InstanceFlags::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER,
190 wgpu::MemoryBudgetThresholds::default(),
191 false,
192 Some(Box::new(move || {
193 drop(instance);
194 })),
195 )?
196 };
197
198 Ok(unsafe { wgpu::Instance::from_hal::<wgpu::hal::vulkan::Api>(wgpu_instance) })
199}