Trait DeviceInfo

Source
pub trait DeviceInfo: Send + Sync {
    type HooksType: DeviceHooks;
    type HooksRefType<'a>: Deref<Target = Self::HooksType> + 'a
       where Self: 'a;

    // Required methods
    fn hooked_commands() -> &'static [VulkanCommand];
    fn hooks(&self) -> Self::HooksRefType<'_>;
}
Expand description

A trait for the layer implementation to provide metadata of DeviceHooks for the layer framework.

This trait serves as the container of the DeviceHooks type and provides the list of intercepted Vulkan device functions for the layer framework. This trait and DeviceHooks can be implemented by the same type.

This trait can also be automatically implemented with the help of the auto_deviceinfo_impl attribute macro.

§Examples

A layer that needs to intercept the vkCreateImage function.

struct MyLayerDeviceInfo;

impl DeviceHooks for MyLayerDeviceInfo {
    fn create_image(
        &self,
        _p_create_info: &vk::ImageCreateInfo,
        _p_allocator: Option<&vk::AllocationCallbacks>,
    ) -> LayerResult<VkResult<vk::Image>> {
        LayerResult::Unhandled
    }
}

impl DeviceInfo for MyLayerDeviceInfo {
    type HooksType = Self;
    type HooksRefType<'a> = &'a Self;

    fn hooked_commands() -> &'static [VulkanCommand] {
        &[VulkanCommand::CreateImage]
    }

    fn hooks(&self) -> Self::HooksRefType<'_> {
        self
    }
}

Required Associated Types§

Source

type HooksType: DeviceHooks

The underlying DeviceHooks type that implements the core logic to intercept Vulkan device functions.

If a type implements both this trait and the DeviceHooks trait simultaneously, DeviceInfo::HooksType can be set to Self.

Source

type HooksRefType<'a>: Deref<Target = Self::HooksType> + 'a where Self: 'a

A type that can be dereferencing to DeviceInfo::HooksType. Usually just &DeviceInfo::HooksType.

This extra associated type allows the layer implementation to use a smart pointer like Arc or MutexGuard to hold the reference.

§Examples

A layer implementation that returns a Arc.

struct MyLayerDeviceInfo(Arc<MyLayerDeviceHooks>);

impl DeviceInfo for MyLayerDeviceInfo {
    type HooksType = MyLayerDeviceHooks;
    type HooksRefType<'a> = Arc<MyLayerDeviceHooks>;

    // Other required methods omitted.

    fn hooks(&self) -> Self::HooksRefType<'_> {
        Arc::clone(&self.0)
    }
}

Required Methods§

Source

fn hooked_commands() -> &'static [VulkanCommand]

Returns a slice of Vulkan device functions that the layer implementation needs to intercept.

This function should normally return the methods implemented by the associated DeviceHooks type. If the layer implementation needs to decide the functions to intercept dynamically at runtime, use the Layer::hooked_device_commands method to override the list of intercepted device functions.

Avoid returning commands other than Vulkan device functions. Otherwise, those commands may or may not be intercepted.

For Vulkan commands that have multiple names, e.g. vkCreateSamplerYcbcrConversion and vkCreateSamplerYcbcrConversionKHR, only the shortest name should be used(VulkanCommand::CreateSamplerYcbcrConversion in this example). The layer framework automatically wires both entries to the layer implementation.

§Examples

A layer that intercepts the vkCreateImage only if the ASTC LDR feature is enabled.

use ash::{self, prelude::VkResult, vk};
use once_cell::sync::Lazy;
use std::sync::Arc;
use vulkan_layer::{
    DeviceHooks, DeviceInfo, Global, Layer, LayerManifest, LayerResult,
    LayerVulkanCommand as VulkanCommand, StubGlobalHooks, StubInstanceInfo,
    VulkanBaseInStructChain,
};

struct MyLayerDeviceInfo {
    is_astc_enabled: bool,
}

impl DeviceHooks for MyLayerDeviceInfo {
    fn create_image(
        &self,
        create_info: &vk::ImageCreateInfo,
        _p_allocator: Option<&vk::AllocationCallbacks>,
    ) -> LayerResult<VkResult<vk::Image>> {
        if create_info.format == vk::Format::ASTC_4X4_UNORM_BLOCK {
            println!("ASTC 4x4 UNORM image created.");
        }
        LayerResult::Unhandled
    }
}

impl DeviceInfo for MyLayerDeviceInfo {
    type HooksType = Self;
    type HooksRefType<'a> = &'a Self;

    fn hooked_commands() -> &'static [VulkanCommand] {
        &[VulkanCommand::CreateImage]
    }

    fn hooks(&self) -> Self::HooksRefType<'_> {
        self
    }
}

#[derive(Default)]
struct MyLayer(StubGlobalHooks);

impl Layer for MyLayer {
    // ...
    type DeviceInfo = MyLayerDeviceInfo;
    type DeviceInfoContainer = MyLayerDeviceInfo;
    fn create_device_info(
        &self,
        _: vk::PhysicalDevice,
        create_info: &vk::DeviceCreateInfo,
        _: Option<&vk::AllocationCallbacks>,
        _: Arc<ash::Device>,
        _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
    ) -> Self::DeviceInfoContainer {
        let mut p_next_chain: VulkanBaseInStructChain =
            unsafe { (create_info.p_next as *const vk::BaseInStructure).as_ref() }.into();
        let is_astc_enabled = p_next_chain
            .find_map(|p_next| {
                let p_next = p_next as *const vk::BaseInStructure;
                unsafe {
                    ash::match_in_struct!(match p_next {
                        features2 @ vk::PhysicalDeviceFeatures2 => {
                            Some(&features2.features)
                        }
                        _ => {
                            None
                        }
                    })
                }
            })
            .or_else(|| unsafe { create_info.p_enabled_features.as_ref() })
            .map(|features| features.texture_compression_astc_ldr == vk::TRUE)
            .unwrap_or(false);
        MyLayerDeviceInfo { is_astc_enabled }
    }

    fn hooked_device_commands(
        &self,
        _instance_info: &Self::InstanceInfo,
        device_info: Option<&Self::DeviceInfo>,
    ) -> Box<dyn Iterator<Item = VulkanCommand>> {
        let should_hook_create_image = device_info
            .map(|device_info| device_info.is_astc_enabled)
            // Always hook the vkCreateImage function in the function pointers returned by
            // vkGetInstanceProcAddr: we don't know if the to-be-created VkDevice will be
            // created with the ASTC feature enabled.
            .unwrap_or(true);
        Box::new(
            Self::DeviceInfo::hooked_commands()
                .iter()
                .cloned()
                .filter(move |command| match command {
                    VulkanCommand::CreateImage => should_hook_create_image,
                    _ => true,
                }),
        )
    }
}
Source

fn hooks(&self) -> Self::HooksRefType<'_>

Returns the reference of the DeviceInfo::HooksType.

The layer framework uses the returned value to call into the layer implementation of intercepted commands.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl DeviceInfo for StubDeviceInfo

Source§

impl<T: TestLayerMock> DeviceInfo for MockDeviceInfo<T>

Available on crate feature _test only.
Source§

type HooksType = MockDeviceHooks

Source§

type HooksRefType<'a> = MutexGuard<'a, MockDeviceHooks>