unity_native_plugin_vulkan/
vulkan.rs

1use ash::vk::Handle;
2use unity_native_plugin::define_unity_interface;
3use unity_native_plugin::interface::UnityInterface;
4use unity_native_plugin_sys::*;
5
6define_unity_interface!(
7    UnityGraphicsVulkan,
8    unity_native_plugin_sys::IUnityGraphicsVulkan,
9    0x95355348d4ef4e11_u64,
10    0x9789313dfcffcc87_u64
11);
12
13pub type VulkanInitCallback = Option<
14    unsafe extern "system" fn(
15        get_instance_proc_addr: ash::vk::PFN_vkGetInstanceProcAddr,
16        userdata: *mut ::std::os::raw::c_void,
17    ) -> ash::vk::PFN_vkGetInstanceProcAddr,
18>;
19
20pub struct VulkanInstance {
21    native: UnityVulkanInstance,
22}
23
24impl VulkanInstance {
25    pub fn pipeline_cache(&self) -> ash::vk::PipelineCache {
26        ash::vk::PipelineCache::from_raw(self.native.pipelineCache as u64)
27    }
28
29    pub fn instance(&self) -> ash::vk::Instance {
30        ash::vk::Instance::from_raw(self.native.instance as u64)
31    }
32
33    pub fn physical_device(&self) -> ash::vk::PhysicalDevice {
34        ash::vk::PhysicalDevice::from_raw(self.native.physicalDevice as u64)
35    }
36
37    pub fn device(&self) -> ash::vk::Device {
38        ash::vk::Device::from_raw(self.native.device as u64)
39    }
40
41    pub fn graphics_queue(&self) -> ash::vk::Queue {
42        ash::vk::Queue::from_raw(self.native.graphicsQueue as u64)
43    }
44
45    pub fn queue_family_index(&self) -> ::std::os::raw::c_uint {
46        self.native.queueFamilyIndex
47    }
48
49    pub unsafe fn get_instance_proc_addr(
50        &self,
51        name: *const std::os::raw::c_char,
52    ) -> PFN_vkVoidFunction {
53        if let Some(f) = self.native.getInstanceProcAddr {
54            (f)(self.native.instance, name)
55        } else {
56            PFN_vkVoidFunction::None
57        }
58    }
59}
60
61#[repr(u32)]
62#[derive(Copy, Clone, PartialEq, Eq, Debug)]
63pub enum VulkanEventRenderPassPreCondition {
64    DontCare = UnityVulkanEventRenderPassPreCondition_kUnityVulkanRenderPass_DontCare,
65    EnsureInside = UnityVulkanEventRenderPassPreCondition_kUnityVulkanRenderPass_EnsureInside,
66    EnsureOutside = UnityVulkanEventRenderPassPreCondition_kUnityVulkanRenderPass_EnsureOutside,
67}
68
69#[repr(u32)]
70#[derive(Copy, Clone, PartialEq, Eq, Debug)]
71pub enum VulkanGraphicsQueueAccess {
72    DontCare = UnityVulkanGraphicsQueueAccess_kUnityVulkanGraphicsQueueAccess_DontCare,
73    Allow = UnityVulkanGraphicsQueueAccess_kUnityVulkanGraphicsQueueAccess_Allow,
74}
75
76pub struct VulkanPluginEventConfig {
77    native: UnityVulkanPluginEventConfig,
78}
79
80impl VulkanPluginEventConfig {
81    pub fn render_pass_precondition(&self) -> VulkanEventRenderPassPreCondition {
82        unsafe { std::mem::transmute(self.native.renderPassPrecondition) }
83    }
84
85    pub fn graphics_queue_access(&self) -> VulkanGraphicsQueueAccess {
86        unsafe { std::mem::transmute(self.native.graphicsQueueAccess) }
87    }
88
89    pub fn flags(&self) -> u32 {
90        unsafe { std::mem::transmute(self.native.flags) }
91    }
92}
93
94pub struct VulkanRecordingState {
95    native: UnityVulkanRecordingState,
96}
97
98impl VulkanRecordingState {
99    pub fn command_buffer(&self) -> ash::vk::CommandBuffer {
100        ash::vk::CommandBuffer::from_raw(self.native.commandBuffer as u64)
101    }
102
103    pub fn command_buffer_level(&self) -> ash::vk::CommandBufferLevel {
104        unsafe { std::mem::transmute(self.native.commandBufferLevel) }
105    }
106
107    pub fn render_pass(&self) -> ash::vk::RenderPass {
108        ash::vk::RenderPass::from_raw(self.native.renderPass as u64)
109    }
110
111    pub fn framebuffer(&self) -> ash::vk::Framebuffer {
112        ash::vk::Framebuffer::from_raw(self.native.framebuffer as u64)
113    }
114
115    pub fn sub_pass_index(&self) -> ::std::os::raw::c_int {
116        self.native.subPassIndex
117    }
118
119    pub fn current_frame_number(&self) -> ::std::os::raw::c_ulonglong {
120        self.native.currentFrameNumber
121    }
122
123    pub fn safe_frame_number(&self) -> ::std::os::raw::c_ulonglong {
124        self.native.safeFrameNumber
125    }
126}
127
128pub struct VulkanMemory<'a> {
129    native: &'a UnityVulkanMemory,
130}
131
132impl VulkanMemory<'_> {
133    pub fn memory(&self) -> ash::vk::DeviceMemory {
134        ash::vk::DeviceMemory::from_raw(self.native.memory as u64)
135    }
136
137    pub fn offset(&self) -> ash::vk::DeviceSize {
138        self.native.offset
139    }
140
141    pub fn size(&self) -> ash::vk::DeviceSize {
142        self.native.size
143    }
144
145    pub fn mapped(&self) -> *mut ::std::os::raw::c_void {
146        self.native.mapped
147    }
148
149    pub fn flags(&self) -> ash::vk::MemoryPropertyFlags {
150        unsafe { std::mem::transmute(self.native.flags) }
151    }
152
153    pub fn memory_type_index(&self) -> ::std::os::raw::c_uint {
154        self.native.memoryTypeIndex
155    }
156}
157
158#[repr(u32)]
159#[derive(Copy, Clone, PartialEq, Eq, Debug)]
160pub enum VulkanResourceAccessMode {
161    ObserveOnly = UnityVulkanResourceAccessMode_kUnityVulkanResourceAccess_ObserveOnly,
162    PipelineBarrier = UnityVulkanResourceAccessMode_kUnityVulkanResourceAccess_PipelineBarrier,
163    Recreate = UnityVulkanResourceAccessMode_kUnityVulkanResourceAccess_Recreate,
164}
165
166pub struct VulkanImage {
167    native: UnityVulkanImage,
168}
169
170impl VulkanImage {
171    pub fn memory(&self) -> VulkanMemory {
172        VulkanMemory {
173            native: &self.native.memory,
174        }
175    }
176
177    pub fn image(&self) -> ash::vk::Image {
178        ash::vk::Image::from_raw(self.native.image as u64)
179    }
180
181    pub fn layout(&self) -> ash::vk::ImageLayout {
182        unsafe { ash::vk::ImageLayout::from_raw(std::mem::transmute(self.native.layout)) }
183    }
184
185    pub fn aspect(&self) -> ash::vk::ImageAspectFlags {
186        unsafe { std::mem::transmute(self.native.aspect) }
187    }
188
189    pub fn usage(&self) -> ash::vk::ImageUsageFlags {
190        unsafe { std::mem::transmute(self.native.usage) }
191    }
192
193    pub fn format(&self) -> ash::vk::Format {
194        unsafe { std::mem::transmute(self.native.format) }
195    }
196
197    pub fn extent(&self) -> ash::vk::Extent3D {
198        unsafe { std::mem::transmute(self.native.extent) }
199    }
200
201    pub fn tiling(&self) -> ash::vk::ImageTiling {
202        unsafe { std::mem::transmute(self.native.tiling) }
203    }
204
205    pub fn image_type(&self) -> ash::vk::ImageType {
206        unsafe { std::mem::transmute(self.native.type_) }
207    }
208
209    pub fn samples(&self) -> ash::vk::SampleCountFlags {
210        unsafe { std::mem::transmute(self.native.samples) }
211    }
212
213    pub fn layers(&self) -> ::std::os::raw::c_int {
214        self.native.layers
215    }
216
217    pub fn mip_count(&self) -> ::std::os::raw::c_int {
218        self.native.mipCount
219    }
220}
221
222#[repr(u32)]
223#[derive(Copy, Clone, PartialEq, Eq, Debug)]
224pub enum VulkanSwapchainMode {
225    Default = UnityVulkanSwapchainMode_kUnityVulkanSwapchainMode_Default,
226    Offscreen = UnityVulkanSwapchainMode_kUnityVulkanSwapchainMode_Offscreen,
227}
228
229#[repr(C)]
230pub struct VulkanSwapchainConfiguration {
231    pub mode: VulkanSwapchainMode,
232}
233
234impl UnityGraphicsVulkan {
235    pub unsafe fn intercept_initialization(
236        &self,
237        func: VulkanInitCallback,
238        userdata: *mut ::std::os::raw::c_void,
239    ) {
240        self.interface()
241            .InterceptInitialization
242            .expect("InterceptInitialization")(std::mem::transmute(func), userdata);
243    }
244
245    pub unsafe fn intercept_vulkan_api(
246        &self,
247        name: *const ::std::os::raw::c_char,
248        func: ash::vk::PFN_vkVoidFunction,
249    ) -> ash::vk::PFN_vkVoidFunction {
250        std::mem::transmute(self
251            .interface()
252            .InterceptVulkanAPI
253            .expect("InterceptVulkanAPI")(
254            name, std::mem::transmute(func)
255        ))
256    }
257
258    pub fn configure_event(&self, event_id: i32, plugin_event_config: &VulkanPluginEventConfig) {
259        unsafe {
260            self.interface().ConfigureEvent.expect("ConfigureEvent")(
261                event_id,
262                &plugin_event_config.native,
263            )
264        }
265    }
266
267    pub fn instance(&self) -> VulkanInstance {
268        unsafe {
269            VulkanInstance {
270                native: self.interface().Instance.expect("Instance")(),
271            }
272        }
273    }
274
275    pub fn command_recording_state(
276        &self,
277        queue_access: VulkanGraphicsQueueAccess,
278    ) -> Option<VulkanRecordingState> {
279        unsafe {
280            let mut ret = std::mem::zeroed::<UnityVulkanRecordingState>();
281            if self
282                .interface()
283                .CommandRecordingState
284                .expect("CommandRecordingState")(
285                std::mem::transmute(&mut ret),
286                queue_access as UnityVulkanGraphicsQueueAccess,
287            ) {
288                Some(VulkanRecordingState { native: ret })
289            } else {
290                None
291            }
292        }
293    }
294
295    pub unsafe fn access_texture(
296        &self,
297        native_texture: *mut ::std::os::raw::c_void,
298        sub_resource: Option<&ash::vk::ImageSubresource>,
299        layout: ash::vk::ImageLayout,
300        pipeline_stage_flags: ash::vk::PipelineStageFlags,
301        access_flags: ash::vk::AccessFlags,
302        access_mode: VulkanResourceAccessMode,
303    ) -> Option<VulkanImage> {
304        let mut ret = std::mem::zeroed::<UnityVulkanImage>();
305        if self.interface().AccessTexture.expect("AccessTexture")(
306            native_texture,
307            match sub_resource {
308                Some(t) => std::mem::transmute(t),
309                None => std::ptr::null(),
310            },
311            std::mem::transmute(layout),
312            std::mem::transmute(pipeline_stage_flags),
313            std::mem::transmute(access_flags),
314            access_mode as UnityVulkanResourceAccessMode,
315            std::mem::transmute(&mut ret),
316        ) {
317            Some(VulkanImage { native: ret })
318        } else {
319            None
320        }
321    }
322
323    pub unsafe fn access_render_buffer_texture(
324        &self,
325        native_render_buffer: unity_native_plugin::graphics::RenderBuffer,
326        sub_resource: Option<&ash::vk::ImageSubresource>,
327        layout: ash::vk::ImageLayout,
328        pipeline_stage_flags: ash::vk::PipelineStageFlags,
329        access_flags: ash::vk::AccessFlags,
330        access_mode: VulkanResourceAccessMode,
331    ) -> Option<VulkanImage> {
332        let mut ret = std::mem::zeroed::<UnityVulkanImage>();
333        if self
334            .interface()
335            .AccessRenderBufferTexture
336            .expect("AccessRenderBufferTexture")(
337            native_render_buffer,
338            match sub_resource {
339                Some(t) => std::mem::transmute(t),
340                None => std::ptr::null(),
341            },
342            std::mem::transmute(layout),
343            std::mem::transmute(pipeline_stage_flags),
344            std::mem::transmute(access_flags),
345            access_mode as UnityVulkanResourceAccessMode,
346            std::mem::transmute(&mut ret),
347        ) {
348            Some(VulkanImage { native: ret })
349        } else {
350            None
351        }
352    }
353
354    pub unsafe fn access_render_buffer_resolve_texture(
355        &self,
356        native_render_buffer: unity_native_plugin::graphics::RenderBuffer,
357        sub_resource: Option<&ash::vk::ImageSubresource>,
358        layout: ash::vk::ImageLayout,
359        pipeline_stage_flags: ash::vk::PipelineStageFlags,
360        access_flags: ash::vk::AccessFlags,
361        access_mode: VulkanResourceAccessMode,
362    ) -> Option<VulkanImage> {
363        let mut ret = std::mem::zeroed::<UnityVulkanImage>();
364        if self
365            .interface()
366            .AccessRenderBufferResolveTexture
367            .expect("AccessRenderBufferResolveTexture")(
368            native_render_buffer,
369            match sub_resource {
370                Some(t) => std::mem::transmute(t),
371                None => std::ptr::null(),
372            },
373            std::mem::transmute(layout),
374            std::mem::transmute(pipeline_stage_flags),
375            std::mem::transmute(access_flags),
376            access_mode as UnityVulkanResourceAccessMode,
377            std::mem::transmute(&mut ret),
378        ) {
379            Some(VulkanImage { native: ret })
380        } else {
381            None
382        }
383    }
384
385    pub unsafe fn access_buffer(
386        &self,
387        native_buffer: *mut ::std::os::raw::c_void,
388        pipeline_stage_flags: ash::vk::PipelineStageFlags,
389        access_flags: ash::vk::AccessFlags,
390        access_mode: VulkanResourceAccessMode,
391    ) -> Option<VulkanImage> {
392        let mut ret = std::mem::zeroed::<UnityVulkanImage>();
393        if self.interface().AccessBuffer.expect("AccessTexture")(
394            native_buffer,
395            std::mem::transmute(pipeline_stage_flags),
396            std::mem::transmute(access_flags),
397            access_mode as UnityVulkanResourceAccessMode,
398            std::mem::transmute(&mut ret),
399        ) {
400            Some(VulkanImage { native: ret })
401        } else {
402            None
403        }
404    }
405
406    pub fn ensure_outside_render_pass(&self) {
407        unsafe {
408            self.interface()
409                .EnsureOutsideRenderPass
410                .expect("EnsureOutsideRenderPass")()
411        }
412    }
413
414    pub fn ensure_inside_render_pass(&self) {
415        unsafe {
416            self.interface()
417                .EnsureInsideRenderPass
418                .expect("EnsureInsideRenderPass")()
419        }
420    }
421
422    pub unsafe fn access_queue(
423        &self,
424        callback: UnityRenderingEventAndData,
425        event_id: ::std::os::raw::c_int,
426        user_data: *mut ::std::os::raw::c_void,
427        flush: bool,
428    ) {
429        self.interface().AccessQueue.expect("AccessQueue")(callback, event_id, user_data, flush);
430    }
431
432    pub fn configure_swapchain(&self, swapchain_config: &VulkanSwapchainConfiguration) -> bool {
433        unsafe {
434            self.interface()
435                .ConfigureSwapchain
436                .expect("ConfigureSwapchain")(std::mem::transmute(swapchain_config))
437        }
438    }
439
440    pub unsafe fn access_texture_by_id(
441        &self,
442        texture_id: unity_native_plugin::graphics::TextureID,
443        sub_resource: Option<&ash::vk::ImageSubresource>,
444        layout: ash::vk::ImageLayout,
445        pipeline_stage_flags: ash::vk::PipelineStageFlags,
446        access_flags: ash::vk::AccessFlags,
447        access_mode: VulkanResourceAccessMode,
448    ) -> Option<VulkanImage> {
449        let mut ret = std::mem::zeroed::<UnityVulkanImage>();
450        if self
451            .interface()
452            .AccessTextureByID
453            .expect("AccessTextureByID")(
454            texture_id,
455            match sub_resource {
456                Some(t) => std::mem::transmute(t),
457                None => std::ptr::null(),
458            },
459            std::mem::transmute(layout),
460            std::mem::transmute(pipeline_stage_flags),
461            std::mem::transmute(access_flags),
462            access_mode as UnityVulkanResourceAccessMode,
463            std::mem::transmute(&mut ret),
464        ) {
465            Some(VulkanImage { native: ret })
466        } else {
467            None
468        }
469    }
470}
471
472#[cfg(test)]
473mod test {
474    use super::*;
475
476    #[test]
477    fn size_test() {
478        assert_eq!(
479            ::std::mem::size_of::<VulkanSwapchainConfiguration>(),
480            ::std::mem::size_of::<unity_native_plugin_sys::UnityVulkanSwapchainConfiguration>()
481        );
482    }
483}