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