From fc552804abd22e7b229522911810dbd2fc313a4c Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Wed, 29 Apr 2026 21:32:03 +0900 Subject: [PATCH 1/8] Update README to add Metal support and clarify Vulkan dependency integration --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index fe59bff..305cb80 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,7 @@ Unity Native Plugin API for Rust ## Notice -* WIP -* Currently supports D3D11, D3D12, Vulkan +* Currently supports D3D11, D3D12, Vulkan, Metal * API is not stable. ## How to use @@ -19,16 +18,13 @@ unity-native-plugin = { version = "*", features = ["d3d11"] } # * Support features # * d3d11 - IUnityGraphicsD3D11 # * d3d12 - IUnityGraphicsD3D12 +# * vulkan - IUnityGraphicsVulkan +# * metal - IUnityGraphicsMetal # * profiler - IUnityProfiler # * profiler_callbacks - IUnityProfilerCallbacks ``` -* If you use Vulkan, define "unity-native-plugin-vulkan" in your dependencies. -```cargo -[dependencies] -unity-native-plugin = "*" -unity-native-plugin-vulkan = "*" -``` +* Vulkan support has been integrated into `unity-native-plugin`. No separate crate needs to be added to your dependencies. * Use a macro in lib.rs to define your entry points. Without this definition, UnityInterfaces cannot be used. ```rust From 1a6542eed5f07ac1b5ce99d5390b68e43c252e19 Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Wed, 29 Apr 2026 21:33:09 +0900 Subject: [PATCH 2/8] Update `Cargo.toml` to use resolver version 3 for dependency resolution --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f7415de..929c3f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,5 @@ members = [ "unity-native-plugin-sample", "unity-native-plugin-sample-profiler", ] -resolver = "2" +resolver = "3" From def36e0a91faec1db3d7dedcb7ac97b15ff730d4 Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Wed, 29 Apr 2026 21:35:29 +0900 Subject: [PATCH 3/8] Update dependencies in `Cargo.toml` to add Apple platform support with `objc2` libraries --- unity-native-plugin/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/unity-native-plugin/Cargo.toml b/unity-native-plugin/Cargo.toml index 1a952c2..bceec15 100644 --- a/unity-native-plugin/Cargo.toml +++ b/unity-native-plugin/Cargo.toml @@ -29,7 +29,9 @@ profiler_callbacks = ["profiler"] [dependencies] ash = { version = "0.38.0+1.3.281.1", optional = true } +unity-native-plugin-sys = { version = "0.9.0", path = "../unity-native-plugin-sys" } + +[target.'cfg(target_vendor = "apple")'.dependencies] objc2 = { version = "0.6.3", optional = true } objc2-foundation = { version = "0.3.2", optional = true } objc2-metal = { version = "0.3.2", optional = true } -unity-native-plugin-sys = { version = "0.9.0", path = "../unity-native-plugin-sys" } From 3939f744c2bad738554f843398e21d7c543e7ad8 Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Wed, 29 Apr 2026 21:44:35 +0900 Subject: [PATCH 4/8] Add clippy lint allowances to suppress warnings in `lib.rs` --- unity-native-plugin-sys/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unity-native-plugin-sys/src/lib.rs b/unity-native-plugin-sys/src/lib.rs index acae30f..8204f58 100644 --- a/unity-native-plugin-sys/src/lib.rs +++ b/unity-native-plugin-sys/src/lib.rs @@ -1,6 +1,10 @@ #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] +#![allow(clippy::all)] +#![allow(clippy::pedantic)] +#![allow(unnecessary_transmutes)] +#![allow(unsafe_op_in_unsafe_fn)] include!("plugin_api.rs"); include!("metal.rs"); From a64b5ceeaded170e0885e9df11a974ad4639ce14 Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Wed, 29 Apr 2026 21:56:01 +0900 Subject: [PATCH 5/8] Refactor unsafe casts with explicit type annotations for better clarity and safety, add Clippy lint allowances, update dependency versions, and optimize Vulkan resource accesses. --- .../src/lib.rs | 8 +- unity-native-plugin-sample/src/vulkan.rs | 20 ++- unity-native-plugin-tester/src/graphics.rs | 2 +- unity-native-plugin-tester/src/interface.rs | 10 +- unity-native-plugin-tester/src/lib.rs | 4 +- unity-native-plugin/Cargo.toml | 2 +- unity-native-plugin/src/bitflag.rs | 6 +- unity-native-plugin/src/graphics.rs | 14 +- unity-native-plugin/src/lib.rs | 2 + unity-native-plugin/src/log.rs | 2 +- unity-native-plugin/src/memory_manager.rs | 7 +- unity-native-plugin/src/profiler.rs | 19 +-- unity-native-plugin/src/profiler_callbacks.rs | 4 +- unity-native-plugin/src/vulkan.rs | 121 +++++++++++------- 14 files changed, 142 insertions(+), 79 deletions(-) diff --git a/unity-native-plugin-sample-profiler/src/lib.rs b/unity-native-plugin-sample-profiler/src/lib.rs index fc9fbd0..5ee2a95 100644 --- a/unity-native-plugin-sample-profiler/src/lib.rs +++ b/unity-native-plugin-sample-profiler/src/lib.rs @@ -75,13 +75,17 @@ fn plugin_load(interfaces: &unity_native_plugin::interface::UnityInterfaces) { } }; let pid = 1; - let tid: NonZeroU64 = unsafe { std::mem::transmute(std::thread::current().id()) }; + let tid: NonZeroU64 = unsafe { + std::mem::transmute::( + std::thread::current().id(), + ) + }; let ts = Instant::now(); let dt = ts - start_ts; let cat = desc.desc.category_id(); let cat: BuiltinProfilerCategory = if cat <= BuiltinProfilerCategory::VirtualTexturing as u16 { - unsafe { std::mem::transmute(cat) } + unsafe { std::mem::transmute::(cat) } } else { BuiltinProfilerCategory::Other }; diff --git a/unity-native-plugin-sample/src/vulkan.rs b/unity-native-plugin-sample/src/vulkan.rs index 80d8053..3efe662 100644 --- a/unity-native-plugin-sample/src/vulkan.rs +++ b/unity-native-plugin-sample/src/vulkan.rs @@ -52,13 +52,29 @@ pub fn fill_texture(unity_texture: *mut c_void, x: f32, y: f32, z: f32, w: f32) let pfn = unwrap_pfn(vk_instance.get_instance_proc_addr(c"vkGetDeviceProcAddr".as_ptr())); let vk_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr = match pfn { - Some(f) => std::mem::transmute(f), + Some(f) => std::mem::transmute::< + unsafe extern "system" fn(), + unsafe extern "system" fn( + vk::Device, + *const std::os::raw::c_char, + ) -> Option, + >(f), None => return, }; let pfn = vk_get_device_proc_addr(vk_instance.device(), c"vkCmdClearColorImage".as_ptr()); let vk_cmd_clear_color_image: vk::PFN_vkCmdClearColorImage = match pfn { - Some(f) => std::mem::transmute(f), + Some(f) => std::mem::transmute::< + unsafe extern "system" fn(), + unsafe extern "system" fn( + vk::CommandBuffer, + vk::Image, + vk::ImageLayout, + *const vk::ClearColorValue, + u32, + *const vk::ImageSubresourceRange, + ), + >(f), None => return, }; diff --git a/unity-native-plugin-tester/src/graphics.rs b/unity-native-plugin-tester/src/graphics.rs index 5659085..b6df417 100644 --- a/unity-native-plugin-tester/src/graphics.rs +++ b/unity-native-plugin-tester/src/graphics.rs @@ -30,7 +30,7 @@ impl crate::interface::UnityInterfaceBase for TesterContextGraphics { } fn get_unity_interface(&self) -> *mut IUnityInterface { - unsafe { std::mem::transmute::<_, _>(&self.interfaces) } + &self.interfaces as *const IUnityGraphics as *mut IUnityInterface } } diff --git a/unity-native-plugin-tester/src/interface.rs b/unity-native-plugin-tester/src/interface.rs index c20fef6..2c567a5 100644 --- a/unity-native-plugin-tester/src/interface.rs +++ b/unity-native-plugin-tester/src/interface.rs @@ -36,6 +36,12 @@ impl Debug for TesterContextInterfaces { unsafe impl Send for TesterContextInterfaces {} unsafe impl Sync for TesterContextInterfaces {} +impl Default for TesterContextInterfaces { + fn default() -> Self { + Self::new() + } +} + impl TesterContextInterfaces { pub fn new() -> Self { TesterContextInterfaces { @@ -50,7 +56,7 @@ impl TesterContextInterfaces { } pub fn interfaces(&self) -> *mut IUnityInterfaces { - unsafe { std::mem::transmute::<_, _>(&self.interfaces) } + &self.interfaces as *const IUnityInterfaces as *mut IUnityInterfaces } pub fn get_interface(&self, guid: UnityInterfaceGUID) -> Option> { @@ -133,7 +139,7 @@ pub unsafe fn get_unity_interface() { + if any_ref.downcast_ref::().is_some() { // Use Rc::clone to safely create an Rc // First, get a raw pointer from the original Rc let ptr = Rc::as_ptr(&interface_rc); diff --git a/unity-native-plugin-tester/src/lib.rs b/unity-native-plugin-tester/src/lib.rs index 267c7d0..fb8d783 100644 --- a/unity-native-plugin-tester/src/lib.rs +++ b/unity-native-plugin-tester/src/lib.rs @@ -1,6 +1,8 @@ +#![allow(clippy::missing_safety_doc)] + pub mod graphics; pub mod interface; pub mod window; -#[cfg(all(feature = "d3d11"))] +#[cfg(feature = "d3d11")] pub mod d3d11; diff --git a/unity-native-plugin/Cargo.toml b/unity-native-plugin/Cargo.toml index bceec15..63ffd88 100644 --- a/unity-native-plugin/Cargo.toml +++ b/unity-native-plugin/Cargo.toml @@ -28,7 +28,7 @@ profiler = [] profiler_callbacks = ["profiler"] [dependencies] -ash = { version = "0.38.0+1.3.281.1", optional = true } +ash = { version = "0.38.0", optional = true } unity-native-plugin-sys = { version = "0.9.0", path = "../unity-native-plugin-sys" } [target.'cfg(target_vendor = "apple")'.dependencies] diff --git a/unity-native-plugin/src/bitflag.rs b/unity-native-plugin/src/bitflag.rs index 4ab366e..5f4125c 100644 --- a/unity-native-plugin/src/bitflag.rs +++ b/unity-native-plugin/src/bitflag.rs @@ -18,9 +18,9 @@ macro_rules! bitflag { } } - impl Into<$flag_value_type> for $flag_type { - fn into(self) -> $flag_value_type { - self.flag as $flag_value_type + impl From<$flag_type> for $flag_value_type { + fn from(value: $flag_type) -> Self { + value.flag as $flag_value_type } } diff --git a/unity-native-plugin/src/graphics.rs b/unity-native-plugin/src/graphics.rs index bb5cdd8..6b9b0b9 100644 --- a/unity-native-plugin/src/graphics.rs +++ b/unity-native-plugin/src/graphics.rs @@ -46,13 +46,13 @@ define_unity_interface!( 0x8C5AD4926EB17B11_u64 ); -pub type GraphicsDeviceEventCallback = extern "system" fn(eventType: GfxDeviceEventType); +pub type GraphicsDeviceEventCallback = extern "system" fn(event_type: GfxDeviceEventType); impl UnityGraphics { pub fn renderer(&self) -> GfxRenderer { unsafe { match self.interface().GetRenderer { - Some(intf) => std::mem::transmute(intf()), + Some(intf) => std::mem::transmute::(intf()), None => GfxRenderer::Null, } } @@ -61,7 +61,10 @@ impl UnityGraphics { pub fn register_device_event_callback(&self, callback: Option) { unsafe { if let Some(intf) = self.interface().RegisterDeviceEventCallback { - intf(std::mem::transmute(callback)); + intf(std::mem::transmute::< + Option, + IUnityGraphicsDeviceEventCallback, + >(callback)); } } } @@ -69,7 +72,10 @@ impl UnityGraphics { pub fn unregister_device_event_callback(&self, callback: Option) { unsafe { if let Some(intf) = self.interface().UnregisterDeviceEventCallback { - intf(std::mem::transmute(callback)); + intf(std::mem::transmute::< + Option, + IUnityGraphicsDeviceEventCallback, + >(callback)); } } } diff --git a/unity-native-plugin/src/lib.rs b/unity-native-plugin/src/lib.rs index 395250e..729b7b9 100644 --- a/unity-native-plugin/src/lib.rs +++ b/unity-native-plugin/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::missing_safety_doc)] + #[cfg(feature = "d3d11")] pub mod d3d11; diff --git a/unity-native-plugin/src/log.rs b/unity-native-plugin/src/log.rs index 8824887..63fe67e 100644 --- a/unity-native-plugin/src/log.rs +++ b/unity-native-plugin/src/log.rs @@ -15,7 +15,7 @@ pub enum LogType { define_unity_interface!( UnityLog, IUnityLog, - 0x9E7507fA5B444D5D_u64, + 0x9E7507FA5B444D5D_u64, 0x92FB979515EA83FC_u64 ); diff --git a/unity-native-plugin/src/memory_manager.rs b/unity-native-plugin/src/memory_manager.rs index 621456f..541a0f1 100644 --- a/unity-native-plugin/src/memory_manager.rs +++ b/unity-native-plugin/src/memory_manager.rs @@ -1,7 +1,6 @@ use crate::define_unity_interface; use crate::interface::UnityInterface; use std::ffi::{CStr, c_void}; -use std::ptr::null_mut; use unity_native_plugin_sys::*; define_unity_interface!( @@ -71,10 +70,10 @@ impl UnityMemoryManager { area_name.as_ptr(), object_name.as_ptr(), ); - if allocator != null_mut() { + if !allocator.is_null() { Some(UnityAllocator { - allocator: allocator, - memory_manager: self.clone(), + allocator, + memory_manager: *self, }) } else { None diff --git a/unity-native-plugin/src/profiler.rs b/unity-native-plugin/src/profiler.rs index 1813eb8..d580704 100644 --- a/unity-native-plugin/src/profiler.rs +++ b/unity-native-plugin/src/profiler.rs @@ -1,7 +1,6 @@ use crate::bitflag; use crate::define_unity_interface; use crate::interface::UnityInterface; -use std::ptr::null_mut; use unity_native_plugin_sys::*; define_unity_interface!( @@ -92,7 +91,7 @@ impl ProfilerMarkerEventType { pub fn from(value: u16) -> Option { use ProfilerMarkerEventType::*; if value <= Single as u16 { - Some(unsafe { std::mem::transmute(value) }) + Some(unsafe { std::mem::transmute::(value) }) } else { None } @@ -160,7 +159,7 @@ impl ProfilerMarkerDataType { #[allow(unused)] pub(crate) fn from(value: u8) -> Option { if value <= ProfilerMarkerDataType::Blob8 as u8 { - Some(unsafe { std::mem::transmute(value) }) + Some(unsafe { std::mem::transmute::(value) }) } else { None } @@ -183,7 +182,7 @@ impl ProfilerMarkerDataUnit { #[allow(unused)] pub(crate) fn from(value: u8) -> Option { if value <= ProfilerMarkerDataUnit::FrequencyHz as u8 { - Some(unsafe { std::mem::transmute(value) }) + Some(unsafe { std::mem::transmute::(value) }) } else { None } @@ -213,7 +212,7 @@ impl ProfilerMarkerData<'_> { } pub fn data_type(&self) -> ProfilerMarkerDataType { - unsafe { std::mem::transmute(self.native.type_) } + unsafe { std::mem::transmute::(self.native.type_) } } pub fn data(&self) -> &'_ [u8] { @@ -232,7 +231,7 @@ pub enum ProfilerFlowEventType { impl ProfilerFlowEventType { pub fn from(value: u8) -> Option { if value <= ProfilerFlowEventType::End as u8 { - Some(unsafe { std::mem::transmute(value) }) + Some(unsafe { std::mem::transmute::(value) }) } else { None } @@ -284,8 +283,8 @@ macro_rules! impl_profiler { unsafe { self.interface().IsAvailable.expect("IsAvailable")() != 0 } } - pub fn create_marker<'a>( - &'a self, + pub fn create_marker( + &self, name: &std::ffi::CStr, category: ProfilerCategoryId, flags: ProfilerMarkerFlags, @@ -412,6 +411,7 @@ macro_rules! impl_profiler_v2 { } } + #[allow(clippy::too_many_arguments)] pub unsafe fn create_counter_value( &self, category: ProfilerCategoryId, @@ -451,6 +451,7 @@ macro_rules! impl_profiler_v2 { } } + #[allow(clippy::too_many_arguments)] pub unsafe fn create_counter( &self, category: ProfilerCategoryId, @@ -476,7 +477,7 @@ macro_rules! impl_profiler_v2 { deactivate_func, user_data, ); - if r != null_mut() { + if !r.is_null() { Some(ProfilerCounter:: { counter: r as *mut T, }) diff --git a/unity-native-plugin/src/profiler_callbacks.rs b/unity-native-plugin/src/profiler_callbacks.rs index bd64bdf..55d4941 100644 --- a/unity-native-plugin/src/profiler_callbacks.rs +++ b/unity-native-plugin/src/profiler_callbacks.rs @@ -71,8 +71,8 @@ impl<'a> std::fmt::Debug for ProfilerMarkerEvent<'a> { pub struct ProfilerMarkerData(UnityProfilerMarkerData); impl ProfilerMarkerData { - pub fn value(&self) -> ProfilerMarkerDataValue { - match unsafe { std::mem::transmute::<_, ProfilerMarkerDataType>(self.0.type_) } { + pub fn value(&self) -> ProfilerMarkerDataValue<'_> { + match unsafe { std::mem::transmute::(self.0.type_) } { ProfilerMarkerDataType::None => ProfilerMarkerDataValue::None, ProfilerMarkerDataType::InstanceId => { ProfilerMarkerDataValue::InstanceId(unsafe { *(self.0.ptr as *const i32) }) diff --git a/unity-native-plugin/src/vulkan.rs b/unity-native-plugin/src/vulkan.rs index 9d9e77e..104174b 100644 --- a/unity-native-plugin/src/vulkan.rs +++ b/unity-native-plugin/src/vulkan.rs @@ -94,15 +94,24 @@ impl VulkanPluginEventConfig { } pub fn render_pass_precondition(&self) -> VulkanEventRenderPassPreCondition { - unsafe { std::mem::transmute(self.native.renderPassPrecondition) } + unsafe { + std::mem::transmute::< + UnityVulkanEventRenderPassPreCondition, + VulkanEventRenderPassPreCondition, + >(self.native.renderPassPrecondition) + } } pub fn graphics_queue_access(&self) -> VulkanGraphicsQueueAccess { - unsafe { std::mem::transmute(self.native.graphicsQueueAccess) } + unsafe { + std::mem::transmute::( + self.native.graphicsQueueAccess, + ) + } } pub fn flags(&self) -> u32 { - unsafe { std::mem::transmute(self.native.flags) } + self.native.flags } } @@ -116,7 +125,7 @@ impl VulkanRecordingState { } pub fn command_buffer_level(&self) -> ash::vk::CommandBufferLevel { - unsafe { std::mem::transmute(self.native.commandBufferLevel) } + ash::vk::CommandBufferLevel::from_raw(self.native.commandBufferLevel as i32) } pub fn render_pass(&self) -> ash::vk::RenderPass { @@ -162,7 +171,7 @@ impl VulkanMemory<'_> { } pub fn flags(&self) -> ash::vk::MemoryPropertyFlags { - unsafe { std::mem::transmute(self.native.flags) } + ash::vk::MemoryPropertyFlags::from_raw(self.native.flags) } pub fn memory_type_index(&self) -> ::std::os::raw::c_uint { @@ -183,7 +192,7 @@ pub struct VulkanImage { } impl VulkanImage { - pub fn memory(&self) -> VulkanMemory { + pub fn memory(&self) -> VulkanMemory<'_> { VulkanMemory { native: &self.native.memory, } @@ -194,35 +203,39 @@ impl VulkanImage { } pub fn layout(&self) -> ash::vk::ImageLayout { - unsafe { ash::vk::ImageLayout::from_raw(std::mem::transmute(self.native.layout)) } + ash::vk::ImageLayout::from_raw(self.native.layout as i32) } pub fn aspect(&self) -> ash::vk::ImageAspectFlags { - unsafe { std::mem::transmute(self.native.aspect) } + ash::vk::ImageAspectFlags::from_raw(self.native.aspect) } pub fn usage(&self) -> ash::vk::ImageUsageFlags { - unsafe { std::mem::transmute(self.native.usage) } + ash::vk::ImageUsageFlags::from_raw(self.native.usage) } pub fn format(&self) -> ash::vk::Format { - unsafe { std::mem::transmute(self.native.format) } + ash::vk::Format::from_raw(self.native.format as i32) } pub fn extent(&self) -> ash::vk::Extent3D { - unsafe { std::mem::transmute(self.native.extent) } + ash::vk::Extent3D { + width: self.native.extent.width, + height: self.native.extent.height, + depth: self.native.extent.depth, + } } pub fn tiling(&self) -> ash::vk::ImageTiling { - unsafe { std::mem::transmute(self.native.tiling) } + ash::vk::ImageTiling::from_raw(self.native.tiling as i32) } pub fn image_type(&self) -> ash::vk::ImageType { - unsafe { std::mem::transmute(self.native.type_) } + ash::vk::ImageType::from_raw(self.native.type_ as i32) } pub fn samples(&self) -> ash::vk::SampleCountFlags { - unsafe { std::mem::transmute(self.native.samples) } + ash::vk::SampleCountFlags::from_raw(self.native.samples) } pub fn layers(&self) -> ::std::os::raw::c_int { @@ -256,7 +269,10 @@ macro_rules! impl_vulkan { unsafe { self.interface() .InterceptInitialization - .expect("InterceptInitialization")(std::mem::transmute(func), user_data); + .expect("InterceptInitialization")( + std::mem::transmute::(func), + user_data, + ); } } @@ -266,12 +282,9 @@ macro_rules! impl_vulkan { func: ash::vk::PFN_vkVoidFunction, ) -> ash::vk::PFN_vkVoidFunction { unsafe { - std::mem::transmute(self - .interface() + self.interface() .InterceptVulkanAPI - .expect("InterceptVulkanAPI")( - name, std::mem::transmute(func) - )) + .expect("InterceptVulkanAPI")(name, func) } } @@ -306,7 +319,7 @@ macro_rules! impl_vulkan { .interface() .CommandRecordingState .expect("CommandRecordingState")( - std::mem::transmute(&mut ret), + &mut ret, queue_access as UnityVulkanGraphicsQueueAccess, ) { Some(VulkanRecordingState { native: ret }) @@ -330,14 +343,16 @@ macro_rules! impl_vulkan { if self.interface().AccessTexture.expect("AccessTexture")( native_texture, match sub_resource { - Some(t) => std::mem::transmute(t), + Some(t) => { + t as *const ash::vk::ImageSubresource as *const VkImageSubresource + } None => std::ptr::null(), }, - std::mem::transmute(layout), - std::mem::transmute(pipeline_stage_flags), - std::mem::transmute(access_flags), + layout.as_raw() as VkImageLayout, + pipeline_stage_flags.as_raw(), + access_flags.as_raw(), access_mode as UnityVulkanResourceAccessMode, - std::mem::transmute(&mut ret), + &mut ret, ) { Some(VulkanImage { native: ret }) } else { @@ -363,14 +378,16 @@ macro_rules! impl_vulkan { .expect("AccessRenderBufferTexture")( native_render_buffer, match sub_resource { - Some(t) => std::mem::transmute(t), + Some(t) => { + t as *const ash::vk::ImageSubresource as *const VkImageSubresource + } None => std::ptr::null(), }, - std::mem::transmute(layout), - std::mem::transmute(pipeline_stage_flags), - std::mem::transmute(access_flags), + layout.as_raw() as VkImageLayout, + pipeline_stage_flags.as_raw(), + access_flags.as_raw(), access_mode as UnityVulkanResourceAccessMode, - std::mem::transmute(&mut ret), + &mut ret, ) { Some(VulkanImage { native: ret }) } else { @@ -396,14 +413,16 @@ macro_rules! impl_vulkan { .expect("AccessRenderBufferResolveTexture")( native_render_buffer, match sub_resource { - Some(t) => std::mem::transmute(t), + Some(t) => { + t as *const ash::vk::ImageSubresource as *const VkImageSubresource + } None => std::ptr::null(), }, - std::mem::transmute(layout), - std::mem::transmute(pipeline_stage_flags), - std::mem::transmute(access_flags), + layout.as_raw() as VkImageLayout, + pipeline_stage_flags.as_raw(), + access_flags.as_raw(), access_mode as UnityVulkanResourceAccessMode, - std::mem::transmute(&mut ret), + &mut ret, ) { Some(VulkanImage { native: ret }) } else { @@ -423,10 +442,10 @@ macro_rules! impl_vulkan { let mut ret = std::mem::zeroed::(); if self.interface().AccessBuffer.expect("AccessTexture")( native_buffer, - std::mem::transmute(pipeline_stage_flags), - std::mem::transmute(access_flags), + pipeline_stage_flags.as_raw(), + access_flags.as_raw(), access_mode as UnityVulkanResourceAccessMode, - std::mem::transmute(&mut ret), + &mut ret as *mut UnityVulkanImage as *mut UnityVulkanBuffer, ) { Some(VulkanImage { native: ret }) } else { @@ -469,7 +488,10 @@ macro_rules! impl_vulkan { unsafe { self.interface() .ConfigureSwapchain - .expect("ConfigureSwapchain")(std::mem::transmute(swapchain_config)) + .expect("ConfigureSwapchain")( + swapchain_config as *const VulkanSwapchainConfiguration + as *const UnityVulkanSwapchainConfiguration, + ) } } @@ -490,14 +512,16 @@ macro_rules! impl_vulkan { .expect("AccessTextureByID")( texture_id, match sub_resource { - Some(t) => std::mem::transmute(t), + Some(t) => { + t as *const ash::vk::ImageSubresource as *const VkImageSubresource + } None => std::ptr::null(), }, - std::mem::transmute(layout), - std::mem::transmute(pipeline_stage_flags), - std::mem::transmute(access_flags), + layout.as_raw() as VkImageLayout, + pipeline_stage_flags.as_raw(), + access_flags.as_raw(), access_mode as UnityVulkanResourceAccessMode, - std::mem::transmute(&mut ret), + &mut ret, ) { Some(VulkanImage { native: ret }) } else { @@ -533,7 +557,7 @@ macro_rules! impl_vulkan_v2 { self.interface() .AddInterceptInitialization .expect("AddInterceptInitialization")( - std::mem::transmute(func), + std::mem::transmute::(func), user_data, priority, ) @@ -544,7 +568,10 @@ macro_rules! impl_vulkan_v2 { unsafe { self.interface() .RemoveInterceptInitialization - .expect("RemoveInterceptInitialization")(std::mem::transmute(func)) + .expect("RemoveInterceptInitialization")(std::mem::transmute::< + VulkanInitCallback, + UnityVulkanInitCallback, + >(func)) } } }; From a03b4a8e6ece3794beb4b491e45c021d520ad27a Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Thu, 30 Apr 2026 21:19:56 +0900 Subject: [PATCH 6/8] Update Windows-specific dependencies in `Cargo.toml` and refine feature gating for `d3d11` in `lib.rs` --- unity-native-plugin-tester/Cargo.toml | 2 ++ unity-native-plugin-tester/src/lib.rs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/unity-native-plugin-tester/Cargo.toml b/unity-native-plugin-tester/Cargo.toml index 403abd1..0342fec 100644 --- a/unity-native-plugin-tester/Cargo.toml +++ b/unity-native-plugin-tester/Cargo.toml @@ -27,6 +27,8 @@ d3d12 = [] [dependencies] unity-native-plugin-sys = { version = "0.9.0", path = "../unity-native-plugin-sys" } unity-native-plugin = { version = "0.9.0", path = "../unity-native-plugin", features = ["d3d11", "d3d12"] } + +[target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["winuser", "dxgi", "d3d11", "dxgiformat", "dxgitype", "d3dcommon"] } winit = "0.23.0" wio = "0.2.2" diff --git a/unity-native-plugin-tester/src/lib.rs b/unity-native-plugin-tester/src/lib.rs index fb8d783..046f9a9 100644 --- a/unity-native-plugin-tester/src/lib.rs +++ b/unity-native-plugin-tester/src/lib.rs @@ -2,7 +2,8 @@ pub mod graphics; pub mod interface; +#[cfg(windows)] pub mod window; -#[cfg(feature = "d3d11")] +#[cfg(all(windows, feature = "d3d11"))] pub mod d3d11; From e0153971a96e09e37e6d3265f439bebd4219dde1 Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Thu, 30 Apr 2026 21:29:00 +0900 Subject: [PATCH 7/8] Add GitHub Actions CI workflow for testing on multiple platforms --- .github/workflows/ci.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0b8fb38 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + pull_request: + push: + branches: [master] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: -D warnings + +jobs: + test: + name: ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - uses: Swatinem/rust-cache@v2 + + - name: Clippy + run: cargo clippy --workspace --all-targets + + - name: Build + run: cargo build --workspace --all-targets + + - name: Test + run: cargo test --workspace From a6e194a5c8e3e251b55993aa21a3a818f0c76d6a Mon Sep 17 00:00:00 2001 From: Yasuhiro Taniuchi Date: Thu, 30 Apr 2026 21:39:00 +0900 Subject: [PATCH 8/8] Mark `test_plugin_d3d11` as ignored on Windows due to desktop requirement --- unity-native-plugin-sample/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/unity-native-plugin-sample/src/lib.rs b/unity-native-plugin-sample/src/lib.rs index 7c6b0c4..91c75de 100644 --- a/unity-native-plugin-sample/src/lib.rs +++ b/unity-native-plugin-sample/src/lib.rs @@ -106,6 +106,7 @@ pub extern "system" fn GetFillTextureCallback() -> extern "system" fn(c_int, *mu #[cfg(windows)] #[test] +#[ignore = "Requires Desktop"] fn test() { let instant = std::time::Instant::now(); unity_native_plugin_tester::d3d11::test_plugin_d3d11(