unity-native-plugin 0.9.0

Unity Native Plugin API for Rust
Documentation
use crate::bitflag;
use crate::graphics;
use crate::interface::UnityInterface;
use crate::windows::ComPtr;
use unity_native_plugin_sys::*;

pub type ResourceState = UnityGraphicsD3D12ResourceState;
pub type PhysicalVideoMemoryControlValues = UnityGraphicsD3D12PhysicalVideoMemoryControlValues;

#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum GraphicsQueueAccess {
    DontCare = UnityD3D12GraphicsQueueAccess_kUnityD3D12GraphicsQueueAccess_DontCare,
    Allow = UnityD3D12GraphicsQueueAccess_kUnityD3D12GraphicsQueueAccess_Allow,
}

#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum EventConfigFlagBit {
    EnsurePreviousFrameSubmission =
        UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_EnsurePreviousFrameSubmission,
    FlushCommandBuffers =
        UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_FlushCommandBuffers,
    SyncWorkerThreads = UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_SyncWorkerThreads,
    ModifiesCommandBuffersState =
        UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState,
}

bitflag!(EventConfigFlagBits, EventConfigFlagBit, u32);

#[derive(Copy, Clone)]
pub struct PluginEventConfig {
    pub graphics_queue_access: GraphicsQueueAccess,
    pub flags: EventConfigFlagBits,
    pub ensure_active_render_texture_is_bound: bool,
}

pub trait UnityGraphicsD3D12v2Interface {
    unsafe fn device(&self) -> ComPtr;
    unsafe fn frame_fence(&self) -> ComPtr;
    fn next_frame_fence_value(&self) -> u64;
}

pub use UnityGraphicsD3D12v2Interface as IUnityGraphicsD3D12v2;

macro_rules! impl_d3d12_v2 {
    ($intf:ty) => {
        impl UnityGraphicsD3D12v2Interface for $intf {
            unsafe fn device(&self) -> ComPtr {
                unsafe { self.interface().GetDevice.expect("GetDevice")() as ComPtr }
            }

            unsafe fn frame_fence(&self) -> ComPtr {
                unsafe { self.interface().GetFrameFence.expect("GetFrameFence")() as ComPtr }
            }

            fn next_frame_fence_value(&self) -> u64 {
                unsafe {
                    self.interface()
                        .GetNextFrameFenceValue
                        .expect("GetNextFrameFenceValue")() as u64
                }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12v2,
    unity_native_plugin_sys::IUnityGraphicsD3D12v2,
    0xEC39D2F18446C745_u64,
    0xB1A2626641D6B11F_u64
);
impl_d3d12_v2!(UnityGraphicsD3D12v2);

pub trait UnityGraphicsD3D12Interface {
    unsafe fn device(&self) -> ComPtr;
    unsafe fn command_queue(&self) -> ComPtr;
    unsafe fn frame_fence(&self) -> ComPtr;
    fn next_frame_fence_value(&self) -> u64;
    fn resource_state(&self, resource: ComPtr) -> Option<i32>;
    fn set_resource_state(&self, resource: ComPtr, state: i32);
}

pub use UnityGraphicsD3D12Interface as IUnityGraphicsD3D12;

macro_rules! impl_d3d12 {
    ($intf:ty) => {
        impl UnityGraphicsD3D12Interface for $intf {
            unsafe fn device(&self) -> ComPtr {
                unsafe { self.interface().GetDevice.expect("GetDevice")() as ComPtr }
            }

            unsafe fn command_queue(&self) -> ComPtr {
                unsafe { self.interface().GetCommandQueue.expect("GetCommandQueue")() as ComPtr }
            }

            unsafe fn frame_fence(&self) -> ComPtr {
                unsafe { self.interface().GetFrameFence.expect("GetFrameFence")() as ComPtr }
            }

            fn next_frame_fence_value(&self) -> u64 {
                unsafe {
                    self.interface()
                        .GetNextFrameFenceValue
                        .expect("GetNextFrameFenceValue")() as u64
                }
            }

            fn resource_state(&self, resource: ComPtr) -> Option<i32> {
                unsafe {
                    let mut ret: D3D12_RESOURCE_STATES = D3D12_RESOURCE_STATES::default();
                    if self.interface().GetResourceState.expect("GetResourceState")(
                        resource as *mut ID3D12Resource,
                        &mut ret as *mut D3D12_RESOURCE_STATES,
                    ) {
                        Some(ret)
                    } else {
                        None
                    }
                }
            }

            fn set_resource_state(&self, resource: ComPtr, state: i32) {
                unsafe {
                    self.interface().SetResourceState.expect("SetResourceState")(
                        resource as *mut ID3D12Resource,
                        state,
                    )
                }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12,
    unity_native_plugin_sys::IUnityGraphicsD3D12,
    0xEF4CEC88A45F4C4C_u64,
    0xBD295B6F2A38D9DE_u64
);
impl_d3d12!(UnityGraphicsD3D12);

pub trait UnityGraphicsD3D12v3Interface: UnityGraphicsD3D12v2Interface {
    fn set_physical_video_memory_control_values(&self, mem_info: &PhysicalVideoMemoryControlValues);
}

pub use UnityGraphicsD3D12v3Interface as IUnityGraphicsD3D12v3;

macro_rules! impl_d3d12_v3 {
    ($intf:ty) => {
        impl_d3d12_v2!($intf);

        impl UnityGraphicsD3D12v3Interface for $intf {
            fn set_physical_video_memory_control_values(
                &self,
                mem_info: &PhysicalVideoMemoryControlValues,
            ) {
                unsafe {
                    self.interface()
                        .SetPhysicalVideoMemoryControlValues
                        .expect("SetPhysicalVideoMemoryControlValues")(
                        mem_info as *const UnityGraphicsD3D12PhysicalVideoMemoryControlValues,
                    )
                }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12v3,
    unity_native_plugin_sys::IUnityGraphicsD3D12v3,
    0x57C3FAFE59E5E843_u64,
    0xBF4F5998474BB600_u64
);
impl_d3d12_v3!(UnityGraphicsD3D12v3);

pub trait UnityGraphicsD3D12v4Interface: UnityGraphicsD3D12v3Interface {
    unsafe fn command_queue(&self) -> ComPtr;
}

pub use UnityGraphicsD3D12v4Interface as IUnityGraphicsD3D12v4;

macro_rules! impl_d3d12_v4 {
    ($intf:ty) => {
        impl_d3d12_v3!($intf);

        impl UnityGraphicsD3D12v4Interface for $intf {
            unsafe fn command_queue(&self) -> ComPtr {
                unsafe { self.interface().GetCommandQueue.expect("GetCommandQueue")() as ComPtr }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12v4,
    unity_native_plugin_sys::IUnityGraphicsD3D12v4,
    0x498FFCC13EC94006_u64,
    0xB18F8B0FF67778C8_u64
);
impl_d3d12_v4!(UnityGraphicsD3D12v4);

pub trait UnityGraphicsD3D12v5Interface: UnityGraphicsD3D12v4Interface {
    unsafe fn texture_from_render_buffer(&self, rb: graphics::RenderBuffer) -> ComPtr;
}

pub use UnityGraphicsD3D12v5Interface as IUnityGraphicsD3D12v5;

macro_rules! impl_d3d12_v5 {
    ($intf:ty) => {
        impl_d3d12_v4!($intf);

        impl UnityGraphicsD3D12v5Interface for $intf {
            unsafe fn texture_from_render_buffer(&self, rb: graphics::RenderBuffer) -> ComPtr {
                unsafe {
                    self.interface()
                        .TextureFromRenderBuffer
                        .expect("TextureFromRenderBuffer")(rb) as ComPtr
                }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12v5,
    unity_native_plugin_sys::IUnityGraphicsD3D12v5,
    0xF5C8D8A37D37BC42_u64,
    0xB02DFE93B5064A27_u64
);
impl_d3d12_v5!(UnityGraphicsD3D12v5);

pub trait UnityGraphicsD3D12v6Interface: UnityGraphicsD3D12v5Interface {
    fn configure_event(&self, event_id: i32, plugin_event_config: &PluginEventConfig);
    unsafe fn command_recording_state(&self) -> Option<ComPtr>;
}

pub use UnityGraphicsD3D12v6Interface as IUnityGraphicsD3D12v6;

macro_rules! impl_d3d12_v6 {
    ($intf:ty) => {
        impl_d3d12_v5!($intf);

        impl UnityGraphicsD3D12v6Interface for $intf {
            fn configure_event(&self, event_id: i32, plugin_event_config: &PluginEventConfig) {
                unsafe {
                    let cfg = UnityD3D12PluginEventConfig {
                        graphicsQueueAccess: plugin_event_config.graphics_queue_access
                            as UnityD3D12GraphicsQueueAccess,
                        flags: plugin_event_config.flags.flag,
                        ensureActiveRenderTextureIsBound: plugin_event_config
                            .ensure_active_render_texture_is_bound,
                    };
                    self.interface().ConfigureEvent.expect("ConfigureEvent")(event_id, &cfg)
                }
            }

            unsafe fn command_recording_state(&self) -> Option<ComPtr> {
                unsafe {
                    let mut state: UnityGraphicsD3D12RecordingState = std::mem::zeroed();
                    if self
                        .interface()
                        .CommandRecordingState
                        .expect("CommandRecordingState")(&mut state)
                    {
                        Some(state.commandList as ComPtr)
                    } else {
                        None
                    }
                }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12v6,
    unity_native_plugin_sys::IUnityGraphicsD3D12v6,
    0xA396DCE58CAC4D78_u64,
    0xAFDD9B281F20B840_u64
);
impl_d3d12_v6!(UnityGraphicsD3D12v6);

pub trait UnityGraphicsD3D12v7Interface: UnityGraphicsD3D12v6Interface {
    unsafe fn swap_chain(&self) -> ComPtr;
    fn sync_interval(&self) -> u32;
    fn present_flags(&self) -> u32;
}

pub use UnityGraphicsD3D12v7Interface as IUnityGraphicsD3D12v7;

macro_rules! impl_d3d12_v7 {
    ($intf:ty) => {
        impl_d3d12_v6!($intf);

        impl UnityGraphicsD3D12v7Interface for $intf {
            unsafe fn swap_chain(&self) -> ComPtr {
                unsafe { self.interface().GetSwapChain.expect("GetSwapChain")() as ComPtr }
            }

            fn sync_interval(&self) -> u32 {
                unsafe { self.interface().GetSyncInterval.expect("GetSyncInterval")() }
            }

            fn present_flags(&self) -> u32 {
                unsafe { self.interface().GetPresentFlags.expect("GetPresentFlags")() }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12v7,
    unity_native_plugin_sys::IUnityGraphicsD3D12v7,
    0x4624B0DA41B64AAC_u64,
    0x915AABCB9BC3F0D3_u64
);
impl_d3d12_v7!(UnityGraphicsD3D12v7);

pub trait UnityGraphicsD3D12v8Interface: UnityGraphicsD3D12v7Interface {
    fn request_resource_state(&self, resource: ComPtr, state: i32);
    fn notify_resource_state(&self, resource: ComPtr, state: i32, uav_access: bool);
}

pub use UnityGraphicsD3D12v8Interface as IUnityGraphicsD3D12v8;

macro_rules! impl_d3d12_v8 {
    ($intf:ty) => {
        impl_d3d12_v7!($intf);

        impl UnityGraphicsD3D12v8Interface for $intf {
            fn request_resource_state(&self, resource: ComPtr, state: i32) {
                unsafe {
                    self.interface()
                        .RequestResourceState
                        .expect("RequestResourceState")(
                        resource as *mut ID3D12Resource, state
                    )
                }
            }

            fn notify_resource_state(&self, resource: ComPtr, state: i32, uav_access: bool) {
                unsafe {
                    self.interface()
                        .NotifyResourceState
                        .expect("NotifyResourceState")(
                        resource as *mut ID3D12Resource,
                        state,
                        uav_access,
                    )
                }
            }
        }
    };
}

define_unity_interface!(
    UnityGraphicsD3D12v8,
    unity_native_plugin_sys::IUnityGraphicsD3D12v8,
    0x9D303045D00D4CFD_u64,
    0x8FEBB42968B423B6_u64
);
impl_d3d12_v8!(UnityGraphicsD3D12v8);