vulkan_layer_macros/
lib.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#![warn(missing_docs)]
16
17//! Macros for `vulkan-layer`.
18
19use proc_macro::TokenStream;
20use proc_macro2::TokenStream as TokenStream2;
21use quote::quote;
22use syn::{parse_macro_input, ItemImpl, Type};
23
24mod details;
25mod dummy;
26
27/// Derive the implementation of the `vulkan_layer::GlobalHooksInfo` trait from the implementation
28/// of the `vulkan_layer::GlobalHooks` trait.
29///
30/// This attribute macro should be used over an implementation item of the
31/// `vulkan_layer::GlobalHooks` trait, and will implement the `vulkan_layer::GlobalHooksInfo` trait
32/// for the type:
33/// * `GlobalHooksInfo::hooked_commands` returns a list of the overridden methods that appear in the
34///   implementation item.
35/// * `GlobalHooksInfo::HooksType` and `GlobalHooksInfo::HooksRefType` are defined as `Self` and
36///   `&Self`.
37/// * `GlobalHooksInfo::hooks` returns `self`.
38///
39/// # Examples
40///
41/// ```
42/// use ash::vk;
43/// use vulkan_layer::{
44///     auto_globalhooksinfo_impl, GlobalHooks, GlobalHooksInfo, LayerResult, LayerVulkanCommand,
45///     VkLayerInstanceLink,
46/// };
47///
48/// #[derive(Default)]
49/// struct MyGlobalHooks;
50///
51/// #[auto_globalhooksinfo_impl]
52/// impl GlobalHooks for MyGlobalHooks {
53///     fn create_instance(
54///         &self,
55///         _p_create_info: &vk::InstanceCreateInfo,
56///         _layer_instance_link: &VkLayerInstanceLink,
57///         _p_allocator: Option<&vk::AllocationCallbacks>,
58///         _p_instance: *mut vk::Instance,
59///     ) -> LayerResult<ash::prelude::VkResult<()>> {
60///         LayerResult::Unhandled
61///     }
62/// }
63///
64/// let my_global_hooks: MyGlobalHooks = Default::default();
65/// assert!(std::ptr::eq(&my_global_hooks, my_global_hooks.hooks()));
66/// assert_eq!(
67///     MyGlobalHooks::hooked_commands(),
68///     [LayerVulkanCommand::CreateInstance]
69/// );
70/// ```
71#[proc_macro_attribute]
72pub fn auto_globalhooksinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream {
73    let original_item: TokenStream2 = item.clone().into();
74    let input = parse_macro_input!(item as ItemImpl);
75    let target_trait = quote!(::vulkan_layer::GlobalHooksInfo);
76    let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| {
77        let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait);
78        let compile_error = e.to_compile_error();
79        quote! {
80            #dummy
81            #compile_error
82        }
83    });
84    quote! {
85        #original_item
86        #to_append
87    }
88    .into()
89}
90
91/// Derive the implementation of the `vulkan_layer::InstanceInfo` trait from the implementation of
92/// the `vulkan_layer::InstanceHooks`.
93///
94/// This attribute macro should be used over an implementation item of the
95/// `vulkan_layer::InstanceHooks` trait, and will implement the `vulkan_layer::InstanceInfo` trait
96/// for the type:
97/// * `InstanceInfo::hooked_commands` returns a list of the overridden methods that appear in the
98///   implementation item.
99/// * `InstanceInfo::HooksType` and `InstanceInfo::HooksRefType` are defined as `Self` and `&Self`.
100/// * `InstanceInfo::hooks` returns `self`.
101///
102/// # Examples
103///
104/// ```
105/// use ash::vk;
106/// use std::mem::MaybeUninit;
107/// use vulkan_layer::{
108///     auto_instanceinfo_impl, InstanceHooks, InstanceInfo, LayerResult, LayerVulkanCommand,
109/// };
110///
111/// #[derive(Default)]
112/// struct MyInstanceHooks;
113///
114/// #[auto_instanceinfo_impl]
115/// impl InstanceHooks for MyInstanceHooks {
116///     fn get_physical_device_features(
117///         &self,
118///         _physical_device: vk::PhysicalDevice,
119///         _p_features: &mut MaybeUninit<vk::PhysicalDeviceFeatures>,
120///     ) -> LayerResult<()> {
121///         LayerResult::Unhandled
122///     }
123/// }
124///
125/// let my_instance_hooks: MyInstanceHooks = Default::default();
126/// assert!(std::ptr::eq(my_instance_hooks.hooks(), &my_instance_hooks));
127/// assert_eq!(
128///     MyInstanceHooks::hooked_commands(),
129///     [LayerVulkanCommand::GetPhysicalDeviceFeatures]
130/// );
131/// ```
132#[proc_macro_attribute]
133pub fn auto_instanceinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream {
134    let original_item: TokenStream2 = item.clone().into();
135    let input = parse_macro_input!(item as ItemImpl);
136    let target_trait = quote!(::vulkan_layer::InstanceInfo);
137    let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| {
138        let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait);
139        let compile_error = e.to_compile_error();
140        quote! {
141            #dummy
142            #compile_error
143        }
144    });
145    quote! {
146        #original_item
147        #to_append
148    }
149    .into()
150}
151
152/// Derive the implementation of the `vulkan_layer::DeviceInfo` trait from the implementation of the
153/// `vulkan_layer::DeviceHooks` trait.
154///
155/// This attribute macro should be used over an implementation item of the
156/// `vulkan_layer::DeviceHooks` trait, and will implement the `vulkan_layer::DeviceInfo` trait for
157/// the type:
158/// * `DeviceInfo::hooked_commands` returns a list of the overridden methods that appear in the
159///   implementation item.
160/// * `DeviceInfo::HooksType` and `DeviceInfo::HooksRefType` are defined as `Self` and `&Self`.
161/// * `DeviceInfo::hooks` returns `self`.
162///
163/// # Examples
164///
165/// ```
166/// use ash::vk;
167/// use vulkan_layer::{
168///     auto_deviceinfo_impl, DeviceHooks, DeviceInfo, LayerResult, LayerVulkanCommand,
169/// };
170///
171/// #[derive(Default)]
172/// struct MyDeviceHooks;
173///
174/// #[auto_deviceinfo_impl]
175/// impl DeviceHooks for MyDeviceHooks {
176///     fn create_image(
177///         &self,
178///         _p_create_info: &vk::ImageCreateInfo,
179///         _p_allocator: Option<&vk::AllocationCallbacks>,
180///     ) -> LayerResult<ash::prelude::VkResult<vk::Image>> {
181///         LayerResult::Unhandled
182///     }
183/// }
184///
185/// let my_device_hooks: MyDeviceHooks = Default::default();
186/// assert!(std::ptr::eq(my_device_hooks.hooks(), &my_device_hooks));
187/// assert_eq!(
188///     MyDeviceHooks::hooked_commands(),
189///     [LayerVulkanCommand::CreateImage]
190/// );
191/// ```
192#[proc_macro_attribute]
193pub fn auto_deviceinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream {
194    let original_item: TokenStream2 = item.clone().into();
195    let input = parse_macro_input!(item as ItemImpl);
196    let target_trait = quote!(::vulkan_layer::DeviceInfo);
197    let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| {
198        let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait);
199        let compile_error = e.to_compile_error();
200        quote! {
201            #dummy
202            #compile_error
203        }
204    });
205    quote! {
206        #original_item
207        #to_append
208    }
209    .into()
210}
211
212/// Declare the required introspection queries for Android given an instantiated
213/// `vulkan_layer::Global` type.
214///
215/// All functions are defined without name mangling, so that they are exported as C symbols in the
216/// generated dynamic library. This is recommended by
217/// [the Vulkan loader doc](https://github.com/KhronosGroup/Vulkan-Loader/blob/280997da523951c4016f4ca6af66d58a31e36ab3/docs/LoaderLayerInterface.md#layer-manifest-file-usage:~:text=These%20introspection%20functions%20are%20not%20used%20by%20the%20Khronos%20loader%20but%20should%20be%20present%20in%20layers%20to%20maintain%20consistency.%20The%20specific%20%22introspection%22%20functions%20are%20called%20out%20in%20the%20Layer%20Manifest%20File%20Format%20table):
218///
219/// > These introspection functions are not used by the Khronos loader but should be present in
220/// > layers to maintain consistency. The specific "introspection" functions are called out in the
221/// > Layer Manifest File Format table.
222///
223/// According to the
224/// [the Vulkan loader doc](https://github.com/KhronosGroup/Vulkan-Loader/blob/280997da523951c4016f4ca6af66d58a31e36ab3/docs/LoaderLayerInterface.md#layer-manifest-file-format), introspection queries include:
225/// * `vkEnumerateInstanceLayerProperties`
226/// * `vkEnumerateInstanceExtensionProperties`
227/// * `vkEnumerateDeviceLayerProperties`
228/// * `vkEnumerateDeviceExtensionProperties`
229/// * `vkGetInstanceProcAddr`
230/// * `vkGetDeviceProcAddr`
231/// # Examples
232///
233/// ```
234/// # use std::sync::Arc;
235/// # use vulkan_layer::{StubGlobalHooks, StubInstanceInfo, StubDeviceInfo, Layer, Global, declare_introspection_queries, LayerManifest};
236/// # use once_cell::sync::Lazy;
237/// # use ash::{vk, self};
238/// #
239/// #[derive(Default)]
240/// struct MyLayer(StubGlobalHooks);
241///
242/// impl Layer for MyLayer {
243///     // ...
244/// #     type GlobalHooksInfo = StubGlobalHooks;
245/// #     type InstanceInfo = StubInstanceInfo;
246/// #     type DeviceInfo = StubDeviceInfo;
247/// #     type InstanceInfoContainer = StubInstanceInfo;
248/// #     type DeviceInfoContainer = StubDeviceInfo;
249/// #     
250/// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
251/// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
252/// #         &*GLOBAL
253/// #     }
254/// #
255/// #     fn manifest() -> LayerManifest {
256/// #         Default::default()
257/// #     }
258/// #
259/// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
260/// #         &self.0
261/// #     }
262/// #
263/// #     fn create_instance_info(
264/// #         &self,
265/// #         _: &vk::InstanceCreateInfo,
266/// #         _: Option<&vk::AllocationCallbacks>,
267/// #         _: Arc<ash::Instance>,
268/// #         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
269/// #     ) -> Self::InstanceInfoContainer {
270/// #         Default::default()
271/// #     }
272/// #
273/// #     fn create_device_info(
274/// #         &self,
275/// #         _: vk::PhysicalDevice,
276/// #         _: &vk::DeviceCreateInfo,
277/// #         _: Option<&vk::AllocationCallbacks>,
278/// #         _: Arc<ash::Device>,
279/// #         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
280/// #     ) -> Self::DeviceInfoContainer {
281/// #         Default::default()
282/// #     }
283/// }
284///
285/// type MyGlobal = Global::<MyLayer>;
286/// declare_introspection_queries!(MyGlobal);
287/// # let _: vk::PFN_vkEnumerateInstanceLayerProperties = vkEnumerateInstanceLayerProperties;
288/// # let _: vk::PFN_vkEnumerateInstanceExtensionProperties = vkEnumerateInstanceExtensionProperties;
289/// # let _: vk::PFN_vkEnumerateDeviceLayerProperties = vkEnumerateDeviceLayerProperties;
290/// # let _: vk::PFN_vkEnumerateDeviceExtensionProperties = vkEnumerateDeviceExtensionProperties;
291/// # let _: vk::PFN_vkGetInstanceProcAddr = vkGetInstanceProcAddr;
292/// # let _: vk::PFN_vkGetDeviceProcAddr = vkGetDeviceProcAddr;
293/// ```
294#[proc_macro]
295pub fn declare_introspection_queries(item: TokenStream) -> TokenStream {
296    let global_type = parse_macro_input!(item as Type);
297    details::declare_introspection_queries_impl(&global_type)
298        .unwrap_or_else(|e| e.to_compile_error())
299        .into()
300}