vulkan_layer/
layer_trait.rs

1// Copyright 2023 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module includes all the traits that require the layer implementation to implement.
16
17use crate::{bindings::vk_layer::VkLayerInstanceLink, global_simple_intercept::Extension, Global};
18use ash::vk;
19use std::{borrow::Borrow, ffi::CString, ops::Deref, sync::Arc};
20use thiserror::Error;
21
22pub mod generated;
23pub use generated::*;
24
25/// The return value of an intercepted Vulkan command by the layer implementation.
26///
27/// The layer framework uses the value of this type to decide whether to call into the next call
28/// chain after calling into the layer implementation. For an intercepted Vulkan command, if the
29/// layer implementation returns [`LayerResult::Handled`], the layer framework won't call into the
30/// next layer call chain. Otherwise, if [`LayerResult::Unhandled`] is returned, the layer framework
31/// will call into the next layer call chain with the original parameters.
32#[must_use]
33#[derive(Clone)]
34pub enum LayerResult<T> {
35    /// The layer implementation has handled this Vulkan command, so the layer framework shouldn't
36    /// try to call into the next call chain.
37    ///
38    /// This can be useful if the layer implementation wants to modify the parameters passed to the
39    /// next call chain, or wants to use some other Vulkan commands to fake/emulate the intercepted
40    /// Vulkan command. This is useful when the layer wants to emulate an unsupported extension.
41    /// `T` is usually `ash::prelude::VkResult<U>`.
42    Handled(T),
43    /// The layer implementation doesn't handle this Vulkan command, so the layer framework should
44    /// call into the next call chain with the original parameters.
45    ///
46    /// If the layer implementation doesn't want to bother calling into the next call chain, and
47    /// wants the layer framework to do the job, this variant can be used. Note that if the layer
48    /// implementation needs to inform the layer framework that there is an error and needs to
49    /// return early, [`LayerResult::Handled`] should be used.
50    Unhandled,
51}
52
53#[derive(Error, Debug)]
54pub enum TryFromVulkanCommandError {
55    #[error("unknown command `{0}`")]
56    UnknownCommand(String),
57}
58
59/// A trait for the layer implementation to provide metadata of [`DeviceHooks`] for the layer
60/// framework.
61///
62/// This trait serves as the container of the [`DeviceHooks`] type and provides the list of
63/// intercepted
64/// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions)
65/// for the layer framework. This trait and [`DeviceHooks`] can be implemented by the same type.
66///
67/// This trait can also be automatically implemented with the help of the
68/// [`auto_deviceinfo_impl`][crate::auto_deviceinfo_impl] attribute macro.
69///
70/// # Examples
71///
72/// A layer that needs to intercept the `vkCreateImage` function.
73/// ```
74/// # use ash::{vk, prelude::VkResult};
75/// # use vulkan_layer::{DeviceHooks, DeviceInfo, LayerVulkanCommand as VulkanCommand, LayerResult};
76/// #
77/// struct MyLayerDeviceInfo;
78///
79/// impl DeviceHooks for MyLayerDeviceInfo {
80///     fn create_image(
81///         &self,
82///         _p_create_info: &vk::ImageCreateInfo,
83///         _p_allocator: Option<&vk::AllocationCallbacks>,
84///     ) -> LayerResult<VkResult<vk::Image>> {
85///         LayerResult::Unhandled
86///     }
87/// }
88///
89/// impl DeviceInfo for MyLayerDeviceInfo {
90///     type HooksType = Self;
91///     type HooksRefType<'a> = &'a Self;
92///
93///     fn hooked_commands() -> &'static [VulkanCommand] {
94///         &[VulkanCommand::CreateImage]
95///     }
96///
97///     fn hooks(&self) -> Self::HooksRefType<'_> {
98///         self
99///     }
100/// }
101/// ```
102pub trait DeviceInfo: Send + Sync {
103    /// The underlying [`DeviceHooks`] type that implements the core logic to intercept
104    /// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions).
105    ///
106    /// If a type implements both this trait and the [`DeviceHooks`] trait simultaneously,
107    /// [`DeviceInfo::HooksType`] can be set to `Self`.
108    type HooksType: DeviceHooks;
109
110    /// A type that can be dereferencing to [`DeviceInfo::HooksType`]. Usually just
111    /// `&DeviceInfo::HooksType`.
112    ///
113    /// This extra associated type allows the layer implementation to use a smart pointer like
114    /// [`Arc`][std::sync::Arc] or [`MutexGuard`][std::sync::MutexGuard] to hold the reference.
115    ///
116    /// # Examples
117    ///
118    /// A layer implementation that returns a [`Arc`][std::sync::Arc].
119    /// ```
120    /// # use std::sync::Arc;
121    /// # use vulkan_layer::{DeviceHooks, DeviceInfo, LayerVulkanCommand as VulkanCommand};
122    /// #
123    /// # struct MyLayerDeviceHooks;
124    /// #
125    /// # impl DeviceHooks for MyLayerDeviceHooks {}
126    /// #
127    /// struct MyLayerDeviceInfo(Arc<MyLayerDeviceHooks>);
128    ///
129    /// impl DeviceInfo for MyLayerDeviceInfo {
130    ///     type HooksType = MyLayerDeviceHooks;
131    ///     type HooksRefType<'a> = Arc<MyLayerDeviceHooks>;
132    /// #
133    /// #     fn hooked_commands() -> &'static [VulkanCommand] {
134    /// #         &[]
135    /// #     }
136    ///
137    ///     // Other required methods omitted.
138    ///
139    ///     fn hooks(&self) -> Self::HooksRefType<'_> {
140    ///         Arc::clone(&self.0)
141    ///     }
142    /// }
143    /// ```
144    type HooksRefType<'a>: Deref<Target = Self::HooksType> + 'a
145    where
146        Self: 'a;
147
148    /// Returns a slice of
149    /// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions)
150    /// that the layer implementation needs to intercept.
151    ///
152    /// This function should normally return the methods implemented by the associated
153    /// [`DeviceHooks`] type. If the layer implementation needs to decide the functions to intercept
154    /// dynamically at runtime, use the [`Layer::hooked_device_commands`] method to override the
155    /// list of intercepted device functions.
156    ///
157    /// Avoid returning commands other than
158    /// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions).
159    /// Otherwise, those commands may or may not be intercepted.
160    ///
161    /// For Vulkan commands that have multiple names, e.g. `vkCreateSamplerYcbcrConversion` and
162    /// `vkCreateSamplerYcbcrConversionKHR`, only the shortest name should be
163    /// used([`VulkanCommand::CreateSamplerYcbcrConversion`] in this example). The layer framework
164    /// automatically wires both entries to the layer implementation.
165    ///
166    /// # Examples
167    ///
168    /// A layer that intercepts the `vkCreateImage` only if the ASTC LDR feature is enabled.
169    /// ```
170    /// use ash::{self, prelude::VkResult, vk};
171    /// use once_cell::sync::Lazy;
172    /// use std::sync::Arc;
173    /// use vulkan_layer::{
174    ///     DeviceHooks, DeviceInfo, Global, Layer, LayerManifest, LayerResult,
175    ///     LayerVulkanCommand as VulkanCommand, StubGlobalHooks, StubInstanceInfo,
176    ///     VulkanBaseInStructChain,
177    /// };
178    ///
179    /// struct MyLayerDeviceInfo {
180    ///     is_astc_enabled: bool,
181    /// }
182    ///
183    /// impl DeviceHooks for MyLayerDeviceInfo {
184    ///     fn create_image(
185    ///         &self,
186    ///         create_info: &vk::ImageCreateInfo,
187    ///         _p_allocator: Option<&vk::AllocationCallbacks>,
188    ///     ) -> LayerResult<VkResult<vk::Image>> {
189    ///         if create_info.format == vk::Format::ASTC_4X4_UNORM_BLOCK {
190    ///             println!("ASTC 4x4 UNORM image created.");
191    ///         }
192    ///         LayerResult::Unhandled
193    ///     }
194    /// }
195    ///
196    /// impl DeviceInfo for MyLayerDeviceInfo {
197    ///     type HooksType = Self;
198    ///     type HooksRefType<'a> = &'a Self;
199    ///
200    ///     fn hooked_commands() -> &'static [VulkanCommand] {
201    ///         &[VulkanCommand::CreateImage]
202    ///     }
203    ///
204    ///     fn hooks(&self) -> Self::HooksRefType<'_> {
205    ///         self
206    ///     }
207    /// }
208    ///
209    /// #[derive(Default)]
210    /// struct MyLayer(StubGlobalHooks);
211    ///
212    /// impl Layer for MyLayer {
213    ///     // ...
214    /// #     type GlobalHooksInfo = StubGlobalHooks;
215    /// #     type InstanceInfo = StubInstanceInfo;
216    ///     type DeviceInfo = MyLayerDeviceInfo;
217    /// #     type InstanceInfoContainer = StubInstanceInfo;
218    ///     type DeviceInfoContainer = MyLayerDeviceInfo;
219    /// #
220    /// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
221    /// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
222    /// #         &*GLOBAL
223    /// #     }
224    /// #
225    /// #     fn manifest() -> LayerManifest {
226    /// #         Default::default()
227    /// #     }
228    /// #
229    /// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
230    /// #         &self.0
231    /// #     }
232    /// #
233    /// #     fn create_instance_info(
234    /// #         &self,
235    /// #         _: &vk::InstanceCreateInfo,
236    /// #         _: Option<&vk::AllocationCallbacks>,
237    /// #         _: Arc<ash::Instance>,
238    /// #         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
239    /// #     ) -> Self::InstanceInfoContainer {
240    /// #         Default::default()
241    /// #     }
242    /// #
243    ///     fn create_device_info(
244    ///         &self,
245    ///         _: vk::PhysicalDevice,
246    ///         create_info: &vk::DeviceCreateInfo,
247    ///         _: Option<&vk::AllocationCallbacks>,
248    ///         _: Arc<ash::Device>,
249    ///         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
250    ///     ) -> Self::DeviceInfoContainer {
251    ///         let mut p_next_chain: VulkanBaseInStructChain =
252    ///             unsafe { (create_info.p_next as *const vk::BaseInStructure).as_ref() }.into();
253    ///         let is_astc_enabled = p_next_chain
254    ///             .find_map(|p_next| {
255    ///                 let p_next = p_next as *const vk::BaseInStructure;
256    ///                 unsafe {
257    ///                     ash::match_in_struct!(match p_next {
258    ///                         features2 @ vk::PhysicalDeviceFeatures2 => {
259    ///                             Some(&features2.features)
260    ///                         }
261    ///                         _ => {
262    ///                             None
263    ///                         }
264    ///                     })
265    ///                 }
266    ///             })
267    ///             .or_else(|| unsafe { create_info.p_enabled_features.as_ref() })
268    ///             .map(|features| features.texture_compression_astc_ldr == vk::TRUE)
269    ///             .unwrap_or(false);
270    ///         MyLayerDeviceInfo { is_astc_enabled }
271    ///     }
272    ///
273    ///     fn hooked_device_commands(
274    ///         &self,
275    ///         _instance_info: &Self::InstanceInfo,
276    ///         device_info: Option<&Self::DeviceInfo>,
277    ///     ) -> Box<dyn Iterator<Item = VulkanCommand>> {
278    ///         let should_hook_create_image = device_info
279    ///             .map(|device_info| device_info.is_astc_enabled)
280    ///             // Always hook the vkCreateImage function in the function pointers returned by
281    ///             // vkGetInstanceProcAddr: we don't know if the to-be-created VkDevice will be
282    ///             // created with the ASTC feature enabled.
283    ///             .unwrap_or(true);
284    ///         Box::new(
285    ///             Self::DeviceInfo::hooked_commands()
286    ///                 .iter()
287    ///                 .cloned()
288    ///                 .filter(move |command| match command {
289    ///                     VulkanCommand::CreateImage => should_hook_create_image,
290    ///                     _ => true,
291    ///                 }),
292    ///         )
293    ///     }
294    /// }
295    /// ```
296    fn hooked_commands() -> &'static [VulkanCommand];
297
298    /// Returns the reference of the [`DeviceInfo::HooksType`].
299    ///
300    /// The layer framework uses the returned value to call into the layer implementation of
301    /// intercepted commands.
302    fn hooks(&self) -> Self::HooksRefType<'_>;
303}
304
305/// A trait for the layer implementation to provide metadata of [`InstanceHooks`] for the layer
306/// framework.
307///
308/// This trait serves as the container of the [`InstanceHooks`] type and provides the list of
309/// intercepted
310/// [Vulkan instance functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#instance-functions)
311/// ([global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
312/// not included) for the layer framework. This trait and [`InstanceHooks`] can be implemented by
313/// the same type. Avoid returning either
314/// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions)
315/// or
316/// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.).
317///
318/// This trait can also be automatically implemented with the help of the
319/// [`auto_instanceinfo_impl`][crate::auto_instanceinfo_impl] attribute macro.
320///
321/// # Examples
322///
323/// A layer that needs to intercept the `vkCreateWin32SurfaceKHR` function.
324/// ```
325/// use ash::{prelude::VkResult, vk};
326/// use vulkan_layer::{
327///     InstanceHooks, InstanceInfo, LayerResult, LayerVulkanCommand as VulkanCommand,
328/// };
329///
330/// struct MyLayerInstanceHooks;
331///
332/// impl InstanceHooks for MyLayerInstanceHooks {
333///     fn create_win32_surface_khr(
334///         &self,
335///         _p_create_info: &vk::Win32SurfaceCreateInfoKHR,
336///         _p_allocator: Option<&vk::AllocationCallbacks>,
337///     ) -> LayerResult<VkResult<vk::SurfaceKHR>> {
338///         LayerResult::Unhandled
339///     }
340/// }
341///
342/// impl InstanceInfo for MyLayerInstanceHooks {
343///     type HooksType = Self;
344///     type HooksRefType<'a> = &'a Self;
345///
346///     fn hooked_commands() -> &'static [VulkanCommand] {
347///         &[VulkanCommand::CreateWin32SurfaceKhr]
348///     }
349///
350///     fn hooks(&self) -> Self::HooksRefType<'_> {
351///         self
352///     }
353/// }
354/// ```
355pub trait InstanceInfo: Send + Sync {
356    /// The underlying [`InstanceHooks`] type that implements the core logic to intercept
357    /// [Vulkan instance functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#instance-functions)
358    /// apart from
359    /// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.).
360    ///
361    /// If a type implements both this trait and the [`InstanceHooks`] trait simultaneously,
362    /// [`InstanceInfo::HooksType`] can be set to `Self`.
363    type HooksType: InstanceHooks;
364
365    /// A type that can be dereferencing to [`InstanceInfo::HooksType`]. Usually
366    /// `&InstanceInfo::HooksType`.
367    ///
368    /// This extra associated type allows the layer implementation to use a smart pointer like
369    /// [`Arc`][std::sync::Arc] or [`MutexGuard`][std::sync::MutexGuard] to hold the reference.
370    ///
371    /// # Examples
372    ///
373    /// A layer implementation that returns a [`Arc`][std::sync::Arc].
374    /// ```
375    /// # use std::sync::Arc;
376    /// # use vulkan_layer::{InstanceHooks, InstanceInfo, LayerVulkanCommand as VulkanCommand};
377    /// #
378    /// # struct MyLayerInstanceHooks;
379    /// #
380    /// # impl InstanceHooks for MyLayerInstanceHooks {}
381    /// #
382    /// struct MyLayerInstanceInfo(Arc<MyLayerInstanceHooks>);
383    ///
384    /// impl InstanceInfo for MyLayerInstanceInfo {
385    ///     type HooksType = MyLayerInstanceHooks;
386    ///     type HooksRefType<'a> = Arc<MyLayerInstanceHooks>;
387    /// #
388    /// #     fn hooked_commands() -> &'static [VulkanCommand] {
389    /// #         &[]
390    /// #     }
391    ///
392    ///     // Other required methods omitted.
393    ///
394    ///     fn hooks(&self) -> Self::HooksRefType<'_> {
395    ///         Arc::clone(&self.0)
396    ///     }
397    /// }
398    /// ```
399    type HooksRefType<'a>: Deref<Target = Self::HooksType> + 'a
400    where
401        Self: 'a;
402
403    /// Returns a slice of
404    /// [Vulkan instance functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#instance-functions)
405    /// ([global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
406    /// not included) that the layer implementation needs to intercept.
407    ///
408    /// This function should normally return the methods implemented by the associated
409    /// [`InstanceHooks`] type. If the layer implementation needs to decide the function to
410    /// intercept dynamically at runtime, use the [`Layer::hooked_instance_commands`] method to
411    /// override the list of intercepted instance functions.
412    ///
413    /// Avoid returning unexpected commands(i.e.
414    /// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions)
415    /// or
416    /// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)).
417    /// Otherwise, those commands may or may not be intercepted.
418    ///
419    /// For Vulkan commands that have multiple names, e.g. `vkGetPhysicalDeviceProperties2` and
420    /// `vkGetPhysicalDeviceProperties2KHR`, only the shortest name should be
421    /// used([`VulkanCommand::GetPhysicalDeviceProperties2`] in this example). The layer framework
422    /// automatically wires both entries to the layer implementation.
423    ///
424    /// # Examples
425    ///
426    /// A layer that intercepts `vkDestroySurfaceKHR` only if the `VK_KHR_win32_surface` extension
427    /// is enabled.
428    /// ```
429    /// use ash::vk;
430    /// use once_cell::sync::Lazy;
431    /// use std::{ffi::CStr, sync::Arc};
432    /// use vulkan_layer::{
433    ///     Global, InstanceHooks, InstanceInfo, Layer, LayerManifest, LayerResult,
434    ///     LayerVulkanCommand as VulkanCommand, StubDeviceInfo, StubGlobalHooks,
435    /// };
436    ///
437    /// struct MyLayerInstanceInfo {
438    ///     is_win32_surface_enabled: bool,
439    /// }
440    ///
441    /// impl InstanceHooks for MyLayerInstanceInfo {
442    ///     fn destroy_surface_khr(
443    ///         &self,
444    ///         _surface: vk::SurfaceKHR,
445    ///         _p_allocator: Option<&vk::AllocationCallbacks>,
446    ///     ) -> LayerResult<()> {
447    ///         LayerResult::Unhandled
448    ///     }
449    /// }
450    ///
451    /// impl InstanceInfo for MyLayerInstanceInfo {
452    ///     type HooksType = Self;
453    ///     type HooksRefType<'a> = &'a Self;
454    ///
455    ///     fn hooked_commands() -> &'static [VulkanCommand] {
456    ///         &[VulkanCommand::DestroySurfaceKhr]
457    ///     }
458    ///
459    ///     fn hooks(&self) -> Self::HooksRefType<'_> {
460    ///         self
461    ///     }
462    /// }
463    ///
464    /// #[derive(Default)]
465    /// struct MyLayer(StubGlobalHooks);
466    ///
467    /// impl Layer for MyLayer {
468    ///     // ...
469    /// #     type GlobalHooksInfo = StubGlobalHooks;
470    ///     type InstanceInfo = MyLayerInstanceInfo;
471    /// #     type DeviceInfo = StubDeviceInfo;
472    ///     type InstanceInfoContainer = MyLayerInstanceInfo;
473    /// #     type DeviceInfoContainer = StubDeviceInfo;
474    /// #
475    /// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
476    /// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
477    /// #         &*GLOBAL
478    /// #     }
479    /// #
480    /// #     fn manifest() -> LayerManifest {
481    /// #         Default::default()
482    /// #     }
483    /// #
484    /// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
485    /// #         &self.0
486    /// #     }
487    ///
488    ///     fn create_instance_info(
489    ///         &self,
490    ///         create_info: &vk::InstanceCreateInfo,
491    ///         _: Option<&vk::AllocationCallbacks>,
492    ///         _: Arc<ash::Instance>,
493    ///         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
494    ///     ) -> Self::InstanceInfoContainer {
495    ///         let enabled_extensions = if create_info.enabled_extension_count > 0 {
496    ///             unsafe {
497    ///                 std::slice::from_raw_parts(
498    ///                     create_info.pp_enabled_extension_names,
499    ///                     create_info.enabled_extension_count as usize,
500    ///                 )
501    ///             }
502    ///         } else {
503    ///             &[]
504    ///         };
505    ///         let is_win32_surface_enabled = enabled_extensions
506    ///             .iter()
507    ///             .find(|extension_name| {
508    ///                 (unsafe { CStr::from_ptr(**extension_name) })
509    ///                     == ash::extensions::khr::Win32Surface::name()
510    ///             })
511    ///             .is_some();
512    ///         MyLayerInstanceInfo {
513    ///             is_win32_surface_enabled,
514    ///         }
515    ///     }
516    ///
517    ///     fn hooked_instance_commands(
518    ///         &self,
519    ///         instance_info: &Self::InstanceInfo,
520    ///     ) -> Box<dyn Iterator<Item = VulkanCommand>> {
521    ///         let should_hook_destroy_surface = instance_info.is_win32_surface_enabled;
522    ///         Box::new(
523    ///             Self::InstanceInfo::hooked_commands()
524    ///                 .iter()
525    ///                 .cloned()
526    ///                 .filter(move |command| match command {
527    ///                     VulkanCommand::DestroySurfaceKhr => should_hook_destroy_surface,
528    ///                     _ => true,
529    ///                 }),
530    ///         )
531    ///     }
532    /// #
533    /// #     fn create_device_info(
534    /// #         &self,
535    /// #         _: vk::PhysicalDevice,
536    /// #         _: &vk::DeviceCreateInfo,
537    /// #         _: Option<&vk::AllocationCallbacks>,
538    /// #         _: Arc<ash::Device>,
539    /// #         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
540    /// #     ) -> Self::DeviceInfoContainer {
541    /// #         Default::default()
542    /// #     }
543    /// }
544    /// ```
545    fn hooked_commands() -> &'static [VulkanCommand];
546
547    /// Returns the reference of the [`InstanceInfo::HooksType`].
548    ///
549    /// The layer framework uses the returned value to call into the layer implementation of
550    /// intercepted commands.
551    fn hooks(&self) -> Self::HooksRefType<'_>;
552}
553
554/// A trait for the layer implementation to provide the implementation of the intercepted
555/// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.).
556///
557/// The global commands are copied here for convenience:
558/// * `vkEnumerateInstanceVersion`
559/// * `vkEnumerateInstanceExtensionProperties`
560/// * `vkEnumerateInstanceLayerProperties`
561/// * `vkCreateInstance`
562///
563/// Currently, it is only supported to intercept the `vkCreateInstance` function.
564pub trait GlobalHooks: Send + Sync {
565    /// The logic to intercept the `vkCreateInstance` function.
566    ///
567    /// The implementations should return [`LayerResult::Unhandled`] if the layer implementation
568    /// wants the layer framework to handle the task to call into the next layer, otherwise should
569    /// return [`LayerResult::Handled`].
570    ///
571    /// This function is usually intercepted if the layer needs to modify the `VkInstanceCreateInfo`
572    /// passed to the next layer. Otherwise, [`Layer::create_instance_info`] is almost always
573    /// better. This function is called before [`Layer::create_instance_info`] to create the
574    /// `VkInstance`.
575    ///
576    /// # Arguments
577    ///
578    /// * `_p_create_info` is a pointer to a VkInstanceCreateInfo structure controlling creation of
579    ///   the instance. The `VkLayerInstanceLink` linked list in the `pNext` chain is already
580    ///   advanced by the layer framework.
581    /// * `_layer_instance_link` is the `VkLayerInstanceLink` linked list node pointing to the next
582    ///   layer.
583    /// * `_p_allocator` controls host memory allocation as described in the Memory Allocation
584    ///   chapter of the Vulkan spec.
585    /// * `_p_instance` points a VkInstance handle in which the resulting instance is returned.
586    ///   If the layer implementation wants to handle the call to the next layer, according to
587    ///   [the `LLP_LAYER_21` requirement](https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderLayerInterface.md#example-code-for-createinstance:~:text=LLP_LAYER_21,N/A),
588    ///   implementations must guarantee that the original pointer should be passed to the lower
589    ///   layers.
590    ///
591    /// # Examples
592    /// A layer that always enables the `VK_KHR_surface` extension.
593    /// ```
594    /// use ash::vk;
595    /// use std::{ffi::CStr, ptr::null};
596    /// use vulkan_layer::{GlobalHooks, LayerResult, VkLayerInstanceLink};
597    ///
598    /// struct MyGlobalHooks;
599    ///
600    /// impl GlobalHooks for MyGlobalHooks {
601    ///     fn create_instance(
602    ///         &self,
603    ///         p_create_info: &vk::InstanceCreateInfo,
604    ///         layer_instance_link: &VkLayerInstanceLink,
605    ///         p_allocator: Option<&vk::AllocationCallbacks>,
606    ///         p_instance: *mut vk::Instance,
607    ///     ) -> LayerResult<ash::prelude::VkResult<()>> {
608    ///         // Clone the input enabled extension names as a Vec.
609    ///         let mut enabled_extensions = if p_create_info.enabled_extension_count == 0 {
610    ///             vec![]
611    ///         } else {
612    ///             unsafe {
613    ///                 std::slice::from_raw_parts(
614    ///                     p_create_info.pp_enabled_extension_names,
615    ///                     p_create_info.enabled_extension_count as usize,
616    ///                 )
617    ///             }
618    ///             .to_vec()
619    ///         };
620    ///         // Push the VK_KHR_surface extension name only if it doesn't exist.
621    ///         if enabled_extensions
622    ///             .iter()
623    ///             .find(|extension_name| {
624    ///                 (unsafe { CStr::from_ptr(**extension_name) })
625    ///                     == ash::extensions::khr::Win32Surface::name()
626    ///             })
627    ///             .is_none()
628    ///         {
629    ///             enabled_extensions.push(ash::extensions::khr::Win32Surface::name().as_ptr());
630    ///         }
631    ///         // Create a new VkInstanceCreateInfo with the new extensions. The passed in
632    ///         // VkInstanceCreateInfo is const, so we have to create another VkInstanceCreateInfo
633    ///         // to mutate the field we need to avoid possible undefined behavior in Rust.
634    ///         let mut create_info = p_create_info.clone();
635    ///         create_info.enabled_extension_count = enabled_extensions.len() as u32;
636    ///         create_info.pp_enabled_extension_names = enabled_extensions.as_ptr();
637    ///         // Convert p_allocator to a raw pointer that can be directly passed to
638    ///         // vkCreateInstance.
639    ///         let p_allocator = p_allocator
640    ///             .map(|allocator| allocator as *const _)
641    ///             .unwrap_or_else(null);
642    ///         // Find the vkCreateInstance entry of the next layer.
643    ///         let create_instance = unsafe {
644    ///             (layer_instance_link.pfnNextGetInstanceProcAddr)(
645    ///                 vk::Instance::null(),
646    ///                 c"vkCreateInstance".as_ptr(),
647    ///             )
648    ///         };
649    ///         let create_instance: vk::PFN_vkCreateInstance = match create_instance {
650    ///             Some(fp) => unsafe { std::mem::transmute(fp) },
651    ///             None => return LayerResult::Handled(Err(vk::Result::ERROR_INITIALIZATION_FAILED)),
652    ///         };
653    ///         // Call into the vkCreateInstance of the next layer with the original p_instance
654    ///         // pointer.
655    ///         LayerResult::Handled(
656    ///             unsafe { create_instance(&create_info, p_allocator, p_instance) }.result(),
657    ///         )
658    ///     }
659    /// }
660    /// ```
661    fn create_instance(
662        &self,
663        _p_create_info: &vk::InstanceCreateInfo,
664        _layer_instance_link: &VkLayerInstanceLink,
665        _p_allocator: Option<&vk::AllocationCallbacks>,
666        _p_instance: *mut vk::Instance,
667    ) -> LayerResult<ash::prelude::VkResult<()>> {
668        LayerResult::Unhandled
669    }
670}
671
672/// A trait for the layer implementation to provide metadata of [`GlobalHooks`] for the layer
673/// framework.
674///
675/// This trait serves as the container of the [`GlobalHooks`] type and provides the list of
676/// intercepted
677/// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
678/// for the layer framework. This trait and [`GlobalHooks`] can be implemented by the same type.
679///
680/// This trait can also be automatically implemented with the help of the
681/// [`auto_globalhooksinfo_impl`][`crate::auto_globalhooksinfo_impl`] attribute macro.
682///
683/// # Examples
684///
685/// A layer that needs to intercept the `vkCreateInstance` function.
686///
687/// ```
688/// # use ash::vk;
689/// # use vulkan_layer::{
690/// #     GlobalHooks, GlobalHooksInfo, LayerResult, LayerVulkanCommand as VulkanCommand,
691/// #     VkLayerInstanceLink,
692/// # };
693/// #
694/// struct MyLayerGlobalHooks;
695///
696/// impl GlobalHooks for MyLayerGlobalHooks {
697///     fn create_instance(
698///         &self,
699///         _p_create_info: &vk::InstanceCreateInfo,
700///         _layer_instance_link: &VkLayerInstanceLink,
701///         _p_allocator: Option<&vk::AllocationCallbacks>,
702///         _p_instance: *mut vk::Instance,
703///     ) -> LayerResult<ash::prelude::VkResult<()>> {
704///         LayerResult::Unhandled
705///     }
706/// }
707///
708/// impl GlobalHooksInfo for MyLayerGlobalHooks {
709///     type HooksType = Self;
710///     type HooksRefType<'a> = &'a Self;
711///
712///     fn hooked_commands() -> &'static [VulkanCommand] {
713///         &[VulkanCommand::CreateInstance]
714///     }
715///
716///     fn hooks(&self) -> Self::HooksRefType<'_> {
717///         self
718///     }
719/// }
720/// ```
721pub trait GlobalHooksInfo: Send + Sync {
722    /// The underlying [`GlobalHooks`] type that implements the core logic to intercept
723    /// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.).
724    ///
725    /// If a type implements both this trait and the [`GlobalHooks`] trait simultaneously,
726    /// [`GlobalHooksInfo::HooksType`] can be set to `Self`.
727    type HooksType: GlobalHooks;
728
729    /// A type that can be dereferencing to [`GlobalHooksInfo::HooksType`]. Usually just
730    /// `&GlobalHooksInfo::HooksType`.
731    ///
732    /// This extra associated type allows the layer implementation to use a smart pointer like
733    /// [`Arc`][std::sync::Arc] or [`MutexGuard`][std::sync::MutexGuard] to hold the reference.
734    ///
735    /// # Examples
736    ///
737    /// A layer implementation that returns a [`Arc`][std::sync::Arc].
738    /// ```
739    /// # use std::sync::Arc;
740    /// # use vulkan_layer::{GlobalHooks, GlobalHooksInfo, LayerVulkanCommand as VulkanCommand};
741    /// #
742    /// # struct MyLayerGlobalHooks;
743    /// #
744    /// # impl GlobalHooks for MyLayerGlobalHooks {}
745    /// #
746    /// struct MyLayerGlobalHooksInfo(Arc<MyLayerGlobalHooks>);
747    ///
748    /// impl GlobalHooksInfo for MyLayerGlobalHooksInfo {
749    ///     type HooksType = MyLayerGlobalHooks;
750    ///     type HooksRefType<'a> = Arc<MyLayerGlobalHooks>;
751    /// #
752    /// #     fn hooked_commands() -> &'static [VulkanCommand] {
753    /// #         &[]
754    /// #     }
755    ///
756    ///     // Other required methods omitted.
757    ///
758    ///     fn hooks(&self) -> Self::HooksRefType<'_> {
759    ///         Arc::clone(&self.0)
760    ///     }
761    /// }
762    /// ```
763    type HooksRefType<'a>: Deref<Target = Self::HooksType> + 'a
764    where
765        Self: 'a;
766
767    /// Returns a slice of
768    /// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
769    /// that the layer implementation needs to intercept.
770    ///
771    /// Avoid returning commands other than
772    /// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.).
773    /// Otherwise, those commands may or may not be intercepted.
774    ///
775    /// Because this function is called in [`Global::default`] to initialize the singleton
776    /// [`Global`] instance, implementations must not call into [`Global::default`] directly or
777    /// indirectly including:
778    /// * [`Layer::global_instance`]: this function will call [`Global::default`] under certain
779    ///   circumstances.
780    /// * Any [`Global`] static methods: These functions may call into [`Layer::global_instance`] to
781    ///   obtain the global singleton.
782    /// * Any Vulkan APIs exposed by the Vulkan loader: These functions will almost certainly
783    ///   trigger the layer initialization logic.
784    fn hooked_commands() -> &'static [VulkanCommand];
785
786    /// Returns the reference of the [`GlobalHooksInfo::HooksType`].
787    ///
788    /// The layer framework uses the returned value to call into the layer implementation of
789    /// intercepted commands.
790    fn hooks(&self) -> Self::HooksRefType<'_>;
791}
792
793/// A wrapper for
794/// [`VkExtensionProperties`](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkExtensionProperties.html).
795/// Structure specifying an extension properties.
796///
797/// Can convert to the `ash::vk::ExtensionProperties` C binding with [`From`] or [`Into`].
798///
799/// # Examples
800///
801/// ```
802/// use ash::vk;
803/// use std::ffi::CStr;
804/// use vulkan_layer::{Extension, ExtensionProperties};
805///
806/// let extension_properties = ExtensionProperties {
807///     name: Extension::KHRSurface,
808///     spec_version: 25,
809/// };
810/// let extension_properties_ffi: vk::ExtensionProperties = extension_properties.clone().into();
811/// assert_eq!(
812///     unsafe { CStr::from_ptr(extension_properties_ffi.extension_name.as_ptr()) },
813///     ash::vk::KhrSurfaceFn::name()
814/// );
815/// assert_eq!(extension_properties_ffi.spec_version, 25);
816/// ```
817#[derive(Clone)]
818pub struct ExtensionProperties {
819    /// The name of the extension.
820    pub name: Extension,
821
822    /// `spec_version` is the version of this extension. It is an integer, incremented with
823    /// backward compatible changes.
824    pub spec_version: u32,
825}
826
827impl From<ExtensionProperties> for vk::ExtensionProperties {
828    fn from(ExtensionProperties { name, spec_version }: ExtensionProperties) -> Self {
829        let name: &str = name.into();
830        let name = CString::new(name).unwrap();
831        let byte_len = name.as_bytes().len();
832        let name = unsafe { std::slice::from_raw_parts(name.as_ptr(), byte_len) };
833        let mut res = Self::builder()
834            .extension_name([0; vk::MAX_EXTENSION_NAME_SIZE])
835            .spec_version(spec_version)
836            .build();
837        res.extension_name[0..byte_len].copy_from_slice(name);
838        res
839    }
840}
841
842/// A Rust bindings of the
843/// [layer manifest file](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#layer-manifest-file-format).
844///
845/// The return type of [`Layer::manifest`]. This type is marked as `non_exhaustive`, because it will
846/// evolve with the [layer manifest schema](https://github.com/LunarG/VulkanTools/blob/v1.3.261/vkconfig_core/layers/layers_schema.json).
847/// The user should initialize the value of this type in a way that will still compile if new fields
848/// are added. [`LayerManifest::default`] will initialize all fields to empty.
849/// ```
850/// # use ash::vk;
851/// # use vulkan_layer::LayerManifest;
852/// let mut manifest = LayerManifest::default();
853/// manifest.name = "VK_LAYER_VENDOR_rust_example";
854/// manifest.spec_version = vk::API_VERSION_1_1;
855/// ```
856// TODO: add the capability to serialize to json.
857#[non_exhaustive]
858#[derive(Default, Clone)]
859pub struct LayerManifest {
860    /// The string used to uniquely identify this layer to applications.
861    ///
862    /// The layer name should follow the
863    /// [layer name convention](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#layer-conventions-and-rules)
864    /// according to
865    /// [`LLP_LAYER_3`](<https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#requirements-of-well-behaved-layers:~:text=Conventions%20and%20Rules-,LLP_LAYER_3,-Any%20new%20layer>).
866    pub name: &'static str,
867
868    /// The `VkLayerProperties::specVersion` field. The `"api_version"` JSON node.
869    ///
870    /// The major.minor.patch version number of the Vulkan API that the layer supports encoded as
871    /// described in
872    /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#extendingvulkan-coreversions-versionnumbers>.
873    /// It does not require the application to make use of that API version. It simply is an
874    /// indication that the layer can support Vulkan API instance and device functions up to and
875    /// including that API version.
876    pub spec_version: u32,
877
878    /// The version of the layer implemented.
879    ///
880    /// It is an integer, increasing with backward compatible changes. If the layer itself has any
881    /// major changes, this number should change so the loader and/or application can identify it
882    /// properly.
883    pub implementation_version: u32,
884
885    /// A high-level description of the layer and its intended use which provides additional
886    /// details that can be used by the application to identify the layer.
887    ///
888    /// The description shouldn't be longer than `VK_MAX_DESCRIPTION_SIZE` bytes after encoded as a
889    /// null-terminated UTF-8 string. Otherwise, the layer framework will panic at runtime.
890    pub description: &'static str,
891
892    /// Contains the list of device extension names supported by this layer.
893    ///
894    /// An array of one or more elements is required if any device extensions are supported by a
895    /// layer; otherwise the array should be empty. In `vkCreateDevice`, the layer framework
896    /// removes the extensions mentioned here from the
897    /// `VkDeviceCreateInfo::ppEnabledExtensionNames` list.
898    pub device_extensions: &'static [ExtensionProperties],
899}
900
901/// The [`Layer`] trait provides all layer implementation information for the layer framework.
902///
903/// The type that implements [`Layer`] provides the following functionalities:
904/// * Global initialization for the layer.
905/// * The factory of [`LayerManifest`], [`InstanceInfo`], and [`DeviceInfo`].
906/// * The container of [`GlobalHooksInfo`].
907/// * Providing the storage of [`Global`].
908/// * Overriding the intercepted Vulkan commands at runtime.
909///
910/// # Initialization
911///
912/// The layer implementation can rely on `Layer::default` to perform the global initialization. e.g.
913/// initialize the logger.
914///
915/// The layer framework guarantees that `Layer::default` is only called once when
916/// [`Global::default`] is called, and won't be called anywhere else. The layer framework doesn't
917/// call [`Global::default`] to initialize. Instead, [`Layer::global_instance`] is called instead on
918/// every Vulkan function entry when the global singleton is needed, and the layer implementation is
919/// expected to lazily create the static [`Global`] singleton with [`Global::default`] in
920/// [`Layer::global_instance`]. Therefore, if the layer implementation can guarantee that
921/// [`Global::default`] is called once during the lifetime of the whole process, it is also
922/// guaranteed that `Layer::default` is called once during the lifetime of the whole process. Note
923/// that it may be difficult to realize such guarantee, because the Vulkan loader my load and unload
924/// the layer library multiple times, and the application my load and unload the Vulkan loader
925/// multiple times.
926///
927/// `Layer::default` must not call into any [`Global`] methods and any Vulkan commands exported by
928/// the Vulkan loader to avoid an endless recursion.
929///
930/// # Global clean up
931///
932/// It is recommended that the implementor of the [`Layer`] trait should have a no-op drop if all
933/// `VkInstance` intercepted by the layer is destroyed. If so, [`Global`] has a no-op drop when all
934/// `VkInstance` is destroyed. If the [`Layer`] implementor is always
935/// trivially-destructible[^trivial_dtor], it's great.
936///
937/// It is guaranteed that when `Global::drop` is called, `Layer::drop` is called exactly once.
938/// However, as a dynamic link library that may be loaded and unloaded to/from the process multiple
939/// times, there is no easy way to guarantee that `Global::drop` is called on every unload. In
940/// additoon, in Rust, static items do not call drop at the end of the program[^static_drop]. We
941/// can't expect drop to be called on dynamic link library unload as well. Therefore, we should
942/// avoid using `Layer::drop` to do clean-up to avoid resource leak.
943///
944/// If it is really necessary to store some not trivially-destructible types(note that all Rust
945/// [`std::collections`] are not trivially-destructible) in side the type that implements [`Layer`],
946/// the following techniques may be helpful.
947///
948/// One way to test if a type `T` leaks heap memory is to run Miri tests with [`std::mem::forget`].
949///
950/// ```
951/// #[derive(Default)]
952/// struct TriviallyDestructible;
953///
954/// #[derive(Default)]
955/// struct NotTriviallyDestructible(Box<u32>);
956///
957/// // This passes the Miri test, so TriviallyDestructible won't leak heap memory if drop is not
958/// // called.
959/// {
960///     let x: TriviallyDestructible = Default::default();
961///     std::mem::forget(x);
962/// }
963///
964/// // This fails the Miri test, so NotTriviallyDestructible will leak heap memory if drop is not
965/// // called.
966/// {
967///     let x: NotTriviallyDestructible = Default::default();
968///     std::mem::forget(x);
969/// }
970/// ```
971///
972/// The drop of Rust [`std::collections`] is not no-op even if the collection is empty, so avoid
973/// using them directly in the type that implements [`Layer`].
974///
975/// The drop of [`std::sync::Weak`] is not no-op even if all strong references to the underlying
976/// object don't exist, so we should avoid using it to construct a type that needs a no-op drop.
977///
978/// The drop of [`Option::None`] is no-op even if the underlying `T` is not trivially destructible,
979/// and the drop of [`Mutex`][std::sync::Mutex] is no-op if the drop of the wrapped `T` is no-op.
980/// Therefore `Mutex<Option<T>>` is a good basic block to build a type that needs a no-op drop.
981///
982/// # Examples
983///
984/// A simple layer that prints "Hello from the Rust Vulkan layer!" to `stdout` on every
985/// `vkCreateDevice`.
986/// ```
987/// use ash::{self, vk};
988/// use once_cell::sync::Lazy;
989/// use std::sync::Arc;
990/// use vulkan_layer::{
991///     Global, Layer, LayerManifest, StubDeviceInfo, StubGlobalHooks, StubInstanceInfo,
992/// };
993///
994/// #[derive(Default)]
995/// struct MyLayer(StubGlobalHooks);
996///
997/// impl Layer for MyLayer {
998///     type GlobalHooksInfo = StubGlobalHooks;
999///     type InstanceInfo = StubInstanceInfo;
1000///     type DeviceInfo = StubDeviceInfo;
1001///     type InstanceInfoContainer = StubInstanceInfo;
1002///     type DeviceInfoContainer = StubDeviceInfo;
1003///
1004///     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1005///         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
1006///         &*GLOBAL
1007///     }
1008///
1009///     fn manifest() -> LayerManifest {
1010///         let mut manifest = LayerManifest::default();
1011///         manifest.name = "VK_LAYER_VENDOR_rust_example";
1012///         manifest.spec_version = vk::API_VERSION_1_1;
1013///         manifest
1014///     }
1015///
1016///     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1017///         &self.0
1018///     }
1019///
1020///     fn create_instance_info(
1021///         &self,
1022///         _: &vk::InstanceCreateInfo,
1023///         _: Option<&vk::AllocationCallbacks>,
1024///         _: Arc<ash::Instance>,
1025///         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1026///     ) -> Self::InstanceInfoContainer {
1027///         Default::default()
1028///     }
1029///
1030///     fn create_device_info(
1031///         &self,
1032///         _: vk::PhysicalDevice,
1033///         _: &vk::DeviceCreateInfo,
1034///         _: Option<&vk::AllocationCallbacks>,
1035///         _: Arc<ash::Device>,
1036///         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1037///     ) -> Self::DeviceInfoContainer {
1038///         println!("Hello from the Rust Vulkan layer!");
1039///         Default::default()
1040///     }
1041/// }
1042/// ```
1043///
1044/// A layer that initializes the logging infrastructure with `env_logger`.
1045/// ```
1046/// use ash::{self, vk};
1047/// use log::info;
1048/// use once_cell::sync::Lazy;
1049/// use std::sync::Arc;
1050/// use vulkan_layer::{
1051///     Global, Layer, LayerManifest, StubDeviceInfo, StubGlobalHooks, StubInstanceInfo,
1052/// };
1053///
1054/// struct MyLayer(StubGlobalHooks);
1055///
1056/// impl Default for MyLayer {
1057///     fn default() -> Self {
1058///         env_logger::init();
1059///         Self(Default::default())
1060///     }
1061/// }
1062///
1063/// impl Layer for MyLayer {
1064///     type GlobalHooksInfo = StubGlobalHooks;
1065///     type InstanceInfo = StubInstanceInfo;
1066///     type DeviceInfo = StubDeviceInfo;
1067///     type InstanceInfoContainer = StubInstanceInfo;
1068///     type DeviceInfoContainer = StubDeviceInfo;
1069///
1070///     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1071///         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
1072///         &*GLOBAL
1073///     }
1074///
1075///     fn manifest() -> LayerManifest {
1076///         let mut manifest = LayerManifest::default();
1077///         manifest.name = "VK_LAYER_VENDOR_rust_example";
1078///         manifest.spec_version = vk::API_VERSION_1_1;
1079///         manifest
1080///     }
1081///
1082///     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1083///         &self.0
1084///     }
1085///
1086///     fn create_instance_info(
1087///         &self,
1088///         _: &vk::InstanceCreateInfo,
1089///         _: Option<&vk::AllocationCallbacks>,
1090///         _: Arc<ash::Instance>,
1091///         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1092///     ) -> Self::InstanceInfoContainer {
1093///         Default::default()
1094///     }
1095///
1096///     fn create_device_info(
1097///         &self,
1098///         _: vk::PhysicalDevice,
1099///         _: &vk::DeviceCreateInfo,
1100///         _: Option<&vk::AllocationCallbacks>,
1101///         _: Arc<ash::Device>,
1102///         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1103///     ) -> Self::DeviceInfoContainer {
1104///         info!("Hello from the Rust Vulkan layer!");
1105///         Default::default()
1106///     }
1107/// }
1108/// ```
1109///
1110/// [^trivial_dtor]: This term is borrowed from
1111/// [C++](<https://en.cppreference.com/w/cpp/language/destructor#:~:text=since%20C%2B%2B20)-,Trivial%20destructor,-The%20destructor%20for>):
1112/// if the type itself doesn't have a destructor and the types of all fields are trivially
1113/// destructible, this type is trivially destructible. Rust has [`std::mem::needs_drop`], but this
1114/// function doesn't have a strong guarantee.
1115///
1116/// [^static_drop]: <https://doc.rust-lang.org/reference/items/static-items.html#:~:text=Static%20items%20do%20not%20call%20drop%20at%20the%20end%20of%20the%20program.>
1117pub trait Layer: Sync + Default + 'static {
1118    /// The type that provides information about interception of
1119    /// [global commands](<https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance>).
1120    ///
1121    /// If the layer implementation is not interested in intercepting any
1122    /// [global commands](<https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance>),
1123    /// [`StubGlobalHooks`][crate::StubGlobalHooks] can be used.
1124    type GlobalHooksInfo: GlobalHooksInfo;
1125
1126    /// The type that provides information about interception of
1127    /// [Vulkan instance functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#instance-functions),
1128    /// [global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
1129    /// not included.
1130    ///
1131    /// If the layer implementation is not interested in intercepting any
1132    /// [Vulkan instance functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#instance-functions)
1133    /// ([global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
1134    /// not included), [`StubInstanceInfo`][crate::StubInstanceInfo] can be used.
1135    type InstanceInfo: InstanceInfo;
1136
1137    /// The type that provides information about interception of
1138    /// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions).
1139    ///
1140    /// If the layer implementation is not interested in intercepting any
1141    /// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions),
1142    /// [`StubDeviceInfo`][crate::StubDeviceInfo] can be used.
1143    type DeviceInfo: DeviceInfo;
1144
1145    /// The type that holds a [`Layer::InstanceInfo`] type. Usually just `Self::InstanceInfo`.
1146    ///
1147    /// This extra associated type allows the layer to use a smart pointer like [`Arc`] or [`Box`]
1148    /// to hold the [`Layer::InstanceInfo`].
1149    ///
1150    /// # Examples
1151    ///
1152    /// Use [`Arc`] to hold the [`Layer::InstanceInfo`].
1153    /// ```
1154    /// use ash::vk;
1155    /// use once_cell::sync::Lazy;
1156    /// use std::sync::Arc;
1157    /// use vulkan_layer::{
1158    ///     Global, Layer, LayerManifest, StubDeviceInfo, StubGlobalHooks, StubInstanceInfo,
1159    /// };
1160    ///
1161    /// #[derive(Default)]
1162    /// struct MyLayer(StubGlobalHooks);
1163    ///
1164    /// impl Layer for MyLayer {
1165    ///     type InstanceInfo = StubInstanceInfo;
1166    ///     type InstanceInfoContainer = Arc<StubInstanceInfo>;
1167    ///
1168    ///     fn create_instance_info(
1169    ///         &self,
1170    ///         _: &vk::InstanceCreateInfo,
1171    ///         _: Option<&vk::AllocationCallbacks>,
1172    ///         _: Arc<ash::Instance>,
1173    ///         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1174    ///     ) -> Self::InstanceInfoContainer {
1175    ///         Arc::default()
1176    ///     }
1177    ///
1178    ///     // Unrelated required items are omitted.
1179    /// #     type GlobalHooksInfo = StubGlobalHooks;
1180    /// #     type DeviceInfo = StubDeviceInfo;
1181    /// #     type DeviceInfoContainer = StubDeviceInfo;
1182    /// #
1183    /// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1184    /// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
1185    /// #         &*GLOBAL
1186    /// #     }
1187    /// #
1188    /// #     fn manifest() -> LayerManifest {
1189    /// #         Default::default()
1190    /// #     }
1191    /// #
1192    /// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1193    /// #         &self.0
1194    /// #     }
1195    /// #
1196    /// #     fn create_device_info(
1197    /// #         &self,
1198    /// #         _: vk::PhysicalDevice,
1199    /// #         _: &vk::DeviceCreateInfo,
1200    /// #         _: Option<&vk::AllocationCallbacks>,
1201    /// #         _: Arc<ash::Device>,
1202    /// #         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1203    /// #     ) -> Self::DeviceInfoContainer {
1204    /// #         Default::default()
1205    /// #     }
1206    /// }
1207    /// ```
1208    type InstanceInfoContainer: Borrow<Self::InstanceInfo> + Sync + Send;
1209
1210    /// The type that holds a [`Layer::DeviceInfo`] type. Usually just `Self::DeviceInfo`.
1211    ///
1212    /// This extra associated type allows the layer to use a smart pointer like [`Arc`] to hold the
1213    /// [`Layer::DeviceInfo`].
1214    ///
1215    /// # Examples
1216    ///
1217    /// Use [`Arc`] to hold the [`Layer::DeviceInfo`].
1218    /// ```
1219    /// use ash::vk;
1220    /// use once_cell::sync::Lazy;
1221    /// use std::sync::Arc;
1222    /// use vulkan_layer::{
1223    ///     Global, Layer, LayerManifest, StubDeviceInfo, StubGlobalHooks, StubInstanceInfo,
1224    /// };
1225    ///
1226    /// #[derive(Default)]
1227    /// struct MyLayer(StubGlobalHooks);
1228    ///
1229    /// impl Layer for MyLayer {
1230    ///     type DeviceInfo = StubDeviceInfo;
1231    ///     type DeviceInfoContainer = Arc<StubDeviceInfo>;
1232    ///
1233    ///     fn create_device_info(
1234    ///         &self,
1235    ///         _: vk::PhysicalDevice,
1236    ///         _: &vk::DeviceCreateInfo,
1237    ///         _: Option<&vk::AllocationCallbacks>,
1238    ///         _: Arc<ash::Device>,
1239    ///         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1240    ///     ) -> Self::DeviceInfoContainer {
1241    ///         Arc::default()
1242    ///     }
1243    ///
1244    ///     // Unrelated required items are omitted.
1245    /// #     type GlobalHooksInfo = StubGlobalHooks;
1246    /// #     type InstanceInfo = StubInstanceInfo;
1247    /// #     type InstanceInfoContainer = StubInstanceInfo;
1248    /// #
1249    /// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1250    /// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
1251    /// #         &*GLOBAL
1252    /// #     }
1253    /// #
1254    /// #     fn manifest() -> LayerManifest {
1255    /// #         Default::default()
1256    /// #     }
1257    /// #
1258    /// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1259    /// #         &self.0
1260    /// #     }
1261    /// #
1262    /// #     fn create_instance_info(
1263    /// #         &self,
1264    /// #         _: &vk::InstanceCreateInfo,
1265    /// #         _: Option<&vk::AllocationCallbacks>,
1266    /// #         _: Arc<ash::Instance>,
1267    /// #         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1268    /// #     ) -> Self::InstanceInfoContainer {
1269    /// #         Default::default()
1270    /// #     }
1271    /// }
1272    /// ```
1273    type DeviceInfoContainer: Borrow<Self::DeviceInfo> + Sync + Send;
1274
1275    /// Returns the
1276    /// [layer manifest](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#layer-manifest-file-format)
1277    /// to the layer framework.
1278    ///
1279    /// Implementors should always return the same value during the lifetime of the process, and
1280    /// must match the manifest json file with the layer. Implementors should avoid calling into any
1281    /// [`Global`] methods because this function can be called to implement Vulkan introspection
1282    /// queries before any `VkInstance` is created.
1283    ///
1284    /// The layer framework will use this value to:
1285    /// * Implement [Vulkan introspection queries](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderLayerInterface.md#requirements-of-well-behaved-layers:~:text=Parent-,Introspection%20Query,-%22api_version%22),
1286    ///   including `vkEnumerateInstanceLayerProperties`, `vkEnumerateDeviceLayerProperties`,
1287    ///   `vkEnumerateInstanceExtensionProperties` and `vkEnumerateDeviceExtensionProperties`.
1288    /// * Remove the layer device extensions from `VkDeviceCreateInfo::ppEnabledExtensionNames` in
1289    ///   `vkCreateDevice` if present.
1290    fn manifest() -> LayerManifest;
1291
1292    /// Provide the reference to the global singleton of [`Global`].
1293    ///
1294    /// Implementors must always return the reference pointing to the same [`Global`] object.
1295    /// Implementors can use [`LazyLock`][std::sync::LazyLock], [`OnceLock`][std::sync::OnceLock],
1296    /// or `Lazy` from the `once_cell` crate to implement. Implementors should use
1297    /// [`Global::default`] to create the [`Global`] object. More information on initialization can
1298    /// be found [here][Layer#initialization].
1299    ///
1300    /// # Examples
1301    ///
1302    /// Use `Lazy` provided by the `once_cell` crate to implement.
1303    /// ```
1304    /// use ash::{self, vk};
1305    /// use once_cell::sync::Lazy;
1306    /// use std::sync::Arc;
1307    /// use vulkan_layer::{
1308    ///     Global, Layer, LayerManifest, StubDeviceInfo, StubGlobalHooks, StubInstanceInfo,
1309    /// };
1310    ///
1311    /// #[derive(Default)]
1312    /// struct MyLayer(StubGlobalHooks);
1313    ///
1314    /// impl Layer for MyLayer {
1315    ///     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1316    ///         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
1317    ///         &*GLOBAL
1318    ///     }
1319    ///
1320    ///     // Unrelated required items are omitted.
1321    /// #     type GlobalHooksInfo = StubGlobalHooks;
1322    /// #     type InstanceInfo = StubInstanceInfo;
1323    /// #     type DeviceInfo = StubDeviceInfo;
1324    /// #     type InstanceInfoContainer = StubInstanceInfo;
1325    /// #     type DeviceInfoContainer = StubDeviceInfo;
1326    /// #
1327    /// #     fn manifest() -> LayerManifest {
1328    /// #         let mut manifest = LayerManifest::default();
1329    /// #         manifest.name = "VK_LAYER_VENDOR_rust_example";
1330    /// #         manifest.spec_version = vk::API_VERSION_1_1;
1331    /// #         manifest
1332    /// #     }
1333    /// #
1334    /// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1335    /// #         &self.0
1336    /// #     }
1337    /// #
1338    /// #     fn create_instance_info(
1339    /// #         &self,
1340    /// #         _: &vk::InstanceCreateInfo,
1341    /// #         _: Option<&vk::AllocationCallbacks>,
1342    /// #         _: Arc<ash::Instance>,
1343    /// #         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1344    /// #     ) -> Self::InstanceInfoContainer {
1345    /// #         Default::default()
1346    /// #     }
1347    /// #
1348    /// #     fn create_device_info(
1349    /// #         &self,
1350    /// #         _: vk::PhysicalDevice,
1351    /// #         _: &vk::DeviceCreateInfo,
1352    /// #         _: Option<&vk::AllocationCallbacks>,
1353    /// #         _: Arc<ash::Device>,
1354    /// #         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1355    /// #     ) -> Self::DeviceInfoContainer {
1356    /// #         println!("Hello from the Rust Vulkan layer!");
1357    /// #         Default::default()
1358    /// #     }
1359    /// }
1360    /// ```
1361    fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static;
1362
1363    /// Returns a reference of the underlying [`GlobalHooksInfo`] object.
1364    fn global_hooks_info(&self) -> &Self::GlobalHooksInfo;
1365
1366    /// Returns a reference of the underlying [`GlobalHooks`] object.
1367    ///
1368    /// The layer framework relies on this function to obtain [`GlobalHooks`], and implementors
1369    /// should avoid overriding this method.
1370    fn global_hooks(&self) -> <Self::GlobalHooksInfo as GlobalHooksInfo>::HooksRefType<'_> {
1371        self.global_hooks_info().hooks()
1372    }
1373
1374    /// The factory method for the [`InstanceInfo`] type.
1375    ///
1376    /// This function is called by the layer framework in `vkCreateInstance`, after the
1377    /// `vkCreateInstance` of the next layer returns with success.
1378    ///
1379    /// # Arguments
1380    ///
1381    /// * `create_info` is a pointer to a VkInstanceCreateInfo structure controlling creation of the
1382    ///   instance. The [`VkLayerInstanceLink`] linked list in the `pNext` chain is already advanced
1383    ///   by the layer framework. This is the original `VkInstanceCreateInfo` passed in by the
1384    ///   application or the previous layer(except the advanced [`VkLayerInstanceLink`] linked
1385    ///   list), even if the layer implementation passes a different `VkInstanceCreateInfo` to the
1386    ///   next layer in [`GlobalHooks::create_instance`].
1387    /// * `allocator` controls host memory allocation as described in the [Memory Allocation](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#memory-allocation)
1388    ///   chapter of the Vulkan spec.
1389    /// * `instance` contains the loaded instance dispatch table of the next layer. The layer
1390    ///   implementation can just clone this [`Arc`] if it is needed to keep the instance dispatch
1391    ///   table.
1392    /// * `next_get_instance_proc_addr` is the `vkGetInstanceProcAddr` function pointer of the next
1393    ///   layer obtained from the [`VkLayerInstanceLink`] linked list.
1394    fn create_instance_info(
1395        &self,
1396        create_info: &vk::InstanceCreateInfo,
1397        allocator: Option<&vk::AllocationCallbacks>,
1398        instance: Arc<ash::Instance>,
1399        next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1400    ) -> Self::InstanceInfoContainer;
1401
1402    /// The factory method for the [`DeviceInfo`] type.
1403    ///
1404    /// This function is called by the layer framework in `vkCreateDevice`, after the
1405    /// `vkCreateDevice` of the next layer returns with success.
1406    ///
1407    /// # Arguments
1408    /// * `physical_device` is one of the device handles returned from a call to
1409    ///   `vkEnumeratePhysicalDevices` that is passed to `vkCreateDevice` by the application or the
1410    ///   previous layer.
1411    /// * `create_info` is a pointer to a `VkDeviceCreateInfo` structure containing information
1412    ///   about how to create the device. The [`VkLayerDeviceLink`][crate::VkLayerDeviceLink] linked
1413    ///   list in the `pNext` chain is already advanced by the layer framework. This is the original
1414    ///   `VkDeviceCreateInfo` passed in by the application or the previous layer(except the
1415    ///   advanced [`VkLayerDeviceLink`][crate::VkLayerDeviceLink] linked list), even if the layer
1416    ///   implementation passes a different `VkDeviceCreateInfo` to the next layer in
1417    ///   [`InstanceHooks::create_device`].
1418    /// * `allocator` controls host memory allocation as described in the [Memory Allocation](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#memory-allocation)
1419    ///   chapter of the Vulkan spec.
1420    /// * `device` contains the loaded device dispatch table of the next layer. The layer
1421    ///   implementation can just clone this [`Arc`] if it is needed to keep the device dispatch
1422    ///   table.
1423    /// * `next_get_device_proc_addr` is the `vkGetDeviceProcAddr` function pointer of the next
1424    ///   layer obtained from the [`VkLayerDeviceLink`][crate::VkLayerDeviceLink] linked list.
1425    fn create_device_info(
1426        &self,
1427        physical_device: vk::PhysicalDevice,
1428        create_info: &vk::DeviceCreateInfo,
1429        allocator: Option<&vk::AllocationCallbacks>,
1430        device: Arc<ash::Device>,
1431        next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1432    ) -> Self::DeviceInfoContainer;
1433
1434    /// Returns an iterator of
1435    /// [Vulkan instance functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#instance-functions)
1436    /// ([global commands](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkGetInstanceProcAddr.html#:~:text=The%20global%20commands%20are%3A%20vkEnumerateInstanceVersion%2C%20vkEnumerateInstanceExtensionProperties%2C%20vkEnumerateInstanceLayerProperties%2C%20and%20vkCreateInstance.)
1437    /// not included) that the layer implementation needs to intercept.
1438    ///
1439    /// This function allows the layer implementation to decide the commands to intercept
1440    /// dynamically after the `VkInstance` is created. By default it just returns all commands
1441    /// returned by [`InstanceInfo::hooked_commands`].
1442    ///
1443    /// # Arguments
1444    /// * `_instance_info` is the relevant instance.
1445    ///
1446    /// # Examples
1447    ///
1448    /// A layer that intercepts `vkDestroySurfaceKHR` only if the `VK_KHR_win32_surface` extension
1449    /// is enabled.
1450    /// ```
1451    /// use ash::vk;
1452    /// use once_cell::sync::Lazy;
1453    /// use std::{ffi::CStr, sync::Arc};
1454    /// use vulkan_layer::{
1455    ///     Global, InstanceHooks, InstanceInfo, Layer, LayerManifest, LayerResult,
1456    ///     LayerVulkanCommand as VulkanCommand, StubDeviceInfo, StubGlobalHooks,
1457    /// };
1458    ///
1459    /// struct MyLayerInstanceInfo {
1460    ///     is_win32_surface_enabled: bool,
1461    /// }
1462    ///
1463    /// impl InstanceHooks for MyLayerInstanceInfo {
1464    ///     fn destroy_surface_khr(
1465    ///         &self,
1466    ///         _surface: vk::SurfaceKHR,
1467    ///         _p_allocator: Option<&vk::AllocationCallbacks>,
1468    ///     ) -> LayerResult<()> {
1469    ///         LayerResult::Unhandled
1470    ///     }
1471    /// }
1472    ///
1473    /// impl InstanceInfo for MyLayerInstanceInfo {
1474    ///     type HooksType = Self;
1475    ///     type HooksRefType<'a> = &'a Self;
1476    ///
1477    ///     fn hooked_commands() -> &'static [VulkanCommand] {
1478    ///         &[VulkanCommand::DestroySurfaceKhr]
1479    ///     }
1480    ///
1481    ///     fn hooks(&self) -> Self::HooksRefType<'_> {
1482    ///         self
1483    ///     }
1484    /// }
1485    ///
1486    /// #[derive(Default)]
1487    /// struct MyLayer(StubGlobalHooks);
1488    ///
1489    /// impl Layer for MyLayer {
1490    ///     // ...
1491    /// #     type GlobalHooksInfo = StubGlobalHooks;
1492    ///     type InstanceInfo = MyLayerInstanceInfo;
1493    /// #     type DeviceInfo = StubDeviceInfo;
1494    ///     type InstanceInfoContainer = MyLayerInstanceInfo;
1495    /// #     type DeviceInfoContainer = StubDeviceInfo;
1496    /// #
1497    /// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1498    /// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
1499    /// #         &*GLOBAL
1500    /// #     }
1501    /// #
1502    /// #     fn manifest() -> LayerManifest {
1503    /// #         Default::default()
1504    /// #     }
1505    /// #
1506    /// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1507    /// #         &self.0
1508    /// #     }
1509    ///
1510    ///     fn create_instance_info(
1511    ///         &self,
1512    ///         create_info: &vk::InstanceCreateInfo,
1513    ///         _: Option<&vk::AllocationCallbacks>,
1514    ///         _: Arc<ash::Instance>,
1515    ///         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1516    ///     ) -> Self::InstanceInfoContainer {
1517    ///         let enabled_extensions = if create_info.enabled_extension_count > 0 {
1518    ///             unsafe {
1519    ///                 std::slice::from_raw_parts(
1520    ///                     create_info.pp_enabled_extension_names,
1521    ///                     create_info.enabled_extension_count as usize,
1522    ///                 )
1523    ///             }
1524    ///         } else {
1525    ///             &[]
1526    ///         };
1527    ///         let is_win32_surface_enabled = enabled_extensions
1528    ///             .iter()
1529    ///             .find(|extension_name| {
1530    ///                 (unsafe { CStr::from_ptr(**extension_name) })
1531    ///                     == ash::extensions::khr::Win32Surface::name()
1532    ///             })
1533    ///             .is_some();
1534    ///         MyLayerInstanceInfo {
1535    ///             is_win32_surface_enabled,
1536    ///         }
1537    ///     }
1538    ///
1539    ///     fn hooked_instance_commands(
1540    ///         &self,
1541    ///         instance_info: &Self::InstanceInfo,
1542    ///     ) -> Box<dyn Iterator<Item = VulkanCommand>> {
1543    ///         let should_hook_destroy_surface = instance_info.is_win32_surface_enabled;
1544    ///         Box::new(
1545    ///             Self::InstanceInfo::hooked_commands()
1546    ///                 .iter()
1547    ///                 .cloned()
1548    ///                 .filter(move |command| match command {
1549    ///                     VulkanCommand::DestroySurfaceKhr => should_hook_destroy_surface,
1550    ///                     _ => true,
1551    ///                 }),
1552    ///         )
1553    ///     }
1554    /// #
1555    /// #     fn create_device_info(
1556    /// #         &self,
1557    /// #         _: vk::PhysicalDevice,
1558    /// #         _: &vk::DeviceCreateInfo,
1559    /// #         _: Option<&vk::AllocationCallbacks>,
1560    /// #         _: Arc<ash::Device>,
1561    /// #         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1562    /// #     ) -> Self::DeviceInfoContainer {
1563    /// #         Default::default()
1564    /// #     }
1565    /// }
1566    /// ```
1567    fn hooked_instance_commands(
1568        &self,
1569        _instance_info: &Self::InstanceInfo,
1570    ) -> Box<dyn Iterator<Item = VulkanCommand>> {
1571        Box::new(Self::InstanceInfo::hooked_commands().iter().cloned())
1572    }
1573
1574    /// Returns an iterator of
1575    /// [Vulkan device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions)
1576    /// that the layer implementation needs to intercept.
1577    ///
1578    /// This function allows the layer implementation to decide the commands to intercept
1579    /// dynamically after the `VkInstance` or `VkDevice` is created. By default it just returns all
1580    /// commands returned by [`DeviceInfo::hooked_commands`].
1581    ///
1582    /// Arguments
1583    /// * `_instance_info` is the relevant instance.
1584    /// * `_device_info` is an optional relevant device. If `_device_info` is [`None`], the layer
1585    ///   framework is querying all possible intercepted
1586    ///   [device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions)
1587    ///   to implement `vkGetInstanceProcAddr` with the `pName` parameter referring to a
1588    ///   [device functions](https://github.com/KhronosGroup/Vulkan-Loader/blob/v1.3.261/docs/LoaderInterfaceArchitecture.md#device-functions),
1589    ///   i.e. implementations must guarantee that the returned commands with a [`None`]
1590    ///   `_device_info` is the superset of all possible `_device_info`. Otherwise, the application
1591    ///   that just uses the function pointers returned by `vkGetInstanceProcAddr` may skip the
1592    ///   current layer.
1593    ///
1594    /// # Examples
1595    ///
1596    /// A layer that intercepts the `vkCreateImage` only if the ASTC LDR feature is enabled.
1597    /// ```
1598    /// use ash::{self, prelude::VkResult, vk};
1599    /// use once_cell::sync::Lazy;
1600    /// use std::sync::Arc;
1601    /// use vulkan_layer::{
1602    ///     DeviceHooks, DeviceInfo, Global, Layer, LayerManifest, LayerResult,
1603    ///     LayerVulkanCommand as VulkanCommand, StubGlobalHooks, StubInstanceInfo,
1604    ///     VulkanBaseInStructChain,
1605    /// };
1606    ///
1607    /// struct MyLayerDeviceInfo {
1608    ///     is_astc_enabled: bool,
1609    /// }
1610    ///
1611    /// impl DeviceHooks for MyLayerDeviceInfo {
1612    ///     fn create_image(
1613    ///         &self,
1614    ///         create_info: &vk::ImageCreateInfo,
1615    ///         _p_allocator: Option<&vk::AllocationCallbacks>,
1616    ///     ) -> LayerResult<VkResult<vk::Image>> {
1617    ///         if create_info.format == vk::Format::ASTC_4X4_UNORM_BLOCK {
1618    ///             println!("ASTC 4x4 UNORM image created.");
1619    ///         }
1620    ///         LayerResult::Unhandled
1621    ///     }
1622    /// }
1623    ///
1624    /// impl DeviceInfo for MyLayerDeviceInfo {
1625    ///     type HooksType = Self;
1626    ///     type HooksRefType<'a> = &'a Self;
1627    ///
1628    ///     fn hooked_commands() -> &'static [VulkanCommand] {
1629    ///         &[VulkanCommand::CreateImage]
1630    ///     }
1631    ///
1632    ///     fn hooks(&self) -> Self::HooksRefType<'_> {
1633    ///         self
1634    ///     }
1635    /// }
1636    ///
1637    /// #[derive(Default)]
1638    /// struct MyLayer(StubGlobalHooks);
1639    ///
1640    /// impl Layer for MyLayer {
1641    ///     // ...
1642    /// #     type GlobalHooksInfo = StubGlobalHooks;
1643    /// #     type InstanceInfo = StubInstanceInfo;
1644    ///     type DeviceInfo = MyLayerDeviceInfo;
1645    /// #     type InstanceInfoContainer = StubInstanceInfo;
1646    ///     type DeviceInfoContainer = MyLayerDeviceInfo;
1647    /// #
1648    /// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
1649    /// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
1650    /// #         &*GLOBAL
1651    /// #     }
1652    /// #
1653    /// #     fn manifest() -> LayerManifest {
1654    /// #         Default::default()
1655    /// #     }
1656    /// #
1657    /// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
1658    /// #         &self.0
1659    /// #     }
1660    /// #
1661    /// #     fn create_instance_info(
1662    /// #         &self,
1663    /// #         _: &vk::InstanceCreateInfo,
1664    /// #         _: Option<&vk::AllocationCallbacks>,
1665    /// #         _: Arc<ash::Instance>,
1666    /// #         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
1667    /// #     ) -> Self::InstanceInfoContainer {
1668    /// #         Default::default()
1669    /// #     }
1670    /// #
1671    ///     fn create_device_info(
1672    ///         &self,
1673    ///         _: vk::PhysicalDevice,
1674    ///         create_info: &vk::DeviceCreateInfo,
1675    ///         _: Option<&vk::AllocationCallbacks>,
1676    ///         _: Arc<ash::Device>,
1677    ///         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
1678    ///     ) -> Self::DeviceInfoContainer {
1679    ///         let mut p_next_chain: VulkanBaseInStructChain =
1680    ///             unsafe { (create_info.p_next as *const vk::BaseInStructure).as_ref() }.into();
1681    ///         let is_astc_enabled = p_next_chain
1682    ///             .find_map(|p_next| {
1683    ///                 let p_next = p_next as *const vk::BaseInStructure;
1684    ///                 unsafe {
1685    ///                     ash::match_in_struct!(match p_next {
1686    ///                         features2 @ vk::PhysicalDeviceFeatures2 => {
1687    ///                             Some(&features2.features)
1688    ///                         }
1689    ///                         _ => {
1690    ///                             None
1691    ///                         }
1692    ///                     })
1693    ///                 }
1694    ///             })
1695    ///             .or_else(|| unsafe { create_info.p_enabled_features.as_ref() })
1696    ///             .map(|features| features.texture_compression_astc_ldr == vk::TRUE)
1697    ///             .unwrap_or(false);
1698    ///         MyLayerDeviceInfo { is_astc_enabled }
1699    ///     }
1700    ///
1701    ///     fn hooked_device_commands(
1702    ///         &self,
1703    ///         _instance_info: &Self::InstanceInfo,
1704    ///         device_info: Option<&Self::DeviceInfo>,
1705    ///     ) -> Box<dyn Iterator<Item = VulkanCommand>> {
1706    ///         let should_hook_create_image = device_info
1707    ///             .map(|device_info| device_info.is_astc_enabled)
1708    ///             // Always hook the vkCreateImage function in the function pointers returned by
1709    ///             // vkGetInstanceProcAddr: we don't know if the to-be-created VkDevice will be
1710    ///             // created with the ASTC feature enabled.
1711    ///             .unwrap_or(true);
1712    ///         Box::new(
1713    ///             Self::DeviceInfo::hooked_commands()
1714    ///                 .iter()
1715    ///                 .cloned()
1716    ///                 .filter(move |command| match command {
1717    ///                     VulkanCommand::CreateImage => should_hook_create_image,
1718    ///                     _ => true,
1719    ///                 }),
1720    ///         )
1721    ///     }
1722    /// }
1723    /// ```
1724    fn hooked_device_commands(
1725        &self,
1726        _instance_info: &Self::InstanceInfo,
1727        _device_info: Option<&Self::DeviceInfo>,
1728    ) -> Box<dyn Iterator<Item = VulkanCommand>> {
1729        Box::new(Self::DeviceInfo::hooked_commands().iter().cloned())
1730    }
1731}
1732
1733#[cfg(test)]
1734mod tests {
1735    use super::*;
1736
1737    #[test]
1738    fn vulkan_command_try_from_should_end_up_error_with_unknown_commands() {
1739        let unknown_command = "vkTestCommandTEST";
1740        let err = VulkanCommand::try_from(unknown_command).unwrap_err();
1741        assert!(err.to_string().contains(unknown_command));
1742    }
1743}