Skip to main content

vk_video/
instance.rs

1use std::sync::Arc;
2
3use ash::{Entry, vk};
4
5use crate::{
6    VulkanInitError,
7    adapter::{VulkanAdapter, VulkanAdapterDescriptor},
8    wrappers::*,
9};
10
11/// Context for all encoders and decoders. Also contains a [`wgpu::Instance`].
12pub 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    /// Creates an adapter that meets requirements specified in the descriptor.
121    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    /// Iterator over all available [`VulkanAdapter`]s that support at least decoding or encoding.
146    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}