├── .github └── workflows │ ├── 1-unity-native-plugin-sys.yml │ ├── 2-unity-native-plugin.yml │ └── 3-unity-native-plugin-vulkan.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── LICENSE_UnityNativePluginAPI.md ├── README.md ├── unity-native-plugin-sample-profiler ├── Cargo.toml └── src │ └── lib.rs ├── unity-native-plugin-sample ├── Cargo.toml └── src │ └── lib.rs ├── unity-native-plugin-sys ├── Cargo.toml ├── README.md ├── bindgen.sh ├── src │ ├── lib.rs │ └── plugin_api.rs └── wrapper.hpp ├── unity-native-plugin-tester ├── Cargo.toml ├── README.md └── src │ ├── d3d11.rs │ ├── graphics.rs │ ├── interface.rs │ ├── lib.rs │ └── window.rs ├── unity-native-plugin-vulkan ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ └── vulkan.rs └── unity-native-plugin ├── Cargo.toml └── src ├── bitflag.rs ├── d3d11.rs ├── d3d12.rs ├── enums.rs ├── graphics.rs ├── interface.rs ├── lib.rs ├── log.rs ├── memory_manager.rs ├── profiler.rs └── profiler_callbacks.rs /.github/workflows/1-unity-native-plugin-sys.yml: -------------------------------------------------------------------------------- 1 | name: 1. unity-native-plugin-sys 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | publish: 7 | description: "publish (set to \"publish\")" 8 | required: false 9 | default: "" 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | env: 16 | PUBLISH: ${{ github.event.inputs.publish }} 17 | CARGO_REGISTRY_TOKEN: ${{ secrets.CRATESIO_TOKEN }} 18 | MANIFEST_PATH: unity-native-plugin-sys 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: publish dry-run 22 | if: ${{ env.PUBLISH != 'publish' }} 23 | run: | 24 | cargo package --list --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 25 | cargo publish --dry-run --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 26 | - name: publish 27 | if: ${{ env.PUBLISH == 'publish' }} 28 | run: | 29 | cargo publish --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 30 | -------------------------------------------------------------------------------- /.github/workflows/2-unity-native-plugin.yml: -------------------------------------------------------------------------------- 1 | name: 2. unity-native-plugin 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | publish: 7 | description: "publish (set to \"publish\")" 8 | required: false 9 | default: "" 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | env: 16 | PUBLISH: ${{ github.event.inputs.publish }} 17 | CARGO_REGISTRY_TOKEN: ${{ secrets.CRATESIO_TOKEN }} 18 | MANIFEST_PATH: unity-native-plugin 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: publish dry-run 22 | if: ${{ env.PUBLISH != 'publish' }} 23 | run: | 24 | cargo package --list --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 25 | cargo publish --dry-run --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 26 | - name: publish 27 | if: ${{ env.PUBLISH == 'publish' }} 28 | run: | 29 | cargo publish --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 30 | -------------------------------------------------------------------------------- /.github/workflows/3-unity-native-plugin-vulkan.yml: -------------------------------------------------------------------------------- 1 | name: 3. unity-native-plugin-vulkan 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | publish: 7 | description: "publish (set to \"publish\")" 8 | required: false 9 | default: "" 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | env: 16 | PUBLISH: ${{ github.event.inputs.publish }} 17 | CARGO_REGISTRY_TOKEN: ${{ secrets.CRATESIO_TOKEN }} 18 | MANIFEST_PATH: unity-native-plugin-vulkan 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: publish dry-run 22 | if: ${{ env.PUBLISH != 'publish' }} 23 | run: | 24 | cargo package --list --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 25 | cargo publish --dry-run --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 26 | - name: publish 27 | if: ${{ env.PUBLISH == 'publish' }} 28 | run: | 29 | cargo publish --verbose --manifest-path ${{ env.MANIFEST_PATH }}/Cargo.toml 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | unity-native-plugin-sys/include/* 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "unity-native-plugin", 4 | "unity-native-plugin-vulkan", 5 | "unity-native-plugin-sys", 6 | "unity-native-plugin-tester", 7 | "unity-native-plugin-sample", 8 | "unity-native-plugin-sample-profiler", 9 | ] 10 | resolver = "2" 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Unity Native Plugin API for Rust 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) Yasuhiro Taniuchi 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /LICENSE_UnityNativePluginAPI.md: -------------------------------------------------------------------------------- 1 | Unity Native Plugin API copyright © 2015 Unity Technologies ApS 2 | 3 | Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License). 4 | 5 | Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Unity Native Plugin API for Rust 2 | ===== 3 | 4 | [LICENSE (MIT)](LICENSE) 5 | 6 | ## Notice 7 | 8 | * WIP 9 | * Currently supports D3D11, D3D12, Vulkan 10 | * API is not stable. 11 | 12 | ## How to use 13 | 14 | * Define in Cargo.toml 15 | ```cargo 16 | [dependencies] 17 | unity-native-plugin = { version = "*", features = ["d3d11"] } 18 | 19 | # * Support features 20 | # * d3d11 - IUnityGraphicsD3D11 21 | # * d3d12 - IUnityGraphicsD3D12 22 | # * profiler - IUnityProfiler 23 | # * profiler_callbacks - IUnityProfilerCallbacks 24 | ``` 25 | 26 | * If you use Vulkan, define "unity-native-plugin-vulkan" in your dependencies. 27 | ```cargo 28 | [dependencies] 29 | unity-native-plugin = "*" 30 | unity-native-plugin-vulkan = "*" 31 | ``` 32 | 33 | * Use a macro in lib.rs to define your entry points. Without this definition, UnityInterfaces cannot be used. 34 | ```rust 35 | unity_native_plugin::unity_native_plugin_entry_point! { 36 | fn unity_plugin_load(interfaces: &unity_native_plugin::interface::UnityInterfaces) { 37 | // called UnityPluginLoad 38 | } 39 | fn unity_plugin_unload() { 40 | // called UnityPluginUnload 41 | } 42 | } 43 | ``` 44 | 45 | * Use UnityInterface::interface, which is equivalent to IUnityInterfaces::GetInterface, to get the interface. 46 | ```rust 47 | let intf = unity_native_plugin::interface::UnityInterfaces::get() 48 | .interface::(); 49 | ``` 50 | 51 | ## Examples 52 | 53 | * [unity-native-plugin-sample](./unity-native-plugin-sample) 54 | * [Native code (Rust) rendering plugin example for Unity](https://github.com/aosoft/unity-native-rendering-plugin-example-rs) - a port of ["C++ Rendering Plugin example for Unity"](https://github.com/Unity-Technologies/NativeRenderingPlugin) 55 | * [Event tracing example for unity](./unity-native-plugin-sample-profiler) - similar to ["TraceEventProfiler from Unity-Technologies"](https://github.com/Unity-Technologies/TraceEventProfiler) 56 | -------------------------------------------------------------------------------- /unity-native-plugin-sample-profiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unity-native-plugin-sample-profiler" 3 | version = "0.7.0" 4 | authors = ["Yasuhiro Taniuchi"] 5 | edition = "2021" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | unity-native-plugin = { version = "0.7.0", path = "../unity-native-plugin", features = ["profiler_callbacks"] } 15 | unity-native-plugin-sys = { version = "0.7.0", path = "../unity-native-plugin-sys" } 16 | log = "0.4" 17 | env_logger = "0.8" 18 | flume = "0.10" 19 | -------------------------------------------------------------------------------- /unity-native-plugin-sample-profiler/src/lib.rs: -------------------------------------------------------------------------------- 1 | use log::*; 2 | use std::io::*; 3 | use std::num::NonZeroU64; 4 | use std::time::*; 5 | use unity_native_plugin::profiler::*; 6 | use unity_native_plugin::profiler_callbacks::*; 7 | 8 | unity_native_plugin::unity_native_plugin_entry_point! { 9 | fn unity_plugin_load(interfaces: &unity_native_plugin::interface::UnityInterfaces) { 10 | env_logger::try_init().ok(); 11 | 12 | debug!("unity_plugin_load"); 13 | plugin_load(interfaces); 14 | } 15 | 16 | fn unity_plugin_unload() { 17 | debug!("unity_plugin_unload"); 18 | } 19 | } 20 | 21 | #[allow(unused)] 22 | fn plugin_load(interfaces: &unity_native_plugin::interface::UnityInterfaces) { 23 | let profiler_cb = interfaces 24 | .interface::() 25 | .expect("UnityProfilerCallbacks"); 26 | 27 | profiler_cb.register_create_category(Box::new(|desc| { 28 | debug!("create_category: desc={:?}", desc); 29 | })); 30 | 31 | let (sender, receiver) = flume::unbounded::(); 32 | 33 | let start_ts = Instant::now(); 34 | 35 | std::thread::spawn(move || { 36 | let file = std::fs::File::create("profile.log").unwrap(); 37 | let mut writer = std::io::BufWriter::new(file); 38 | 39 | writer.write_all(b"[{}").ok(); 40 | let mut count = 0; 41 | for msg in receiver.iter() { 42 | writer.write_all(msg.as_bytes()).ok(); 43 | count += 1; 44 | 45 | let dt = Instant::now() - start_ts; 46 | if dt.as_secs() > 20 { 47 | info!("stop tracing, duration={:?}, events={}", dt, count); 48 | break; 49 | } 50 | } 51 | writer.write_all(b"]").ok(); 52 | }); 53 | 54 | profiler_cb.register_create_marker(Box::new(move |desc| { 55 | let tid = std::thread::current().id(); 56 | debug!("create_marker: tid={:?}, desc={:?}", tid, desc); 57 | 58 | let flags = desc.flags(); 59 | if flags.has_flag(ProfilerMarkerFlag::ScriptEnterLeave) 60 | || flags.has_flag(ProfilerMarkerFlag::VerbosityInternal) 61 | { 62 | return; 63 | } 64 | 65 | let sender = sender.clone(); 66 | profiler_cb.register_marker_event( 67 | desc, 68 | Box::new(move |desc| { 69 | let ph = match desc.event_type { 70 | ProfilerMarkerEventType::Begin => "B", 71 | ProfilerMarkerEventType::End => "E", 72 | ProfilerMarkerEventType::Single => "i", 73 | _ => { 74 | return; 75 | } 76 | }; 77 | let pid = 1; 78 | let tid: NonZeroU64 = unsafe { std::mem::transmute(std::thread::current().id()) }; 79 | let ts = Instant::now(); 80 | let dt = ts - start_ts; 81 | let cat = desc.desc.category_id(); 82 | let cat: BuiltinProfilerCategory = 83 | if cat <= BuiltinProfilerCategory::VirtualTexturing as u16 { 84 | unsafe { std::mem::transmute(cat) } 85 | } else { 86 | BuiltinProfilerCategory::Other 87 | }; 88 | 89 | sender 90 | .send(format!( 91 | r#",{{"pid":1,"tid":{},"ph":"{}","ts":{},"cat":"{:?}","name":{:?}}} 92 | "#, 93 | tid, 94 | ph, 95 | dt.as_micros(), 96 | cat, 97 | desc.desc.name() 98 | )) 99 | .ok(); 100 | }), 101 | ); 102 | })); 103 | } 104 | -------------------------------------------------------------------------------- /unity-native-plugin-sample/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unity-native-plugin-sample" 3 | version = "0.7.0" 4 | authors = ["Yasuhiro Taniuchi"] 5 | edition = "2021" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | unity-native-plugin = { version = "0.7.0", path = "../unity-native-plugin", features = ["d3d11", "d3d12", "profiler"] } 15 | unity-native-plugin-vulkan = { version = "0.7.0", path = "../unity-native-plugin-vulkan" } 16 | winapi = { version = "0.3.9", features = ["winuser", "d3d11", "dxgiformat"] } 17 | wio = "0.2.2" 18 | 19 | [dev-dependencies] 20 | unity-native-plugin-tester = { version = "0.7.0", path = "../unity-native-plugin-tester", features = ["d3d11"] } 21 | -------------------------------------------------------------------------------- /unity-native-plugin-sample/src/lib.rs: -------------------------------------------------------------------------------- 1 | use winapi::shared::dxgiformat; 2 | use winapi::um::{d3d11, unknwnbase::IUnknown}; 3 | use wio::com::ComPtr; 4 | 5 | unity_native_plugin::unity_native_plugin_entry_point! { 6 | fn unity_plugin_load(interfaces: &unity_native_plugin::interface::UnityInterfaces) { 7 | } 8 | fn unity_plugin_unload() { 9 | } 10 | } 11 | 12 | #[no_mangle] 13 | #[allow(non_snake_case)] 14 | extern "system" fn FillTexture(unity_texture: *mut IUnknown, x: f32, y: f32, z: f32, w: f32) { 15 | unsafe { 16 | if unity_texture.is_null() { 17 | return; 18 | } 19 | let texture = ComPtr::::from_raw(unity_texture); 20 | (&*unity_texture).AddRef(); 21 | let texture = match texture.cast::() { 22 | Ok(t) => t, 23 | Err(_) => return, 24 | }; 25 | 26 | let device = match unity_native_plugin::interface::UnityInterfaces::get() 27 | .interface::() 28 | { 29 | Some(t) => t, 30 | None => return, 31 | } 32 | .device() as *mut d3d11::ID3D11Device; 33 | 34 | let mut dc: *mut d3d11::ID3D11DeviceContext = std::ptr::null_mut(); 35 | (&*device).GetImmediateContext(&mut dc as *mut *mut _); 36 | let dc = ComPtr::from_raw(dc); 37 | 38 | let mut desc: d3d11::D3D11_RENDER_TARGET_VIEW_DESC = std::mem::zeroed(); 39 | desc.Format = dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM; 40 | desc.ViewDimension = d3d11::D3D11_RTV_DIMENSION_TEXTURE2D; 41 | *desc.u.Texture2D_mut() = d3d11::D3D11_TEX2D_RTV { MipSlice: 0 }; 42 | let mut rtv: *mut d3d11::ID3D11RenderTargetView = std::ptr::null_mut(); 43 | if (&*device).CreateRenderTargetView( 44 | texture.as_raw() as *mut d3d11::ID3D11Resource, 45 | &desc, 46 | &mut rtv as *mut *mut _, 47 | ) < 0 48 | { 49 | return; 50 | } 51 | let rtv = ComPtr::from_raw(rtv); 52 | (&*dc).ClearRenderTargetView(rtv.as_raw(), &[x, y, z, w]); 53 | } 54 | } 55 | 56 | #[test] 57 | fn test() { 58 | let instant = std::time::Instant::now(); 59 | unity_native_plugin_tester::d3d11::test_plugin_d3d11( 60 | (256, 256), 61 | |_window, _context| {}, 62 | |_window, context| { 63 | let n = (instant.elapsed().as_millis() % 1000) as f32 / 1000.0; 64 | FillTexture(context.back_buffer().as_raw() as _, 0.0, 0.0, n, 1.0); 65 | unity_native_plugin_tester::window::LoopResult::Continue 66 | }, 67 | |_, _| {}, 68 | unity_plugin_load, 69 | unity_plugin_unload, 70 | ) 71 | .unwrap(); 72 | } 73 | -------------------------------------------------------------------------------- /unity-native-plugin-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unity-native-plugin-sys" 3 | version = "0.7.0" 4 | authors = ["Yasuhiro Taniuchi"] 5 | edition = "2021" 6 | license = "MIT" 7 | description = "unity-native-plugin-sys" 8 | homepage = "https://github.com/aosoft/unity-native-plugin-rs" 9 | repository = "https://github.com/aosoft/unity-native-plugin-rs" 10 | readme = "README.md" 11 | categories = ["api-bindings", "game-engines"] 12 | keywords = ["unity", "ffi"] 13 | include = [ 14 | "**/*.rs", 15 | "Cargo.toml", 16 | "../LICENSE" 17 | ] 18 | 19 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 20 | 21 | [dependencies] 22 | -------------------------------------------------------------------------------- /unity-native-plugin-sys/README.md: -------------------------------------------------------------------------------- 1 | unity-native-plugin-rs 2 | ==== 3 | 4 | * based on Unity 6000.0.10f1 5 | * Vulkan SDK 1.3.283.0 6 | * bindgen 0.69.4 7 | * clang version 14.0.0-1ubuntu1.1 8 | -------------------------------------------------------------------------------- /unity-native-plugin-sys/bindgen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | bindgen \ 4 | --output ./src/plugin_api.rs \ 5 | --with-derive-default \ 6 | --no-derive-debug \ 7 | wrapper.hpp -- -I ./include -I $VULKAN_SDK/Include 8 | sed -i -e "s/extern \""C\""/extern \""system\""/g" ./src/plugin_api.rs 9 | -------------------------------------------------------------------------------- /unity-native-plugin-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | include!("plugin_api.rs"); 5 | 6 | impl UnityInterfaceGUID { 7 | pub fn new( 8 | high: ::std::os::raw::c_ulonglong, 9 | low: ::std::os::raw::c_ulonglong, 10 | ) -> UnityInterfaceGUID { 11 | UnityInterfaceGUID { 12 | m_GUIDHigh: high, 13 | m_GUIDLow: low, 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /unity-native-plugin-sys/wrapper.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define UINT32 uint32_t 5 | #define UINT uint32_t 6 | 7 | #include 8 | #include 9 | 10 | struct ID3D11Device {}; 11 | struct ID3D11Resource {}; 12 | struct ID3D11RenderTargetView {}; 13 | struct ID3D11ShaderResourceView {}; 14 | struct IDXGISwapChain {}; 15 | #include 16 | 17 | typedef std::int32_t D3D12_RESOURCE_STATES; 18 | typedef std::uint64_t UINT64; 19 | struct ID3D12Resource {}; 20 | struct ID3D12Device {}; 21 | struct ID3D12Fence {}; 22 | struct ID3D12GraphicsCommandList {}; 23 | struct ID3D12CommandQueue {}; 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #ifndef NULL 32 | #define NULL nullptr 33 | #endif 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | #define Assert(x) 41 | 42 | #include 43 | #include 44 | -------------------------------------------------------------------------------- /unity-native-plugin-tester/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unity-native-plugin-tester" 3 | version = "0.7.0" 4 | authors = ["Yasuhiro Taniuchi"] 5 | edition = "2021" 6 | license = "MIT" 7 | description = "Unity Native Plugin API Tester Library" 8 | homepage = "https://github.com/aosoft/unity-native-plugin-rs" 9 | repository = "https://github.com/aosoft/unity-native-plugin-tester" 10 | readme = "README.md" 11 | categories = ["api-bindings", "game-engines"] 12 | keywords = ["unity", "ffi"] 13 | include = [ 14 | "**/*.rs", 15 | "Cargo.toml", 16 | "../LICENSE" 17 | ] 18 | publish = false 19 | 20 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 21 | 22 | [features] 23 | default = [] 24 | d3d11 = [] 25 | d3d12 = [] 26 | 27 | [dependencies] 28 | unity-native-plugin-sys = { version = "0.7.0", path = "../unity-native-plugin-sys" } 29 | unity-native-plugin = { version = "0.7.0", path = "../unity-native-plugin", features = ["d3d11", "d3d12"] } 30 | winapi = { version = "0.3.9", features = ["winuser", "dxgi", "d3d11", "dxgiformat", "dxgitype", "d3dcommon"] } 31 | winit = "0.23.0" 32 | wio = "0.2.2" 33 | raw-window-handle = "0.3.3" 34 | 35 | -------------------------------------------------------------------------------- /unity-native-plugin-tester/README.md: -------------------------------------------------------------------------------- 1 | Unity Native Plugin API Tester Library 2 | ==== 3 | 4 | This library is for test runs of native plugin code written in Rust without Unity. 5 | 6 | ## Notice 7 | 8 | It should only be used for testing and debugging of native plugins. 9 | 10 | ## How to use 11 | 12 | * Define in Cargo.toml 13 | * The branch should match the version of "unity-native-plugin" crate. 14 | ```cargo 15 | [dev-dependencies] 16 | unity-native-plugin-tester = { git = "https://github.com/aosoft/unity-native-plugin-tester", branch = "main", features = ["d3d11"] } 17 | 18 | # * Support features 19 | # * d3d11 - IUnityGraphicsD3D11 20 | ``` 21 | 22 | * Write the test code in lib.rs. 23 | ```rust 24 | #[test] 25 | fn test() { 26 | let instant = std::time::Instant::now(); 27 | unity_native_plugin_tester::d3d11::test_plugin_d3d11( 28 | (256, 256), // (a) 29 | |_window, _context| {}, // (b) 30 | |_window, context| { // (c) 31 | let n = (instant.elapsed().as_millis() % 1000) as f32 / 1000.0; 32 | FillTexture(context.back_buffer().as_raw() as _, 0.0, 0.0, n, 1.0); 33 | unity_native_plugin_tester::window::LoopResult::Continue 34 | }, 35 | |_, _| {}, // (d) 36 | unity_plugin_load, // (e) 37 | unity_plugin_unload, // (f) 38 | ) 39 | .unwrap(); 40 | } 41 | ``` 42 | * usage 43 | * (a) Size of the client area (back buffer) 44 | * (b) Initialize function 45 | * (c) Test code function 46 | * (d) Finalize function 47 | * (e) "unity_plugin_load" function (Defined by the unity_native_plugin_entry_point macro) 48 | * (f) "unity_plugin_unload" function (Defined by the unity_native_plugin_entry_point macro) 49 | 50 | * Run the test 51 | ``` 52 | % cargo test test 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /unity-native-plugin-tester/src/d3d11.rs: -------------------------------------------------------------------------------- 1 | use raw_window_handle::HasRawWindowHandle; 2 | use unity_native_plugin::interface::UnityInterface; 3 | use unity_native_plugin_sys::*; 4 | use winapi::shared::{dxgi, dxgiformat, dxgitype, minwindef, winerror}; 5 | use winapi::um::{combaseapi, d3d11, d3dcommon, objbase, winnt}; 6 | use winit::window::Window; 7 | use wio::com::ComPtr; 8 | 9 | pub struct TesterContextGraphicsD3D11 { 10 | device: ComPtr, 11 | interfaces: IUnityGraphicsD3D11, 12 | swap_chain: ComPtr, 13 | back_buffer: ComPtr, 14 | back_buffer_desc: d3d11::D3D11_TEXTURE2D_DESC, 15 | 16 | textures_render_buffer: 17 | std::collections::HashMap>, 18 | textures_native_texture: 19 | std::collections::HashMap>, 20 | rtvs_render_buffer: 21 | std::collections::HashMap>, 22 | srvs_native_texture: 23 | std::collections::HashMap>, 24 | } 25 | 26 | impl TesterContextGraphicsD3D11 { 27 | fn new(window: &Window) -> Result { 28 | unsafe { 29 | let size = window.inner_size(); 30 | let desc = dxgi::DXGI_SWAP_CHAIN_DESC { 31 | BufferDesc: dxgitype::DXGI_MODE_DESC { 32 | Width: size.width, 33 | Height: size.height, 34 | RefreshRate: dxgitype::DXGI_RATIONAL { 35 | Numerator: 60, 36 | Denominator: 1, 37 | }, 38 | Format: dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM, 39 | ScanlineOrdering: dxgitype::DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, 40 | Scaling: dxgitype::DXGI_MODE_SCALING_UNSPECIFIED, 41 | }, 42 | SampleDesc: dxgitype::DXGI_SAMPLE_DESC { 43 | Count: 1, 44 | Quality: 0, 45 | }, 46 | BufferUsage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT, 47 | BufferCount: 2, 48 | OutputWindow: match window.raw_window_handle() { 49 | raw_window_handle::RawWindowHandle::Windows(h) => h.hwnd, 50 | _ => std::ptr::null_mut(), 51 | } as _, 52 | Windowed: minwindef::TRUE, 53 | SwapEffect: dxgi::DXGI_SWAP_EFFECT_DISCARD, 54 | Flags: dxgi::DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH, 55 | }; 56 | 57 | let mut device: *mut d3d11::ID3D11Device = std::ptr::null_mut(); 58 | let mut swap_chain: *mut dxgi::IDXGISwapChain = std::ptr::null_mut(); 59 | 60 | let hr = d3d11::D3D11CreateDeviceAndSwapChain( 61 | std::ptr::null_mut(), 62 | d3dcommon::D3D_DRIVER_TYPE_HARDWARE, 63 | std::ptr::null_mut(), 64 | d3d11::D3D11_CREATE_DEVICE_DEBUG | d3d11::D3D11_CREATE_DEVICE_SINGLETHREADED, 65 | std::ptr::null_mut(), 66 | 0, 67 | d3d11::D3D11_SDK_VERSION, 68 | &desc, 69 | &mut swap_chain, 70 | &mut device, 71 | std::ptr::null_mut(), 72 | std::ptr::null_mut(), 73 | ); 74 | if winerror::SUCCEEDED(hr) { 75 | let mut back_buffer: *mut d3d11::ID3D11Texture2D = std::ptr::null_mut(); 76 | let mut desc = std::mem::zeroed::(); 77 | 78 | (*swap_chain).GetBuffer( 79 | 0, 80 | &d3d11::IID_ID3D11Texture2D, 81 | &mut back_buffer as *mut *mut d3d11::ID3D11Texture2D as _, 82 | ); 83 | if !back_buffer.is_null() { 84 | (*back_buffer).GetDesc(&mut desc); 85 | } 86 | 87 | Ok(TesterContextGraphicsD3D11 { 88 | device: ComPtr::from_raw(device), 89 | swap_chain: ComPtr::from_raw(swap_chain), 90 | back_buffer: ComPtr::from_raw(back_buffer), 91 | back_buffer_desc: desc, 92 | textures_render_buffer: std::collections::HashMap::new(), 93 | textures_native_texture: std::collections::HashMap::new(), 94 | rtvs_render_buffer: std::collections::HashMap::new(), 95 | interfaces: IUnityGraphicsD3D11 { 96 | GetDevice: Some(get_device), 97 | TextureFromRenderBuffer: Some(texture_from_render_buffer), 98 | TextureFromNativeTexture: Some(texture_from_native_texture), 99 | RTVFromRenderBuffer: Some(rtv_from_render_buffer), 100 | SRVFromNativeTexture: Some(srv_from_native_texture), 101 | GetSwapChain: Some(get_swap_chain), 102 | GetSyncInterval: Some(get_sync_interval), 103 | GetPresentFlags: Some(get_present_flags), 104 | }, 105 | srvs_native_texture: std::collections::HashMap::new(), 106 | }) 107 | } else { 108 | Err(hr) 109 | } 110 | } 111 | } 112 | 113 | pub fn device(&self) -> &ComPtr { 114 | &self.device 115 | } 116 | 117 | pub fn swap_chain(&self) -> &ComPtr { 118 | &self.swap_chain 119 | } 120 | 121 | pub fn back_buffer(&self) -> &ComPtr { 122 | &self.back_buffer 123 | } 124 | 125 | pub fn back_buffer_desc(&self) -> &d3d11::D3D11_TEXTURE2D_DESC { 126 | &self.back_buffer_desc 127 | } 128 | 129 | pub fn unity_back_buffer(&self) -> UnityRenderBuffer { 130 | self.back_buffer.as_raw() as _ 131 | } 132 | 133 | pub fn textures_render_buffer( 134 | &self, 135 | ) -> &std::collections::HashMap> { 136 | &self.textures_render_buffer 137 | } 138 | 139 | pub fn textures_render_buffer_mut( 140 | &mut self, 141 | ) -> &mut std::collections::HashMap> { 142 | &mut self.textures_render_buffer 143 | } 144 | 145 | pub fn textures_native_texture( 146 | &self, 147 | ) -> &std::collections::HashMap> { 148 | &self.textures_native_texture 149 | } 150 | 151 | pub fn textures_native_texture_mut( 152 | &mut self, 153 | ) -> &mut std::collections::HashMap> { 154 | &mut self.textures_native_texture 155 | } 156 | 157 | pub fn rtvs_render_buffer( 158 | &self, 159 | ) -> &std::collections::HashMap> { 160 | &self.rtvs_render_buffer 161 | } 162 | 163 | pub fn rtvs_render_buffer_mut( 164 | &mut self, 165 | ) -> &mut std::collections::HashMap> 166 | { 167 | &mut self.rtvs_render_buffer 168 | } 169 | 170 | pub fn srvs_native_texture( 171 | &self, 172 | ) -> &std::collections::HashMap> { 173 | &self.srvs_native_texture 174 | } 175 | 176 | pub fn srvs_native_texture_mut( 177 | &mut self, 178 | ) -> &mut std::collections::HashMap> 179 | { 180 | &mut self.srvs_native_texture 181 | } 182 | } 183 | 184 | impl crate::interface::UnityInterfaceBase for TesterContextGraphicsD3D11 { 185 | fn as_any(&self) -> &dyn std::any::Any { 186 | self 187 | } 188 | 189 | fn get_unity_interface(&self) -> *mut IUnityInterface { 190 | &self.interfaces as *const unity_native_plugin_sys::IUnityGraphicsD3D11 191 | as *mut unity_native_plugin_sys::IUnityInterface 192 | } 193 | } 194 | 195 | impl crate::interface::UnityInterfaceID for TesterContextGraphicsD3D11 { 196 | fn get_interface_guid() -> UnityInterfaceGUID { 197 | unity_native_plugin::d3d11::UnityGraphicsD3D11::get_interface_guid() 198 | } 199 | } 200 | 201 | extern "system" fn get_device() -> *mut ID3D11Device { 202 | unsafe { 203 | crate::interface::get_unity_interface::() 204 | .device() 205 | .as_raw() as _ 206 | } 207 | } 208 | 209 | extern "system" fn texture_from_render_buffer(buffer: UnityRenderBuffer) -> *mut ID3D11Resource { 210 | unsafe { 211 | match crate::interface::get_unity_interface::() 212 | .textures_render_buffer() 213 | .get(&buffer) 214 | { 215 | Some(v) => v.as_raw() as _, 216 | None => std::ptr::null_mut(), 217 | } 218 | } 219 | } 220 | 221 | extern "system" fn texture_from_native_texture(texture: UnityTextureID) -> *mut ID3D11Resource { 222 | unsafe { 223 | match crate::interface::get_unity_interface::() 224 | .textures_native_texture() 225 | .get(&texture) 226 | { 227 | Some(v) => v.as_raw() as _, 228 | None => std::ptr::null_mut(), 229 | } 230 | } 231 | } 232 | 233 | extern "system" fn rtv_from_render_buffer( 234 | surface: UnityRenderBuffer, 235 | ) -> *mut ID3D11RenderTargetView { 236 | unsafe { 237 | match crate::interface::get_unity_interface::() 238 | .rtvs_render_buffer() 239 | .get(&surface) 240 | { 241 | Some(v) => v.as_raw() as _, 242 | None => std::ptr::null_mut(), 243 | } 244 | } 245 | } 246 | 247 | extern "system" fn srv_from_native_texture( 248 | texture: UnityTextureID, 249 | ) -> *mut ID3D11ShaderResourceView { 250 | unsafe { 251 | match crate::interface::get_unity_interface::() 252 | .srvs_native_texture() 253 | .get(&texture) 254 | { 255 | Some(v) => v.as_raw() as _, 256 | None => std::ptr::null_mut(), 257 | } 258 | } 259 | } 260 | 261 | extern "system" fn get_swap_chain() -> *mut IDXGISwapChain { 262 | unsafe { 263 | crate::interface::get_unity_interface::() 264 | .swap_chain() 265 | .as_raw() as _ 266 | } 267 | } 268 | 269 | extern "system" fn get_sync_interval() -> u32 { 270 | 1 271 | } 272 | 273 | extern "system" fn get_present_flags() -> u32 { 274 | 0 275 | } 276 | 277 | /// Running tests for D3D11. 278 | /// 279 | /// * 'TestContextGraphicsD3D11' manages the resources used for testing. 280 | /// * Implement test initialization in the 'fn_init' function. 281 | /// * Set the resource settings for the context. 282 | /// * Implement the test in the 'fn_main' function. 283 | /// * Drawing to 'TestContextGraphicsD3D11::back_buffer()' is displayed in a window. 284 | /// * Returns whether to continue with 'fn_main'. 285 | /// * Implement the finalization process with 'fn_finalize'. 286 | /// * The 'fn_unity_plugin_load' and 'fn_unity_plugin_unload' 287 | /// specify the loading and unloading functions of the plugins specified 288 | /// by the unity_native_plugin_entry_point macro. 289 | /// 290 | /// # Arguments 291 | /// 292 | /// * `client_size` - Size of the client area (back buffer) 293 | /// * `fn_init` - Initialize function 294 | /// * `fn_main` - Test code function 295 | /// * `fn_finalize` - Finalize function 296 | /// * `fn_unity_plugin_load` - "unity_plugin_load" function (Defined by the unity_native_plugin_entry_point macro) 297 | /// * `fn_unity_plugin_unload` - "unity_plugin_unload" function (Defined by the unity_native_plugin_entry_point macro) 298 | /// 299 | pub fn test_plugin_d3d11< 300 | FnInit: FnOnce(&Window, &mut TesterContextGraphicsD3D11), 301 | FnMain: FnMut(&Window, &TesterContextGraphicsD3D11) -> crate::window::LoopResult, 302 | FnFinalize: FnOnce(&Window, &TesterContextGraphicsD3D11), 303 | >( 304 | client_size: (u32, u32), 305 | fn_init: FnInit, 306 | mut fn_main: FnMain, 307 | fn_finalize: FnFinalize, 308 | fn_unity_plugin_load: fn(interfaces: &unity_native_plugin::interface::UnityInterfaces), 309 | fn_unity_plugin_unload: fn(), 310 | ) -> Result<(), winnt::HRESULT> { 311 | unsafe { 312 | objbase::CoInitialize(std::ptr::null_mut()); 313 | } 314 | 315 | crate::interface::initialize_unity_interfaces(); 316 | crate::graphics::initialize_interface(unity_native_plugin::graphics::GfxRenderer::D3D11); 317 | 318 | crate::window::run_window_app( 319 | client_size, 320 | |window| { 321 | let mut ret = TesterContextGraphicsD3D11::new(window).unwrap(); 322 | fn_init(window, &mut ret); 323 | ret 324 | }, 325 | |window, context| { 326 | let ret = fn_main(window, context); 327 | 328 | unsafe { 329 | context.swap_chain().Present(0, 0); 330 | } 331 | ret 332 | }, 333 | fn_finalize, 334 | fn_unity_plugin_load, 335 | fn_unity_plugin_unload, 336 | ); 337 | 338 | crate::interface::finalize_unity_interfaces(); 339 | 340 | unsafe { 341 | combaseapi::CoUninitialize(); 342 | } 343 | 344 | Ok(()) 345 | } 346 | -------------------------------------------------------------------------------- /unity-native-plugin-tester/src/graphics.rs: -------------------------------------------------------------------------------- 1 | use unity_native_plugin::interface::UnityInterface; 2 | use unity_native_plugin_sys::*; 3 | 4 | struct TesterContextGraphics { 5 | renderer: UnityGfxRenderer, 6 | interfaces: IUnityGraphics, 7 | } 8 | 9 | impl TesterContextGraphics { 10 | pub fn new(renderer: unity_native_plugin::graphics::GfxRenderer) -> Self { 11 | TesterContextGraphics { 12 | renderer: renderer as _, 13 | interfaces: IUnityGraphics { 14 | GetRenderer: Some(get_renderer), 15 | RegisterDeviceEventCallback: Some(register_device_event_callback), 16 | UnregisterDeviceEventCallback: Some(unregister_device_event_callback), 17 | ReserveEventIDRange: Some(reserve_event_id_range), 18 | }, 19 | } 20 | } 21 | 22 | pub fn renderer(&self) -> UnityGfxRenderer { 23 | self.renderer 24 | } 25 | } 26 | 27 | impl crate::interface::UnityInterfaceBase for TesterContextGraphics { 28 | fn as_any(&self) -> &dyn std::any::Any { 29 | self 30 | } 31 | 32 | fn get_unity_interface(&self) -> *mut IUnityInterface { 33 | unsafe { std::mem::transmute::<_, _>(&self.interfaces) } 34 | } 35 | } 36 | 37 | impl crate::interface::UnityInterfaceID for TesterContextGraphics { 38 | fn get_interface_guid() -> UnityInterfaceGUID { 39 | unity_native_plugin::graphics::UnityGraphics::get_interface_guid() 40 | } 41 | } 42 | 43 | extern "system" fn get_renderer() -> UnityGfxRenderer { 44 | unsafe { crate::interface::get_unity_interface::().renderer() } 45 | } 46 | 47 | extern "system" fn register_device_event_callback(_: IUnityGraphicsDeviceEventCallback) {} 48 | 49 | extern "system" fn unregister_device_event_callback(_: IUnityGraphicsDeviceEventCallback) {} 50 | 51 | extern "system" fn reserve_event_id_range(_: ::std::os::raw::c_int) -> ::std::os::raw::c_int { 52 | 0 53 | } 54 | 55 | pub fn initialize_interface(renderer: unity_native_plugin::graphics::GfxRenderer) { 56 | unsafe { 57 | crate::interface::get_unity_interfaces().register_interface::(Some( 58 | std::rc::Rc::new(TesterContextGraphics::new(renderer)), 59 | )); 60 | } 61 | } 62 | 63 | #[test] 64 | fn register_graphics() { 65 | crate::interface::initialize_unity_interfaces(); 66 | crate::graphics::initialize_interface(unity_native_plugin::graphics::GfxRenderer::D3D11); 67 | 68 | assert_eq!( 69 | unity_native_plugin::graphics::GfxRenderer::D3D11, 70 | unity_native_plugin::interface::UnityInterfaces::get() 71 | .interface::() 72 | .unwrap() 73 | .renderer() 74 | ); 75 | 76 | crate::interface::finalize_unity_interfaces(); 77 | } 78 | -------------------------------------------------------------------------------- /unity-native-plugin-tester/src/interface.rs: -------------------------------------------------------------------------------- 1 | use std::any::Any; 2 | use std::collections::HashMap; 3 | use std::os::raw::c_ulonglong; 4 | use std::rc::Rc; 5 | use unity_native_plugin_sys::*; 6 | 7 | #[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] 8 | pub struct InfKey { 9 | pub high: c_ulonglong, 10 | pub low: c_ulonglong, 11 | } 12 | 13 | pub trait UnityInterfaceBase { 14 | fn as_any(&self) -> &dyn Any; 15 | fn get_unity_interface(&self) -> *mut IUnityInterface; 16 | } 17 | 18 | pub trait UnityInterfaceID { 19 | fn get_interface_guid() -> UnityInterfaceGUID; 20 | } 21 | 22 | pub struct TesterContextInterfaces { 23 | map: HashMap>, 24 | interfaces: IUnityInterfaces, 25 | } 26 | 27 | impl TesterContextInterfaces { 28 | pub fn new() -> Self { 29 | TesterContextInterfaces { 30 | map: HashMap::>::new(), 31 | interfaces: IUnityInterfaces { 32 | GetInterface: Some(get_interface), 33 | RegisterInterface: Some(register_interface), 34 | GetInterfaceSplit: Some(get_interface_split), 35 | RegisterInterfaceSplit: Some(register_interface_split), 36 | }, 37 | } 38 | } 39 | 40 | pub fn interfaces(&self) -> *mut IUnityInterfaces { 41 | unsafe { std::mem::transmute::<_, _>(&self.interfaces) } 42 | } 43 | 44 | pub fn get_interface(&self, guid: UnityInterfaceGUID) -> Option<&Rc> { 45 | self.get_interface_split(guid.m_GUIDHigh, guid.m_GUIDLow) 46 | } 47 | 48 | pub fn get_interface_split( 49 | &self, 50 | high: ::std::os::raw::c_ulonglong, 51 | low: ::std::os::raw::c_ulonglong, 52 | ) -> Option<&Rc> { 53 | self.map.get(&InfKey { high, low }) 54 | } 55 | 56 | pub fn register_interface( 57 | &mut self, 58 | interface: Option>, 59 | ) { 60 | let guid = T::get_interface_guid(); 61 | self.register_interface_split(guid.m_GUIDHigh, guid.m_GUIDLow, interface); 62 | } 63 | 64 | pub fn register_interface_split( 65 | &mut self, 66 | high: ::std::os::raw::c_ulonglong, 67 | low: ::std::os::raw::c_ulonglong, 68 | interface: Option>, 69 | ) { 70 | if let Some(i) = interface { 71 | self.map.insert(InfKey { high, low }, i); 72 | } else { 73 | self.map.remove(&InfKey { high, low }); 74 | } 75 | } 76 | } 77 | 78 | static mut UNITY_INTERFACES: Option = None; 79 | 80 | extern "system" fn get_interface(guid: UnityInterfaceGUID) -> *mut IUnityInterface { 81 | unsafe { 82 | if let Some(i) = UNITY_INTERFACES.as_ref().unwrap().get_interface(guid) { 83 | i.as_ref().get_unity_interface() 84 | } else { 85 | std::ptr::null_mut() 86 | } 87 | } 88 | } 89 | 90 | extern "system" fn register_interface(_: UnityInterfaceGUID, _: *mut IUnityInterface) {} 91 | 92 | extern "system" fn get_interface_split( 93 | high: ::std::os::raw::c_ulonglong, 94 | low: ::std::os::raw::c_ulonglong, 95 | ) -> *mut IUnityInterface { 96 | unsafe { 97 | if let Some(i) = UNITY_INTERFACES 98 | .as_ref() 99 | .unwrap() 100 | .get_interface_split(high, low) 101 | { 102 | i.as_ref().get_unity_interface() 103 | } else { 104 | std::ptr::null_mut() 105 | } 106 | } 107 | } 108 | 109 | extern "system" fn register_interface_split( 110 | _: ::std::os::raw::c_ulonglong, 111 | _: ::std::os::raw::c_ulonglong, 112 | _: *mut IUnityInterface, 113 | ) { 114 | } 115 | 116 | pub unsafe fn get_unity_interfaces() -> &'static mut TesterContextInterfaces { 117 | unsafe { 118 | UNITY_INTERFACES.as_mut().unwrap() 119 | } 120 | } 121 | 122 | pub unsafe fn get_unity_interface() -> &'static T { 123 | unsafe { 124 | get_unity_interfaces() 125 | .get_interface(T::get_interface_guid()) 126 | .unwrap() 127 | .as_any() 128 | .downcast_ref::() 129 | .unwrap() 130 | } 131 | } 132 | 133 | pub fn initialize_unity_interfaces() { 134 | unsafe { 135 | UNITY_INTERFACES = Some(TesterContextInterfaces::new()); 136 | unity_native_plugin::interface::UnityInterfaces::set_native_unity_interfaces( 137 | crate::interface::get_unity_interfaces().interfaces(), 138 | ); 139 | } 140 | } 141 | 142 | pub fn finalize_unity_interfaces() { 143 | unsafe { 144 | UNITY_INTERFACES = None; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /unity-native-plugin-tester/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod graphics; 2 | pub mod interface; 3 | pub mod window; 4 | 5 | #[cfg(all(feature = "d3d11"))] 6 | pub mod d3d11; 7 | -------------------------------------------------------------------------------- /unity-native-plugin-tester/src/window.rs: -------------------------------------------------------------------------------- 1 | use winit::event::{Event, WindowEvent}; 2 | use winit::event_loop::{ControlFlow, EventLoop}; 3 | use winit::window::{Window, WindowBuilder}; 4 | 5 | use std::ops::Deref; 6 | use winit::platform::desktop::EventLoopExtDesktop; 7 | #[cfg(target_os = "windows")] 8 | use winit::platform::windows::EventLoopExtWindows; 9 | 10 | #[derive(PartialEq, Eq)] 11 | pub enum LoopResult { 12 | /// Continue the loop. The next process is executed immediately. 13 | Continue, 14 | 15 | /// Continue the loop. The next process is executed when a window event occurs. 16 | /// (e.g., moving the mouse over a window) 17 | /// Use when the process to be implemented is high load. 18 | ContinueOnWindowEvent, 19 | 20 | /// End the loop. 21 | Exit, 22 | } 23 | 24 | pub fn run_window_app< 25 | Context: 'static + crate::interface::UnityInterfaceBase + crate::interface::UnityInterfaceID, 26 | FnInit: FnOnce(&Window) -> Context, 27 | FnMain: FnMut(&Window, &Context) -> LoopResult, 28 | FnFinalize: FnOnce(&Window, &Context), 29 | >( 30 | client_size: (u32, u32), 31 | fn_initialize: FnInit, 32 | mut fn_main: FnMain, 33 | fn_finalize: FnFinalize, 34 | fn_unity_plugin_load: fn(interfaces: &unity_native_plugin::interface::UnityInterfaces), 35 | fn_unity_plugin_unload: fn(), 36 | ) { 37 | let mut event_loop = EventLoop::::new_any_thread(); 38 | let window = WindowBuilder::new() 39 | .with_inner_size(winit::dpi::Size::from( 40 | winit::dpi::PhysicalSize::::from(client_size), 41 | )) 42 | .build(&event_loop) 43 | .unwrap(); 44 | 45 | let context = std::rc::Rc::new(fn_initialize(&window)); 46 | unsafe { 47 | crate::interface::get_unity_interfaces() 48 | .register_interface::(Some(context.clone())); 49 | } 50 | 51 | fn_unity_plugin_load(unity_native_plugin::interface::UnityInterfaces::get()); 52 | 53 | let mut last_result = LoopResult::Continue; 54 | event_loop.run_return(|event, _, control_flow| { 55 | let instant = std::time::Instant::now(); 56 | match event { 57 | Event::WindowEvent { window_id, event } => { 58 | if window_id == window.id() { 59 | match event { 60 | WindowEvent::CloseRequested => last_result = LoopResult::Exit, 61 | _ => { 62 | last_result = fn_main(&window, context.deref()); 63 | } 64 | } 65 | } 66 | } 67 | _ => { 68 | if last_result == LoopResult::Continue { 69 | last_result = fn_main(&window, context.deref()); 70 | } 71 | } 72 | } 73 | *control_flow = match last_result { 74 | LoopResult::Continue => { 75 | ControlFlow::WaitUntil(instant + std::time::Duration::from_millis(50)) 76 | } 77 | LoopResult::ContinueOnWindowEvent => ControlFlow::Wait, 78 | _ => ControlFlow::Exit, 79 | }; 80 | }); 81 | 82 | fn_unity_plugin_unload(); 83 | fn_finalize(&window, context.deref()); 84 | } 85 | -------------------------------------------------------------------------------- /unity-native-plugin-vulkan/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unity-native-plugin-vulkan" 3 | version = "0.7.0" 4 | authors = ["Yasuhiro Taniuchi"] 5 | license = "MIT" 6 | description = "Unity Native Plugin API (Vulkan) for Rust" 7 | homepage = "https://github.com/aosoft/unity-native-plugin-rs" 8 | repository = "https://github.com/aosoft/unity-native-plugin-rs" 9 | readme = "README.md" 10 | categories = ["api-bindings", "game-engines"] 11 | keywords = ["unity"] 12 | edition = "2021" 13 | include = [ 14 | "**/*.rs", 15 | "Cargo.toml", 16 | "../LICENSE" 17 | ] 18 | 19 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 20 | 21 | [dependencies] 22 | unity-native-plugin = { version = "0.7.0", path = "../unity-native-plugin" } 23 | unity-native-plugin-sys = { version = "0.7.0", path = "../unity-native-plugin-sys" } 24 | ash = "0.38.0+1.3.281.1" 25 | -------------------------------------------------------------------------------- /unity-native-plugin-vulkan/README.md: -------------------------------------------------------------------------------- 1 | unity-native-plugin-vulkan 2 | ==== 3 | 4 | * Define in Cargo.toml 5 | ```cargo 6 | [dependencies] 7 | unity-native-plugin = "*" 8 | unity-native-plugin-vulkan = "*" 9 | ``` 10 | 11 | See Also: [unity-native-plugin-rs/README.md](../README.md) 12 | 13 | -------------------------------------------------------------------------------- /unity-native-plugin-vulkan/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod vulkan; 2 | -------------------------------------------------------------------------------- /unity-native-plugin-vulkan/src/vulkan.rs: -------------------------------------------------------------------------------- 1 | use ash::vk::Handle; 2 | use unity_native_plugin::define_unity_interface; 3 | use unity_native_plugin::interface::UnityInterface; 4 | use unity_native_plugin_sys::*; 5 | 6 | define_unity_interface!( 7 | UnityGraphicsVulkan, 8 | IUnityGraphicsVulkan, 9 | 0x95355348d4ef4e11_u64, 10 | 0x9789313dfcffcc87_u64 11 | ); 12 | 13 | pub 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 | 20 | pub struct VulkanInstance { 21 | native: UnityVulkanInstance, 22 | } 23 | 24 | impl 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)] 65 | pub 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)] 73 | pub enum VulkanGraphicsQueueAccess { 74 | DontCare = UnityVulkanGraphicsQueueAccess_kUnityVulkanGraphicsQueueAccess_DontCare, 75 | Allow = UnityVulkanGraphicsQueueAccess_kUnityVulkanGraphicsQueueAccess_Allow, 76 | } 77 | 78 | pub struct VulkanPluginEventConfig { 79 | native: UnityVulkanPluginEventConfig, 80 | } 81 | 82 | impl 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 | 96 | pub struct VulkanRecordingState { 97 | native: UnityVulkanRecordingState, 98 | } 99 | 100 | impl 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 | 130 | pub struct VulkanMemory<'a> { 131 | native: &'a UnityVulkanMemory, 132 | } 133 | 134 | impl 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)] 162 | pub enum VulkanResourceAccessMode { 163 | ObserveOnly = UnityVulkanResourceAccessMode_kUnityVulkanResourceAccess_ObserveOnly, 164 | PipelineBarrier = UnityVulkanResourceAccessMode_kUnityVulkanResourceAccess_PipelineBarrier, 165 | Recreate = UnityVulkanResourceAccessMode_kUnityVulkanResourceAccess_Recreate, 166 | } 167 | 168 | pub struct VulkanImage { 169 | native: UnityVulkanImage, 170 | } 171 | 172 | impl 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)] 226 | pub enum VulkanSwapchainMode { 227 | Default = UnityVulkanSwapchainMode_kUnityVulkanSwapchainMode_Default, 228 | Offscreen = UnityVulkanSwapchainMode_kUnityVulkanSwapchainMode_Offscreen, 229 | } 230 | 231 | #[repr(C)] 232 | pub struct VulkanSwapchainConfiguration { 233 | pub mode: VulkanSwapchainMode, 234 | } 235 | 236 | macro_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 { 286 | unsafe { 287 | let mut ret = std::mem::zeroed::(); 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 { 311 | unsafe { 312 | let mut ret = std::mem::zeroed::(); 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 { 341 | unsafe { 342 | let mut ret = std::mem::zeroed::(); 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 { 374 | unsafe { 375 | let mut ret = std::mem::zeroed::(); 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 { 405 | unsafe { 406 | let mut ret = std::mem::zeroed::(); 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 { 466 | unsafe { 467 | let mut ret = std::mem::zeroed::(); 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 | 492 | impl UnityGraphicsVulkan { 493 | impl_vulkan!(); 494 | } 495 | 496 | 497 | define_unity_interface!( 498 | UnityGraphicsVulkanV2, 499 | IUnityGraphicsVulkanV2, 500 | 0xEC39D2F18446C745_u64, 501 | 0xB1A2626641D6B11F_u64 502 | ); 503 | 504 | macro_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 | 528 | impl UnityGraphicsVulkanV2 { 529 | impl_vulkan_v2!(); 530 | } 531 | 532 | 533 | #[cfg(test)] 534 | mod test { 535 | use super::*; 536 | 537 | #[test] 538 | fn size_test() { 539 | assert_eq!( 540 | ::std::mem::size_of::(), 541 | ::std::mem::size_of::() 542 | ); 543 | } 544 | } 545 | -------------------------------------------------------------------------------- /unity-native-plugin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unity-native-plugin" 3 | version = "0.7.0" 4 | authors = ["Yasuhiro Taniuchi"] 5 | license = "MIT" 6 | description = "Unity Native Plugin API for Rust" 7 | homepage = "https://github.com/aosoft/unity-native-plugin-rs" 8 | repository = "https://github.com/aosoft/unity-native-plugin-rs" 9 | readme = "../README.md" 10 | categories = ["api-bindings", "game-engines"] 11 | keywords = ["unity"] 12 | edition = "2021" 13 | include = [ 14 | "**/*.rs", 15 | "Cargo.toml", 16 | "../LICENSE" 17 | ] 18 | 19 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 20 | 21 | [features] 22 | default = [] 23 | d3d11 = [] 24 | d3d12 = [] 25 | profiler = [] 26 | profiler_callbacks = ["profiler"] 27 | 28 | [dependencies] 29 | unity-native-plugin-sys = { version = "0.7.0", path = "../unity-native-plugin-sys" } 30 | -------------------------------------------------------------------------------- /unity-native-plugin/src/bitflag.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! bitflag { 3 | ($flag_type:ident, $flag_enum_type:ty, $flag_value_type:ty) => { 4 | #[derive(Copy, Clone, Debug)] 5 | pub struct $flag_type { 6 | pub flag: $flag_value_type, 7 | } 8 | 9 | impl From<$flag_enum_type> for $flag_type { 10 | fn from(value: $flag_enum_type) -> Self { 11 | $flag_type::new(value) 12 | } 13 | } 14 | 15 | impl From<$flag_value_type> for $flag_type { 16 | fn from(value: $flag_value_type) -> Self { 17 | $flag_type { flag: value } 18 | } 19 | } 20 | 21 | impl Into<$flag_value_type> for $flag_type { 22 | fn into(self) -> $flag_value_type { 23 | self.flag as $flag_value_type 24 | } 25 | } 26 | 27 | impl $flag_type { 28 | pub fn new(flag: $flag_enum_type) -> $flag_type { 29 | $flag_type { flag: flag as $flag_value_type } 30 | } 31 | 32 | pub const fn is_default(&self) -> bool { 33 | self.flag == 0 as $flag_value_type 34 | } 35 | 36 | pub const fn has_flag(&self, flag: $flag_enum_type) -> bool { 37 | (self.flag & flag as $flag_value_type) != 0 38 | } 39 | 40 | pub const fn set_flag(&self, flag: $flag_enum_type) -> $flag_type { 41 | $flag_type { 42 | flag: self.flag | flag as $flag_value_type, 43 | } 44 | } 45 | 46 | pub const fn unset_flag(&self, flag: $flag_enum_type) -> $flag_type { 47 | $flag_type { 48 | flag: self.flag & !(flag as $flag_value_type), 49 | } 50 | } 51 | } 52 | }; 53 | } -------------------------------------------------------------------------------- /unity-native-plugin/src/d3d11.rs: -------------------------------------------------------------------------------- 1 | use crate::define_unity_interface; 2 | use crate::graphics; 3 | use crate::interface::UnityInterface; 4 | 5 | define_unity_interface!( 6 | UnityGraphicsD3D11, 7 | unity_native_plugin_sys::IUnityGraphicsD3D11, 8 | 0xAAB37EF87A87D748_u64, 9 | 0xBF76967F07EFB177_u64 10 | ); 11 | 12 | pub type ComPtr = *mut std::ffi::c_void; 13 | 14 | impl UnityGraphicsD3D11 { 15 | pub unsafe fn device(&self) -> ComPtr { 16 | unsafe { 17 | self.interface().GetDevice.expect("GetDevice")() as ComPtr 18 | } 19 | } 20 | 21 | pub unsafe fn texture_from_render_buffer(&self, buffer: graphics::RenderBuffer) -> ComPtr { 22 | unsafe { 23 | self.interface() 24 | .TextureFromRenderBuffer 25 | .expect("TextureFromRenderBuffer")(buffer) as ComPtr 26 | } 27 | } 28 | 29 | pub unsafe fn texture_from_natvie_texture(&self, texture: graphics::TextureID) -> ComPtr { 30 | unsafe { 31 | self.interface() 32 | .TextureFromNativeTexture 33 | .expect("TextureFromNativeTexture")(texture) as ComPtr 34 | } 35 | } 36 | 37 | pub unsafe fn rtv_from_render_buffer(&self, buffer: graphics::RenderBuffer) -> ComPtr { 38 | unsafe { 39 | self.interface() 40 | .RTVFromRenderBuffer 41 | .expect("RTVFromRenderBuffer")(buffer) as ComPtr 42 | } 43 | } 44 | 45 | pub unsafe fn srv_from_natvie_texture(&self, texture: graphics::TextureID) -> ComPtr { 46 | unsafe { 47 | self.interface() 48 | .SRVFromNativeTexture 49 | .expect("SRVFromNativeTexture")(texture) as ComPtr 50 | } 51 | } 52 | 53 | pub unsafe fn swap_chain(&self) -> ComPtr { 54 | unsafe { 55 | self.interface().GetSwapChain.expect("GetSwapChain")() as ComPtr 56 | } 57 | } 58 | 59 | pub fn sync_interval(&self) -> u32 { 60 | unsafe { 61 | self.interface() 62 | .GetSyncInterval 63 | .expect("GetSyncInterval")() 64 | } 65 | } 66 | 67 | pub fn present_flags(&self) -> u32 { 68 | unsafe { 69 | self.interface() 70 | .GetPresentFlags 71 | .expect("GetPresentFlags")() 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /unity-native-plugin/src/d3d12.rs: -------------------------------------------------------------------------------- 1 | use crate::{bitflag, define_unity_interface}; 2 | use crate::graphics; 3 | use crate::interface::UnityInterface; 4 | use unity_native_plugin_sys::*; 5 | 6 | define_unity_interface!( 7 | UnityGraphicsD3D12, 8 | IUnityGraphicsD3D12, 9 | 0xEF4CEC88A45F4C4C_u64, 10 | 0xBD295B6F2A38D9DE_u64 11 | ); 12 | 13 | pub type ComPtr = *mut std::ffi::c_void; 14 | 15 | #[repr(u32)] 16 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 17 | pub enum GraphicsQueueAccess { 18 | DontCare = UnityD3D12GraphicsQueueAccess_kUnityD3D12GraphicsQueueAccess_DontCare, 19 | Allow = UnityD3D12GraphicsQueueAccess_kUnityD3D12GraphicsQueueAccess_Allow, 20 | } 21 | 22 | #[repr(u32)] 23 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 24 | pub enum EventConfigFlagBit { 25 | EnsurePreviousFrameSubmission = UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_EnsurePreviousFrameSubmission, 26 | FlushCommandBuffers = UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_FlushCommandBuffers, 27 | SyncWorkerThreads = UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_SyncWorkerThreads, 28 | ModifiesCommandBuffersState = UnityD3D12EventConfigFlagBits_kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState, 29 | } 30 | 31 | bitflag!(EventConfigFlagBits, EventConfigFlagBit, u32); 32 | 33 | #[derive(Copy, Clone)] 34 | pub struct PluginEventConfig { 35 | pub graphics_queue_access: GraphicsQueueAccess, 36 | pub flags: EventConfigFlagBits, 37 | pub ensure_active_render_texture_is_bound: bool, 38 | } 39 | 40 | macro_rules! impl_d3d12_v2 { 41 | () => { 42 | pub unsafe fn device(&self) -> ComPtr { 43 | unsafe { 44 | self.interface().GetDevice.expect("GetDevice")() as ComPtr 45 | } 46 | } 47 | 48 | pub unsafe fn frame_fence(&self) -> ComPtr { 49 | unsafe { 50 | self.interface().GetFrameFence.expect("GetFrameFence")() as ComPtr 51 | } 52 | } 53 | 54 | pub fn next_frame_fence_value(&self) -> u64 { 55 | unsafe { 56 | self.interface() 57 | .GetNextFrameFenceValue 58 | .expect("GetNextFrameFenceValue")() as u64 59 | } 60 | } 61 | }; 62 | } 63 | 64 | macro_rules! impl_d3d12 { 65 | () => { 66 | impl_d3d12_v2!(); 67 | 68 | pub unsafe fn command_queue(&self) -> ComPtr { 69 | unsafe { 70 | self.interface().GetCommandQueue.expect("GetCommandQueue")() as ComPtr 71 | } 72 | } 73 | 74 | pub fn resource_state(&self, resource: ComPtr) -> Option { 75 | unsafe { 76 | let mut ret: D3D12_RESOURCE_STATES = D3D12_RESOURCE_STATES::default(); 77 | if self.interface().GetResourceState.expect("GetResourceState")( 78 | resource as *mut ID3D12Resource, 79 | &mut ret as *mut D3D12_RESOURCE_STATES, 80 | ) { 81 | Some(ret) 82 | } else { 83 | None 84 | } 85 | } 86 | } 87 | 88 | pub fn set_resource_state(&self, resource: ComPtr, state: i32) { 89 | unsafe { 90 | self.interface().SetResourceState.expect("SetResourceState")( 91 | resource as *mut ID3D12Resource, 92 | state, 93 | ) 94 | } 95 | } 96 | }; 97 | } 98 | 99 | impl UnityGraphicsD3D12 { 100 | impl_d3d12!(); 101 | } 102 | 103 | define_unity_interface!( 104 | UnityGraphicsD3D12v2, 105 | IUnityGraphicsD3D12v2, 106 | 0xEC39D2F18446C745_u64, 107 | 0xB1A2626641D6B11F_u64 108 | ); 109 | 110 | pub type ResourceState = UnityGraphicsD3D12ResourceState; 111 | 112 | impl UnityGraphicsD3D12v2 { 113 | impl_d3d12_v2!(); 114 | } 115 | 116 | define_unity_interface!( 117 | UnityGraphicsD3D12v3, 118 | IUnityGraphicsD3D12v3, 119 | 0x57C3FAFE59E5E843_u64, 120 | 0xBF4F5998474BB600_u64 121 | ); 122 | 123 | macro_rules! impl_d3d12_v3 { 124 | () => { 125 | impl_d3d12_v2!(); 126 | 127 | pub fn set_physical_video_memory_control_values( 128 | &self, 129 | mem_info: &PhysicalVideoMemoryControlValues, 130 | ) { 131 | unsafe { 132 | self.interface() 133 | .SetPhysicalVideoMemoryControlValues 134 | .expect("SetPhysicalVideoMemoryControlValues")( 135 | mem_info as *const UnityGraphicsD3D12PhysicalVideoMemoryControlValues, 136 | ) 137 | } 138 | } 139 | }; 140 | } 141 | 142 | pub type PhysicalVideoMemoryControlValues = UnityGraphicsD3D12PhysicalVideoMemoryControlValues; 143 | 144 | impl UnityGraphicsD3D12v3 { 145 | impl_d3d12_v3!(); 146 | } 147 | 148 | define_unity_interface!( 149 | UnityGraphicsD3D12v4, 150 | IUnityGraphicsD3D12v4, 151 | 0x498FFCC13EC94006_u64, 152 | 0xB18F8B0FF67778C8_u64 153 | ); 154 | 155 | macro_rules! impl_d3d12_v4 { 156 | () => { 157 | impl_d3d12_v3!(); 158 | 159 | pub unsafe fn command_queue(&self) -> ComPtr { 160 | unsafe { 161 | self.interface().GetCommandQueue.expect("GetCommandQueue")() as ComPtr 162 | } 163 | } 164 | } 165 | } 166 | 167 | impl UnityGraphicsD3D12v4 { 168 | impl_d3d12_v4!(); 169 | } 170 | 171 | define_unity_interface!( 172 | UnityGraphicsD3D12v5, 173 | IUnityGraphicsD3D12v5, 174 | 0xF5C8D8A37D37BC42_u64, 175 | 0xB02DFE93B5064A27_u64 176 | ); 177 | 178 | macro_rules! impl_d3d12_v5 { 179 | () => { 180 | impl_d3d12_v4!(); 181 | 182 | pub unsafe fn texture_from_render_buffer(&self, rb: graphics::RenderBuffer) -> ComPtr { 183 | unsafe { 184 | self.interface() 185 | .TextureFromRenderBuffer 186 | .expect("TextureFromRenderBuffer")(rb) as ComPtr 187 | } 188 | } 189 | } 190 | } 191 | 192 | impl UnityGraphicsD3D12v5 { 193 | impl_d3d12_v5!(); 194 | } 195 | 196 | define_unity_interface!( 197 | UnityGraphicsD3D12v6, 198 | IUnityGraphicsD3D12v6, 199 | 0xA396DCE58CAC4D78_u64, 200 | 0xAFDD9B281F20B840_u64 201 | ); 202 | 203 | macro_rules! impl_d3d12_v6 { 204 | () => { 205 | impl_d3d12_v5!(); 206 | 207 | pub fn configure_event(&self, event_id: i32, plugin_event_config: &PluginEventConfig) { 208 | unsafe { 209 | let cfg = UnityD3D12PluginEventConfig { 210 | graphicsQueueAccess: plugin_event_config.graphics_queue_access as UnityD3D12GraphicsQueueAccess, 211 | flags: plugin_event_config.flags.flag, 212 | ensureActiveRenderTextureIsBound: plugin_event_config.ensure_active_render_texture_is_bound, 213 | }; 214 | self.interface() 215 | .ConfigureEvent 216 | .expect("ConfigureEvent")(event_id, &cfg) 217 | } 218 | } 219 | 220 | pub unsafe fn command_recording_state(&self) -> Option { 221 | unsafe { 222 | let mut state: UnityGraphicsD3D12RecordingState = std::mem::zeroed(); 223 | if self.interface().CommandRecordingState.expect("CommandRecordingState")(&mut state) { 224 | Some(state.commandList as ComPtr) 225 | } else { 226 | None 227 | } 228 | } 229 | } 230 | } 231 | } 232 | impl UnityGraphicsD3D12v6 { 233 | impl_d3d12_v6!(); 234 | } 235 | 236 | define_unity_interface!( 237 | UnityGraphicsD3D12v7, 238 | IUnityGraphicsD3D12v7, 239 | 0x4624B0DA41B64AAC_u64, 240 | 0x915AABCB9BC3F0D3_u64 241 | ); 242 | 243 | macro_rules! impl_d3d12_v7 { 244 | () => { 245 | impl_d3d12_v6!(); 246 | 247 | pub unsafe fn swap_chain(&self) -> crate::d3d11::ComPtr { 248 | unsafe { 249 | self.interface().GetSwapChain.expect("GetSwapChain")() as ComPtr 250 | } 251 | } 252 | 253 | pub fn sync_interval(&self) -> u32 { 254 | unsafe { 255 | self.interface() 256 | .GetSyncInterval 257 | .expect("GetSyncInterval")() 258 | } 259 | } 260 | 261 | pub fn present_flags(&self) -> u32 { 262 | unsafe { 263 | self.interface() 264 | .GetPresentFlags 265 | .expect("GetPresentFlags")() 266 | } 267 | } 268 | } 269 | } 270 | impl UnityGraphicsD3D12v7 { 271 | impl_d3d12_v7!(); 272 | } 273 | -------------------------------------------------------------------------------- /unity-native-plugin/src/enums.rs: -------------------------------------------------------------------------------- 1 | use unity_native_plugin_sys::*; 2 | 3 | #[repr(u32)] 4 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 5 | pub enum RenderingExtEventType { 6 | SetStereoTarget = UnityRenderingExtEventType_kUnityRenderingExtEventSetStereoTarget, 7 | SetStereoEye = UnityRenderingExtEventType_kUnityRenderingExtEventSetStereoEye, 8 | StereoRenderingDone = UnityRenderingExtEventType_kUnityRenderingExtEventStereoRenderingDone, 9 | BeforeDrawCall = UnityRenderingExtEventType_kUnityRenderingExtEventBeforeDrawCall, 10 | AfterDrawCall = UnityRenderingExtEventType_kUnityRenderingExtEventAfterDrawCall, 11 | CustomGrab = UnityRenderingExtEventType_kUnityRenderingExtEventCustomGrab, 12 | CustomBlit = UnityRenderingExtEventType_kUnityRenderingExtEventCustomBlit, 13 | //UpdateTextureBegin = UnityRenderingExtEventType_kUnityRenderingExtEventUpdateTextureBegin, 14 | //UpdateTextureEnd = UnityRenderingExtEventType_kUnityRenderingExtEventUpdateTextureEnd, 15 | UpdateTextureBeginV1 = UnityRenderingExtEventType_kUnityRenderingExtEventUpdateTextureBeginV1, 16 | UpdateTextureEndV1 = UnityRenderingExtEventType_kUnityRenderingExtEventUpdateTextureEndV1, 17 | UpdateTextureBeginV2 = UnityRenderingExtEventType_kUnityRenderingExtEventUpdateTextureBeginV2, 18 | UpdateTextureEndV2 = UnityRenderingExtEventType_kUnityRenderingExtEventUpdateTextureEndV2, 19 | //Count = UnityRenderingExtEventType_kUnityRenderingExtEventCount, 20 | UserEventsStart = UnityRenderingExtEventType_kUnityRenderingExtUserEventsStart, 21 | } 22 | 23 | #[repr(u32)] 24 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 25 | pub enum RenderingExtCustomBlitCommands { 26 | CustomBlitVRFlush = UnityRenderingExtCustomBlitCommands_kUnityRenderingExtCustomBlitVRFlush, 27 | //CustomBlitCount = UnityRenderingExtCustomBlitCommands_kUnityRenderingExtCustomBlitCount, 28 | UserCustomBlitStart = UnityRenderingExtCustomBlitCommands_kUnityRenderingExtUserCustomBlitStart, 29 | } 30 | 31 | #[repr(u32)] 32 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 33 | #[allow(non_camel_case_types)] 34 | pub enum RenderingExtQueryType { 35 | OverrideViewport = UnityRenderingExtQueryType_kUnityRenderingExtQueryOverrideViewport, 36 | OverrideScissor = UnityRenderingExtQueryType_kUnityRenderingExtQueryOverrideScissor, 37 | OverrideVROcclussionMesh = 38 | UnityRenderingExtQueryType_kUnityRenderingExtQueryOverrideVROcclussionMesh, 39 | OverrideVRSinglePass = UnityRenderingExtQueryType_kUnityRenderingExtQueryOverrideVRSinglePass, 40 | KeepOriginalDoubleWideWidth_DEPRECATED = 41 | UnityRenderingExtQueryType_kUnityRenderingExtQueryKeepOriginalDoubleWideWidth_DEPRECATED, 42 | RequestVRFlushCallback = 43 | UnityRenderingExtQueryType_kUnityRenderingExtQueryRequestVRFlushCallback, 44 | OverridePresentFrame = 45 | UnityRenderingExtQueryType_kUnityRenderingExtQueryOverridePresentFrame, 46 | } 47 | 48 | #[repr(u32)] 49 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 50 | #[allow(non_camel_case_types)] 51 | pub enum RenderingExtTextureFormat { 52 | None = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatNone, 53 | //First = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatFirst, 54 | R8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8_SRGB, 55 | R8G8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8_SRGB, 56 | R8G8B8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8_SRGB, 57 | R8G8B8A8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8A8_SRGB, 58 | R8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8_UNorm, 59 | R8G8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8_UNorm, 60 | R8G8B8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8_UNorm, 61 | R8G8B8A8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8A8_UNorm, 62 | R8_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8_SNorm, 63 | R8G8_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8_SNorm, 64 | R8G8B8_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8_SNorm, 65 | R8G8B8A8_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8A8_SNorm, 66 | R8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8_UInt, 67 | R8G8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8_UInt, 68 | R8G8B8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8_UInt, 69 | R8G8B8A8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8A8_UInt, 70 | R8_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8_SInt, 71 | R8G8_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8_SInt, 72 | R8G8B8_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8_SInt, 73 | R8G8B8A8_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR8G8B8A8_SInt, 74 | R16_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16_UNorm, 75 | R16G16_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16_UNorm, 76 | R16G16B16_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16_UNorm, 77 | R16G16B16A16_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16A16_UNorm, 78 | R16_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16_SNorm, 79 | R16G16_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16_SNorm, 80 | R16G16B16_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16_SNorm, 81 | R16G16B16A16_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16A16_SNorm, 82 | R16_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16_UInt, 83 | R16G16_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16_UInt, 84 | R16G16B16_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16_UInt, 85 | R16G16B16A16_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16A16_UInt, 86 | R16_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16_SInt, 87 | R16G16_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16_SInt, 88 | R16G16B16_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16_SInt, 89 | R16G16B16A16_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16A16_SInt, 90 | R32_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32_UInt, 91 | R32G32_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32_UInt, 92 | R32G32B32_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32B32_UInt, 93 | R32G32B32A32_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32B32A32_UInt, 94 | R32_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32_SInt, 95 | R32G32_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32_SInt, 96 | R32G32B32_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32B32_SInt, 97 | R32G32B32A32_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32B32A32_SInt, 98 | R16_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16_SFloat, 99 | R16G16_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16_SFloat, 100 | R16G16B16_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16_SFloat, 101 | R16G16B16A16_SFloat = 102 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR16G16B16A16_SFloat, 103 | R32_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32_SFloat, 104 | R32G32_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32_SFloat, 105 | R32G32B32_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32B32_SFloat, 106 | R32G32B32A32_SFloat = 107 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR32G32B32A32_SFloat, 108 | L8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatL8_UNorm, 109 | A8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA8_UNorm, 110 | A16_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA16_UNorm, 111 | B8G8R8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8_SRGB, 112 | B8G8R8A8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8A8_SRGB, 113 | B8G8R8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8_UNorm, 114 | B8G8R8A8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8A8_UNorm, 115 | B8G8R8_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8_SNorm, 116 | B8G8R8A8_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8A8_SNorm, 117 | B8G8R8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8_UInt, 118 | B8G8R8A8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8A8_UInt, 119 | B8G8R8_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8_SInt, 120 | B8G8R8A8_SInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB8G8R8A8_SInt, 121 | R4G4B4A4_UNormPack16 = 122 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR4G4B4A4_UNormPack16, 123 | B4G4R4A4_UNormPack16 = 124 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB4G4R4A4_UNormPack16, 125 | R5G6B5_UNormPack16 = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR5G6B5_UNormPack16, 126 | B5G6R5_UNormPack16 = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB5G6R5_UNormPack16, 127 | R5G5B5A1_UNormPack16 = 128 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR5G5B5A1_UNormPack16, 129 | B5G5R5A1_UNormPack16 = 130 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB5G5R5A1_UNormPack16, 131 | A1R5G5B5_UNormPack16 = 132 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA1R5G5B5_UNormPack16, 133 | E5B9G9R9_UFloatPack32 = 134 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatE5B9G9R9_UFloatPack32, 135 | B10G11R11_UFloatPack32 = 136 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatB10G11R11_UFloatPack32, 137 | A2B10G10R10_UNormPack32 = 138 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2B10G10R10_UNormPack32, 139 | A2B10G10R10_UIntPack32 = 140 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2B10G10R10_UIntPack32, 141 | A2B10G10R10_SIntPack32 = 142 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2B10G10R10_SIntPack32, 143 | A2R10G10B10_UNormPack32 = 144 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2R10G10B10_UNormPack32, 145 | A2R10G10B10_UIntPack32 = 146 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2R10G10B10_UIntPack32, 147 | A2R10G10B10_SIntPack32 = 148 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2R10G10B10_SIntPack32, 149 | A2R10G10B10_XRSRGBPack32 = 150 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2R10G10B10_XRSRGBPack32, 151 | A2R10G10B10_XRUNormPack32 = 152 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA2R10G10B10_XRUNormPack32, 153 | R10G10B10_XRSRGBPack32 = 154 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR10G10B10_XRSRGBPack32, 155 | R10G10B10_XRUNormPack32 = 156 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR10G10B10_XRUNormPack32, 157 | A10R10G10B10_XRSRGBPack32 = 158 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA10R10G10B10_XRSRGBPack32, 159 | A10R10G10B10_XRUNormPack32 = 160 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA10R10G10B10_XRUNormPack32, 161 | A8R8G8B8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA8R8G8B8_SRGB, 162 | A8R8G8B8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA8R8G8B8_UNorm, 163 | A32R32G32B32_SFloat = 164 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatA32R32G32B32_SFloat, 165 | D16_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatD16_UNorm, 166 | D24_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatD24_UNorm, 167 | D24_UNorm_S8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatD24_UNorm_S8_UInt, 168 | D32_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatD32_SFloat, 169 | D32_SFloat_S8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatD32_SFloat_S8_UInt, 170 | S8_UInt = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatS8_UInt, 171 | RGBA_DXT1_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_DXT1_SRGB, 172 | RGBA_DXT1_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_DXT1_UNorm, 173 | RGBA_DXT3_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_DXT3_SRGB, 174 | RGBA_DXT3_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_DXT3_UNorm, 175 | RGBA_DXT5_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_DXT5_SRGB, 176 | RGBA_DXT5_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_DXT5_UNorm, 177 | R_BC4_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR_BC4_UNorm, 178 | R_BC4_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR_BC4_SNorm, 179 | RG_BC5_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRG_BC5_UNorm, 180 | RG_BC5_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRG_BC5_SNorm, 181 | RGB_BC6H_UFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_BC6H_UFloat, 182 | RGB_BC6H_SFloat = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_BC6H_SFloat, 183 | RGBA_BC7_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_BC7_SRGB, 184 | RGBA_BC7_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_BC7_UNorm, 185 | RGB_PVRTC_2Bpp_SRGB = 186 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_PVRTC_2Bpp_SRGB, 187 | RGB_PVRTC_2Bpp_UNorm = 188 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_PVRTC_2Bpp_UNorm, 189 | RGB_PVRTC_4Bpp_SRGB = 190 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_PVRTC_4Bpp_SRGB, 191 | RGB_PVRTC_4Bpp_UNorm = 192 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_PVRTC_4Bpp_UNorm, 193 | RGBA_PVRTC_2Bpp_SRGB = 194 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_PVRTC_2Bpp_SRGB, 195 | RGBA_PVRTC_2Bpp_UNorm = 196 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_PVRTC_2Bpp_UNorm, 197 | RGBA_PVRTC_4Bpp_SRGB = 198 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_PVRTC_4Bpp_SRGB, 199 | RGBA_PVRTC_4Bpp_UNorm = 200 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_PVRTC_4Bpp_UNorm, 201 | RGB_ETC_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_ETC_UNorm, 202 | RGB_ETC2_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_ETC2_SRGB, 203 | RGB_ETC2_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_ETC2_UNorm, 204 | RGB_A1_ETC2_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_A1_ETC2_SRGB, 205 | RGB_A1_ETC2_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGB_A1_ETC2_UNorm, 206 | RGBA_ETC2_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ETC2_SRGB, 207 | RGBA_ETC2_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ETC2_UNorm, 208 | R_EAC_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR_EAC_UNorm, 209 | R_EAC_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatR_EAC_SNorm, 210 | RG_EAC_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRG_EAC_UNorm, 211 | RG_EAC_SNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRG_EAC_SNorm, 212 | RGBA_ASTC4X4_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC4X4_SRGB, 213 | RGBA_ASTC4X4_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC4X4_UNorm, 214 | RGBA_ASTC5X5_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC5X5_SRGB, 215 | RGBA_ASTC5X5_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC5X5_UNorm, 216 | RGBA_ASTC6X6_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC6X6_SRGB, 217 | RGBA_ASTC6X6_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC6X6_UNorm, 218 | RGBA_ASTC8X8_SRGB = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC8X8_SRGB, 219 | RGBA_ASTC8X8_UNorm = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC8X8_UNorm, 220 | RGBA_ASTC10X10_SRGB = 221 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC10X10_SRGB, 222 | RGBA_ASTC10X10_UNorm = 223 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC10X10_UNorm, 224 | RGBA_ASTC12X12_SRGB = 225 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC12X12_SRGB, 226 | RGBA_ASTC12X12_UNorm = 227 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC12X12_UNorm, 228 | YUV2 = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatYUV2, 229 | RGBA_ASTC4X4_UFloat = 230 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC4X4_UFloat, 231 | RGBA_ASTC5X5_UFloat = 232 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC5X5_UFloat, 233 | RGBA_ASTC6X6_UFloat = 234 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC6X6_UFloat, 235 | RGBA_ASTC8X8_UFloat = 236 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC8X8_UFloat, 237 | RGBA_ASTC10X10_UFloat = 238 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC10X10_UFloat, 239 | RGBA_ASTC12X12_UFloat = 240 | UnityRenderingExtTextureFormat_kUnityRenderingExtFormatRGBA_ASTC12X12_UFloat, 241 | //Last = UnityRenderingExtTextureFormat_kUnityRenderingExtFormatLast, 242 | } 243 | 244 | #[repr(u32)] 245 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 246 | pub enum ShaderCompilerExtCompilerPlatform { 247 | Unused0 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused0, 248 | Unused1 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused1, 249 | Unused2 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused2, 250 | Unused3 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused3, 251 | D3D11 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformD3D11, 252 | Unused6 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused6, 253 | Unused7 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused7, 254 | Unused8 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused8, 255 | GLES3Plus = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformGLES3Plus, 256 | Unused10 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused10, 257 | PS4 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformPS4, 258 | XboxOne = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformXboxOne, 259 | Unused13 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused13, 260 | Metal = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformMetal, 261 | OpenGLCore = 262 | UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformOpenGLCore, 263 | Unused16 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused16, 264 | Unused17 = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformUnused17, 265 | Vulkan = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformVulkan, 266 | Switch = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformSwitch, 267 | XboxOneD3D12 = 268 | UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformXboxOneD3D12, 269 | //Count = UnityShaderCompilerExtCompilerPlatform_kUnityShaderCompilerExtCompPlatformCount, 270 | } 271 | 272 | #[repr(u32)] 273 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 274 | pub enum ShaderCompilerExtShaderType { 275 | None = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderNone, 276 | Vertex = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderVertex, 277 | Fragment = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderFragment, 278 | Geometry = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderGeometry, 279 | Hull = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderHull, 280 | Domain = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderDomain, 281 | RayTracing = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderRayTracing, 282 | //Count = UnityShaderCompilerExtShaderType_kUnityShaderCompilerExtShaderTypeCount, 283 | } 284 | 285 | #[repr(u32)] 286 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 287 | pub enum ShaderCompilerExtGPUProgramType { 288 | Unknown = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetUnknown, 289 | GLLegacy = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLLegacy, 290 | GLES31AEP = 291 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLES31AEP, 292 | GLES31 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLES31, 293 | GLES3 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLES3, 294 | GLES = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLES, 295 | GLCore32 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLCore32, 296 | GLCore41 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLCore41, 297 | GLCore43 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetGLCore43, 298 | DX9VertexSM20 = 299 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX9VertexSM20, 300 | DX9VertexSM30 = 301 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX9VertexSM30, 302 | DX9PixelSM20 = 303 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX9PixelSM20, 304 | DX9PixelSM30 = 305 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX9PixelSM30, 306 | DX10Level9Vertex = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX10Level9Vertex, 307 | DX10Level9Pixel = 308 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX10Level9Pixel, 309 | DX11VertexSM40 = 310 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11VertexSM40, 311 | DX11VertexSM50 = 312 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11VertexSM50, 313 | DX11PixelSM40 = 314 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11PixelSM40, 315 | DX11PixelSM50 = 316 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11PixelSM50, 317 | DX11GeometrySM40 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11GeometrySM40, 318 | DX11GeometrySM50 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11GeometrySM50, 319 | DX11HullSM50 = 320 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11HullSM50, 321 | DX11DomainSM50 = 322 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetDX11DomainSM50, 323 | MetalVS = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetMetalVS, 324 | MetalFS = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetMetalFS, 325 | SPIRV = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetSPIRV, 326 | Unused1 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetUnused1, 327 | Unused2 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetUnused2, 328 | Unused3 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetUnused3, 329 | Unused4 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetUnused4, 330 | Unused5 = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetUnused5, 331 | RayTracing = 332 | UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetRayTracing, 333 | Count = UnityShaderCompilerExtGPUProgramType_kUnityShaderCompilerExtGPUProgramTargetCount, 334 | } 335 | 336 | #[repr(u32)] 337 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 338 | pub enum ShaderCompilerExtGPUProgram { 339 | VS = UnityShaderCompilerExtGPUProgram_kUnityShaderCompilerExtGPUProgramVS, 340 | PS = UnityShaderCompilerExtGPUProgram_kUnityShaderCompilerExtGPUProgramPS, 341 | GS = UnityShaderCompilerExtGPUProgram_kUnityShaderCompilerExtGPUProgramGS, 342 | HS = UnityShaderCompilerExtGPUProgram_kUnityShaderCompilerExtGPUProgramHS, 343 | DS = UnityShaderCompilerExtGPUProgram_kUnityShaderCompilerExtGPUProgramDS, 344 | Custom = UnityShaderCompilerExtGPUProgram_kUnityShaderCompilerExtGPUProgramCustom, 345 | } 346 | 347 | #[repr(u32)] 348 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 349 | pub enum ShaderCompilerExtEventType { 350 | CreateCustomSourceVariant = 351 | UnityShaderCompilerExtEventType_kUnityShaderCompilerExtEventCreateCustomSourceVariant, 352 | CreateCustomSourceVariantCleanup = UnityShaderCompilerExtEventType_kUnityShaderCompilerExtEventCreateCustomSourceVariantCleanup, 353 | CreateCustomBinaryVariant = 354 | UnityShaderCompilerExtEventType_kUnityShaderCompilerExtEventCreateCustomBinaryVariant, 355 | CreateCustomBinaryVariantCleanup = UnityShaderCompilerExtEventType_kUnityShaderCompilerExtEventCreateCustomBinaryVariantCleanup, 356 | PluginConfigure = UnityShaderCompilerExtEventType_kUnityShaderCompilerExtEventPluginConfigure, 357 | //Count = UnityShaderCompilerExtEventType_kUnityShaderCompilerExtEventCount, 358 | UserEventsStart = UnityShaderCompilerExtEventType_kUnityShaderCompilerExtUserEventsStart, 359 | } 360 | -------------------------------------------------------------------------------- /unity-native-plugin/src/graphics.rs: -------------------------------------------------------------------------------- 1 | use crate::define_unity_interface; 2 | use crate::interface::UnityInterface; 3 | use unity_native_plugin_sys::*; 4 | 5 | pub type RenderBuffer = unity_native_plugin_sys::UnityRenderBuffer; 6 | pub type TextureID = unity_native_plugin_sys::UnityTextureID; 7 | pub type RenderingEvent = unity_native_plugin_sys::UnityRenderingEvent; 8 | pub type RenderingEventAndData = unity_native_plugin_sys::UnityRenderingEventAndData; 9 | 10 | #[repr(u32)] 11 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 12 | pub enum GfxRenderer { 13 | D3D11 = UnityGfxRenderer_kUnityGfxRendererD3D11, 14 | Null = UnityGfxRenderer_kUnityGfxRendererNull, 15 | OpenGLES20 = 8, // OpenGL ES 2.0, removed 16 | OpenGLES30 = UnityGfxRenderer_kUnityGfxRendererOpenGLES30, 17 | PS4 = UnityGfxRenderer_kUnityGfxRendererPS4, 18 | XboxOne = UnityGfxRenderer_kUnityGfxRendererXboxOne, 19 | Metal = UnityGfxRenderer_kUnityGfxRendererMetal, 20 | OpenGLCore = UnityGfxRenderer_kUnityGfxRendererOpenGLCore, 21 | D3D12 = UnityGfxRenderer_kUnityGfxRendererD3D12, 22 | Vulkan = UnityGfxRenderer_kUnityGfxRendererVulkan, 23 | Nvn = UnityGfxRenderer_kUnityGfxRendererNvn, 24 | XboxOneD3D12 = UnityGfxRenderer_kUnityGfxRendererXboxOneD3D12, 25 | GameCoreXboxOne = UnityGfxRenderer_kUnityGfxRendererGameCoreXboxOne, 26 | GameCoreXboxSeries = UnityGfxRenderer_kUnityGfxRendererGameCoreXboxSeries, 27 | PS5 = UnityGfxRenderer_kUnityGfxRendererPS5, 28 | PS5NGGC = UnityGfxRenderer_kUnityGfxRendererPS5NGGC, 29 | ReservedCFE = UnityGfxRenderer_kUnityGfxRendererReservedCFE, 30 | } 31 | 32 | #[repr(u32)] 33 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 34 | pub enum GfxDeviceEventType { 35 | Initialize = UnityGfxDeviceEventType_kUnityGfxDeviceEventInitialize, 36 | Shutdown = UnityGfxDeviceEventType_kUnityGfxDeviceEventShutdown, 37 | BeforeReset = UnityGfxDeviceEventType_kUnityGfxDeviceEventBeforeReset, 38 | AfterReset = UnityGfxDeviceEventType_kUnityGfxDeviceEventAfterReset, 39 | } 40 | 41 | define_unity_interface!( 42 | UnityGraphics, 43 | IUnityGraphics, 44 | 0x7CBA0A9CA4DDB544_u64, 45 | 0x8C5AD4926EB17B11_u64 46 | ); 47 | 48 | pub type GraphicsDeviceEventCallback = extern "system" fn(eventType: GfxDeviceEventType); 49 | 50 | impl UnityGraphics { 51 | pub fn renderer(&self) -> GfxRenderer { 52 | unsafe { 53 | match self.interface().GetRenderer { 54 | Some(intf) => std::mem::transmute(intf()), 55 | None => GfxRenderer::Null, 56 | } 57 | } 58 | } 59 | 60 | pub fn register_device_event_callback(&self, callback: Option) { 61 | unsafe { 62 | if let Some(intf) = self.interface().RegisterDeviceEventCallback { 63 | intf(std::mem::transmute(callback)); 64 | } 65 | } 66 | } 67 | 68 | pub fn unregister_device_event_callback(&self, callback: Option) { 69 | unsafe { 70 | if let Some(intf) = self.interface().UnregisterDeviceEventCallback { 71 | intf(std::mem::transmute(callback)); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /unity-native-plugin/src/interface.rs: -------------------------------------------------------------------------------- 1 | use unity_native_plugin_sys::*; 2 | 3 | pub trait UnityInterface { 4 | fn get_interface_guid() -> UnityInterfaceGUID; 5 | fn new(interface: *const IUnityInterface) -> Self; 6 | } 7 | 8 | static mut UNITY_INTERFACES: Option = None; 9 | 10 | pub struct UnityInterfaces { 11 | interfaces: *mut unity_native_plugin_sys::IUnityInterfaces, 12 | } 13 | 14 | impl UnityInterfaces { 15 | pub fn get() -> &'static UnityInterfaces { 16 | unsafe { UNITY_INTERFACES.as_ref().unwrap() } 17 | } 18 | 19 | pub fn set_native_unity_interfaces(interfaces: *mut unity_native_plugin_sys::IUnityInterfaces) { 20 | unsafe { 21 | UNITY_INTERFACES = if !interfaces.is_null() { 22 | Some(UnityInterfaces { interfaces }) 23 | } else { 24 | None 25 | } 26 | } 27 | } 28 | 29 | pub fn interface(&self) -> Option { 30 | unsafe { 31 | if let Some(intf) = (&*self.interfaces).GetInterfaceSplit { 32 | let guid = T::get_interface_guid(); 33 | let r = intf(guid.m_GUIDHigh, guid.m_GUIDLow); 34 | if !r.is_null() { 35 | return Some(T::new(r)); 36 | } 37 | } 38 | None 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /unity-native-plugin/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "d3d11")] 2 | pub mod d3d11; 3 | 4 | #[cfg(feature = "d3d12")] 5 | pub mod d3d12; 6 | 7 | #[cfg(feature = "profiler")] 8 | pub mod profiler; 9 | 10 | #[cfg(feature = "profiler_callbacks")] 11 | pub mod profiler_callbacks; 12 | 13 | pub mod enums; 14 | pub mod graphics; 15 | pub mod interface; 16 | pub mod log; 17 | pub mod memory_manager; 18 | mod bitflag; 19 | 20 | pub type IUnityInterfaces = unity_native_plugin_sys::IUnityInterfaces; 21 | 22 | #[macro_export] 23 | macro_rules! unity_native_plugin_entry_point { 24 | {fn $method_load:ident($p:ident : $t:ty) $body_load:block 25 | fn $method_unload:ident() $body_unload:block} => { 26 | #[allow(unused_variables)] 27 | fn $method_load($p: $t) $body_load 28 | fn $method_unload() $body_unload 29 | 30 | #[no_mangle] 31 | #[allow(non_snake_case)] 32 | extern "system" fn UnityPluginLoad( 33 | interfaces: *mut unity_native_plugin::IUnityInterfaces, 34 | ) { 35 | unity_native_plugin::interface::UnityInterfaces::set_native_unity_interfaces(interfaces); 36 | $method_load(unity_native_plugin::interface::UnityInterfaces::get()); 37 | } 38 | 39 | #[no_mangle] 40 | #[allow(non_snake_case)] 41 | extern "system" fn UnityPluginUnload() { 42 | $method_unload(); 43 | unity_native_plugin::interface::UnityInterfaces::set_native_unity_interfaces(std::ptr::null_mut()); 44 | } 45 | } 46 | } 47 | 48 | #[macro_export] 49 | macro_rules! define_unity_interface { 50 | ($s:ident, $intf:ty, $guid_high:expr, $guid_low:expr) => { 51 | #[derive(Clone, Copy)] 52 | pub struct $s { 53 | interface: *const $intf, 54 | } 55 | 56 | // unity plugin interface should be thread-safe 57 | unsafe impl Send for $s {} 58 | unsafe impl Sync for $s {} 59 | 60 | impl UnityInterface for $s { 61 | fn get_interface_guid() -> unity_native_plugin_sys::UnityInterfaceGUID { 62 | unity_native_plugin_sys::UnityInterfaceGUID::new($guid_high, $guid_low) 63 | } 64 | 65 | fn new(interface: *const unity_native_plugin_sys::IUnityInterface) -> Self { 66 | $s { 67 | interface: interface as *const $intf, 68 | } 69 | } 70 | } 71 | 72 | impl $s { 73 | #[allow(dead_code)] 74 | #[inline] 75 | fn interface(&self) -> &$intf { 76 | unsafe { &*self.interface } 77 | } 78 | } 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /unity-native-plugin/src/log.rs: -------------------------------------------------------------------------------- 1 | use crate::define_unity_interface; 2 | use crate::interface::UnityInterface; 3 | use std::ffi::CStr; 4 | use unity_native_plugin_sys::*; 5 | 6 | #[repr(u32)] 7 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 8 | pub enum LogType 9 | { 10 | Error = UnityLogType_kUnityLogTypeError, 11 | Warning = UnityLogType_kUnityLogTypeWarning, 12 | Log = UnityLogType_kUnityLogTypeLog, 13 | Exception = UnityLogType_kUnityLogTypeException, 14 | } 15 | 16 | define_unity_interface!( 17 | UnityLog, 18 | IUnityLog, 19 | 0x9E7507fA5B444D5D_u64, 20 | 0x92FB979515EA83FC_u64 21 | ); 22 | 23 | impl UnityLog { 24 | pub fn log(&self, log_type: LogType, message: &CStr, file_name: &CStr, file_line: i32) { 25 | unsafe { 26 | self.interface().Log.expect("Log")(log_type as UnityLogType, message.as_ptr(), file_name.as_ptr(), file_line); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /unity-native-plugin/src/memory_manager.rs: -------------------------------------------------------------------------------- 1 | use crate::define_unity_interface; 2 | use crate::interface::UnityInterface; 3 | use std::ffi::{c_void, CStr}; 4 | use std::ptr::null_mut; 5 | use unity_native_plugin_sys::*; 6 | 7 | 8 | define_unity_interface!( 9 | UnityMemoryManager, 10 | IUnityMemoryManager, 11 | 0xBAF9E57C61A811EC_u64, 12 | 0xC5A7CC7861A811EC_u64 13 | ); 14 | 15 | pub struct UnityAllocator { 16 | allocator: *mut unity_native_plugin_sys::UnityAllocator, 17 | memory_manager: UnityMemoryManager, 18 | } 19 | 20 | impl Drop for UnityAllocator { 21 | fn drop(&mut self) { 22 | unsafe { 23 | self.memory_manager.destroy_allocator(self.allocator); 24 | } 25 | } 26 | } 27 | 28 | impl UnityAllocator { 29 | pub unsafe fn allocate(&self, 30 | size: usize, 31 | align: usize, 32 | file: &CStr, 33 | line: i32) -> *mut c_void { 34 | unsafe { 35 | self.memory_manager.allocate(self.allocator, size, align, file, line) 36 | } 37 | } 38 | 39 | pub unsafe fn deallocate(&self, 40 | ptr: *mut c_void, 41 | file: &CStr, 42 | line: i32) { 43 | unsafe { 44 | self.memory_manager.deallocate(self.allocator, ptr, file, line) 45 | } 46 | } 47 | 48 | pub unsafe fn reallocate(&self, 49 | ptr: *mut c_void, 50 | size: usize, 51 | align: usize, 52 | file: &CStr, 53 | line: i32) -> *mut c_void { 54 | unsafe { 55 | self.memory_manager.reallocate(self.allocator, ptr, size, align, file, line) 56 | } 57 | } 58 | } 59 | 60 | impl UnityMemoryManager { 61 | pub unsafe fn create_allocator(&self, area_name: &CStr, object_name: &CStr) -> Option { 62 | unsafe { 63 | let allocator = self.interface().CreateAllocator.expect("CreateAllocator")(area_name.as_ptr(), object_name.as_ptr()); 64 | if allocator != null_mut() { 65 | Some(UnityAllocator { allocator: allocator, memory_manager: self.clone() }) 66 | } else { 67 | None 68 | } 69 | } 70 | } 71 | 72 | pub(crate) unsafe fn destroy_allocator(&self, allocator: *mut unity_native_plugin_sys::UnityAllocator) { 73 | unsafe { 74 | self.interface().DestroyAllocator.expect("DestroyAllocator")(allocator) 75 | } 76 | } 77 | 78 | pub(crate) unsafe fn allocate(&self, 79 | allocator: *mut unity_native_plugin_sys::UnityAllocator, 80 | size: usize, 81 | align: usize, 82 | file: &CStr, 83 | line: i32) -> *mut c_void { 84 | unsafe { 85 | self.interface().Allocate.expect("Allocate")(allocator, size, align, file.as_ptr(), line) 86 | } 87 | } 88 | 89 | pub(crate) unsafe fn deallocate(&self, 90 | allocator: *mut unity_native_plugin_sys::UnityAllocator, 91 | ptr: *mut c_void, 92 | file: &CStr, 93 | line: i32) { 94 | unsafe { 95 | self.interface().Deallocate.expect("Deallocate")(allocator, ptr, file.as_ptr(), line) 96 | } 97 | } 98 | 99 | pub(crate) unsafe fn reallocate(&self, 100 | allocator: *mut unity_native_plugin_sys::UnityAllocator, 101 | ptr: *mut c_void, 102 | size: usize, 103 | align: usize, 104 | file: &CStr, 105 | line: i32) -> *mut c_void { 106 | unsafe { 107 | self.interface().Reallocate.expect("Reallocate")(allocator, ptr, size, align, file.as_ptr(), line) 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /unity-native-plugin/src/profiler.rs: -------------------------------------------------------------------------------- 1 | use std::ptr::null_mut; 2 | use crate::define_unity_interface; 3 | use crate::interface::UnityInterface; 4 | use crate::bitflag; 5 | use unity_native_plugin_sys::*; 6 | 7 | define_unity_interface!( 8 | UnityProfiler, 9 | IUnityProfiler, 10 | 0x2CE79ED8316A4833_u64, 11 | 0x87076B2013E1571F_u64 12 | ); 13 | 14 | #[repr(u16)] 15 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 16 | pub enum BuiltinProfilerCategory { 17 | Render = UnityBuiltinProfilerCategory__kUnityProfilerCategoryRender as u16, 18 | Scripts = UnityBuiltinProfilerCategory__kUnityProfilerCategoryScripts as u16, 19 | ManagedJobs = UnityBuiltinProfilerCategory__kUnityProfilerCategoryManagedJobs as u16, 20 | BurstJobs = UnityBuiltinProfilerCategory__kUnityProfilerCategoryBurstJobs as u16, 21 | GUI = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGUI as u16, 22 | Physics = UnityBuiltinProfilerCategory__kUnityProfilerCategoryPhysics as u16, 23 | Animation = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAnimation as u16, 24 | AI = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAI as u16, 25 | Audio = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAudio as u16, 26 | AudioJob = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAudioJob as u16, 27 | AudioUpdateJob = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAudioUpdateJob as u16, 28 | Video = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVideo as u16, 29 | Particles = UnityBuiltinProfilerCategory__kUnityProfilerCategoryParticles as u16, 30 | Gi = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGi as u16, 31 | Network = UnityBuiltinProfilerCategory__kUnityProfilerCategoryNetwork as u16, 32 | Loading = UnityBuiltinProfilerCategory__kUnityProfilerCategoryLoading as u16, 33 | Other = UnityBuiltinProfilerCategory__kUnityProfilerCategoryOther as u16, 34 | GC = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGC as u16, 35 | VSync = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVSync as u16, 36 | Overhead = UnityBuiltinProfilerCategory__kUnityProfilerCategoryOverhead as u16, 37 | PlayerLoop = UnityBuiltinProfilerCategory__kUnityProfilerCategoryPlayerLoop as u16, 38 | Director = UnityBuiltinProfilerCategory__kUnityProfilerCategoryDirector as u16, 39 | VR = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVR as u16, 40 | Allocation = UnityBuiltinProfilerCategory__kUnityProfilerCategoryAllocation as u16, 41 | Internal = UnityBuiltinProfilerCategory__kUnityProfilerCategoryInternal as u16, 42 | FileIO = UnityBuiltinProfilerCategory__kUnityProfilerCategoryFileIO as u16, 43 | UISystemLayout = UnityBuiltinProfilerCategory__kUnityProfilerCategoryUISystemLayout as u16, 44 | UISystemRender = UnityBuiltinProfilerCategory__kUnityProfilerCategoryUISystemRender as u16, 45 | VFX = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVFX as u16, 46 | BuildInterface = UnityBuiltinProfilerCategory__kUnityProfilerCategoryBuildInterface as u16, 47 | Input = UnityBuiltinProfilerCategory__kUnityProfilerCategoryInput as u16, 48 | VirtualTexturing = UnityBuiltinProfilerCategory__kUnityProfilerCategoryVirtualTexturing as u16, 49 | GPU = UnityBuiltinProfilerCategory__kUnityProfilerCategoryGPU as u16, 50 | Physics2D = UnityBuiltinProfilerCategory__kUnityProfilerCategoryPhysics2D as u16, 51 | NetworkOperations = UnityBuiltinProfilerCategory__kUnityProfilerCategoryNetworkOperations as u16, 52 | UIDetails = UnityBuiltinProfilerCategory__kUnityProfilerCategoryUIDetails as u16, 53 | Debug = UnityBuiltinProfilerCategory__kUnityProfilerCategoryDebug as u16, 54 | Jobs = UnityBuiltinProfilerCategory__kUnityProfilerCategoryJobs as u16, 55 | Text = UnityBuiltinProfilerCategory__kUnityProfilerCategoryText as u16, 56 | } 57 | 58 | pub type ProfilerCategoryId = UnityProfilerCategoryId; 59 | 60 | #[repr(u16)] 61 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 62 | pub enum ProfilerMarkerFlag { 63 | Default = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagDefault as u16, 64 | ScriptUser = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptUser as u16, 65 | ScriptInvoke = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptInvoke as u16, 66 | ScriptEnterLeave = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptEnterLeave as u16, 67 | AvailabilityEditor = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityEditor as u16, 68 | AvailabilityNonDev = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityNonDev as u16, 69 | Warning = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagWarning as u16, 70 | Counter = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagCounter as u16, 71 | VerbosityDebug = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityDebug as u16, 72 | VerbosityInternal = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityInternal as u16, 73 | VerbosityAdvanced = UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityAdvanced as u16, 74 | } 75 | 76 | bitflag!(ProfilerMarkerFlags, ProfilerMarkerFlag, UnityProfilerMarkerFlags); 77 | 78 | 79 | #[repr(u16)] 80 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 81 | pub enum ProfilerMarkerEventType { 82 | Begin = UnityProfilerMarkerEventType__kUnityProfilerMarkerEventTypeBegin as u16, 83 | End = UnityProfilerMarkerEventType__kUnityProfilerMarkerEventTypeEnd as u16, 84 | Single = UnityProfilerMarkerEventType__kUnityProfilerMarkerEventTypeSingle as u16, 85 | } 86 | 87 | impl ProfilerMarkerEventType { 88 | pub fn from(value: u16) -> Option { 89 | use ProfilerMarkerEventType::*; 90 | if value <= Single as u16 { 91 | Some(unsafe { std::mem::transmute(value) }) 92 | } else { 93 | None 94 | } 95 | } 96 | } 97 | 98 | pub type ProfilerMarkerId = UnityProfilerMarkerId; 99 | 100 | #[derive(Clone)] 101 | pub struct ProfilerMarkerDesc { 102 | pub(crate) native: *const UnityProfilerMarkerDesc, 103 | } 104 | 105 | unsafe impl Send for ProfilerMarkerDesc {} 106 | 107 | impl std::fmt::Debug for ProfilerMarkerDesc { 108 | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { 109 | write!( 110 | fmt, 111 | "[desc id={}, flags={}, cat={}, name={:?}]", 112 | self.id(), 113 | self.flags().flag, 114 | self.category_id(), 115 | self.name() 116 | ) 117 | } 118 | } 119 | 120 | impl ProfilerMarkerDesc { 121 | pub fn id(&self) -> ProfilerMarkerId { 122 | unsafe { (*self.native).id as ProfilerMarkerId } 123 | } 124 | 125 | pub fn flags(&self) -> ProfilerMarkerFlags { 126 | unsafe { ProfilerMarkerFlags::from((*self.native).flags) } 127 | } 128 | 129 | pub fn category_id(&self) -> ProfilerCategoryId { 130 | unsafe { (*self.native).categoryId as ProfilerCategoryId } 131 | } 132 | 133 | pub fn name(&self) -> &std::ffi::CStr { 134 | unsafe { std::ffi::CStr::from_ptr((*self.native).name) } 135 | } 136 | } 137 | 138 | #[repr(u8)] 139 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 140 | pub enum ProfilerMarkerDataType { 141 | None = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeNone as u8, 142 | InstanceId = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeInstanceId as u8, 143 | Int32 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeInt32 as u8, 144 | UInt32 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeUInt32 as u8, 145 | Int64 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeInt64 as u8, 146 | UInt64 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeUInt64 as u8, 147 | Float = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeFloat as u8, 148 | Double = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeDouble as u8, 149 | String = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeString as u8, 150 | String16 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeString16 as u8, 151 | Blob8 = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeBlob8 as u8, 152 | GfxResourceId = UnityProfilerMarkerDataType__kUnityProfilerMarkerDataTypeGfxResourceId as u8, 153 | } 154 | 155 | impl ProfilerMarkerDataType { 156 | #[allow(unused)] 157 | pub(crate) fn from(value: u8) -> Option { 158 | if value <= ProfilerMarkerDataType::Blob8 as u8 { 159 | Some(unsafe { std::mem::transmute(value) }) 160 | } else { 161 | None 162 | } 163 | } 164 | } 165 | 166 | #[repr(u8)] 167 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 168 | pub enum ProfilerMarkerDataUnit { 169 | Undefined = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitUndefined as u8, 170 | TimeNanoseconds = 171 | UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitTimeNanoseconds as u8, 172 | Bytes = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitBytes as u8, 173 | Count = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitCount as u8, 174 | Percent = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitPercent as u8, 175 | FrequencyHz = UnityProfilerMarkerDataUnit__kUnityProfilerMarkerDataUnitFrequencyHz as u8, 176 | } 177 | 178 | impl ProfilerMarkerDataUnit { 179 | #[allow(unused)] 180 | pub(crate) fn from(value: u8) -> Option { 181 | if value <= ProfilerMarkerDataUnit::FrequencyHz as u8 { 182 | Some(unsafe { std::mem::transmute(value) }) 183 | } else { 184 | None 185 | } 186 | } 187 | } 188 | 189 | #[repr(C)] 190 | pub struct ProfilerMarkerData<'a> { 191 | native: UnityProfilerMarkerData, 192 | data_ref: &'a [u8], 193 | } 194 | 195 | impl ProfilerMarkerData<'_> { 196 | pub fn new<'a>(data_type: ProfilerMarkerDataType, data: &'a [u8]) -> ProfilerMarkerData<'a> { 197 | unsafe { 198 | ProfilerMarkerData { 199 | native: UnityProfilerMarkerData { 200 | type_: data_type as UnityProfilerMarkerDataType, 201 | reserved0: 0, 202 | reserved1: 0, 203 | size: data.len() as u32, 204 | ptr: &*(data.as_ptr() as *const ::std::os::raw::c_void), 205 | }, 206 | data_ref: data, 207 | } 208 | } 209 | } 210 | 211 | pub fn data_type(&self) -> ProfilerMarkerDataType { 212 | unsafe { std::mem::transmute(self.native.type_) } 213 | } 214 | 215 | pub fn data(&self) -> &'_ [u8] { 216 | self.data_ref 217 | } 218 | } 219 | 220 | #[repr(u8)] 221 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 222 | pub enum ProfilerFlowEventType { 223 | Begin = UnityProfilerFlowEventType__kUnityProfilerFlowEventTypeBegin as u8, 224 | Next = UnityProfilerFlowEventType__kUnityProfilerFlowEventTypeNext as u8, 225 | End = UnityProfilerFlowEventType__kUnityProfilerFlowEventTypeEnd as u8, 226 | } 227 | 228 | impl ProfilerFlowEventType { 229 | pub fn from(value: u8) -> Option { 230 | if value <= ProfilerFlowEventType::End as u8 { 231 | Some(unsafe { std::mem::transmute(value) }) 232 | } else { 233 | None 234 | } 235 | } 236 | } 237 | 238 | #[repr(u16)] 239 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 240 | pub enum ProfilerCounterFlag { 241 | None = UnityProfilerCounterFlags__kUnityProfilerCounterFlagNone as u16, 242 | FlashOnEndOfFrame = UnityProfilerCounterFlags__kUnityProfilerCounterFlushOnEndOfFrame as u16, 243 | ResetToZeroOnFlush = UnityProfilerCounterFlags__kUnityProfilerCounterFlagResetToZeroOnFlush as u16, 244 | Atomic = UnityProfilerCounterFlags__kUnityProfilerCounterFlagAtomic as u16, 245 | Getter = UnityProfilerCounterFlags__kUnityProfilerCounterFlagGetter as u16, 246 | } 247 | 248 | bitflag!(ProfilerCounterFlags, ProfilerCounterFlag, UnityProfilerCounterFlags); 249 | 250 | 251 | pub type ProfilerThreadId = UnityProfilerThreadId; 252 | 253 | macro_rules! impl_profiler { 254 | () => { 255 | pub fn emit_event( 256 | &self, 257 | marker_desc: &ProfilerMarkerDesc, 258 | event_type: ProfilerMarkerEventType, 259 | event_data: &[ProfilerMarkerData], 260 | ) { 261 | unsafe { 262 | self.interface().EmitEvent.expect("EmitEvent")( 263 | marker_desc.native, 264 | event_type as UnityProfilerMarkerEventType, 265 | event_data.len() as u16, 266 | event_data.as_ptr() as *const _, 267 | ); 268 | } 269 | } 270 | 271 | pub fn is_enabled(&self) -> bool { 272 | unsafe { self.interface().IsEnabled.expect("IsEnabled")() != 0 } 273 | } 274 | 275 | pub fn is_available(&self) -> bool { 276 | unsafe { self.interface().IsAvailable.expect("IsAvailable")() != 0 } 277 | } 278 | 279 | pub fn create_marker<'a>( 280 | &'a self, 281 | name: &std::ffi::CStr, 282 | category: ProfilerCategoryId, 283 | flags: ProfilerMarkerFlags, 284 | event_data_count: ::std::os::raw::c_int, 285 | ) -> Result { 286 | unsafe { 287 | let mut ret = std::ptr::null::(); 288 | let result = self.interface().CreateMarker.expect("CreateMarker")( 289 | &mut ret, 290 | name.as_ptr(), 291 | category as _, 292 | flags.flag as _, 293 | event_data_count, 294 | ); 295 | if result > 0 { 296 | Err(result) 297 | } else { 298 | Ok(ProfilerMarkerDesc { native: ret }) 299 | } 300 | } 301 | } 302 | 303 | pub fn set_marker_metadata_name( 304 | &self, 305 | desc: &ProfilerMarkerDesc, 306 | index: ::std::os::raw::c_int, 307 | metadata_name: &std::ffi::CStr, 308 | metadata_type: ProfilerMarkerDataType, 309 | metadata_unit: ProfilerMarkerDataUnit, 310 | ) -> Result<(), ::std::os::raw::c_int> { 311 | unsafe { 312 | let result = self 313 | .interface() 314 | .SetMarkerMetadataName 315 | .expect("SetMarkerMetadataName")( 316 | desc.native, 317 | index, 318 | metadata_name.as_ptr(), 319 | metadata_type as _, 320 | metadata_unit as _, 321 | ); 322 | if result > 0 { 323 | Err(result) 324 | } else { 325 | Ok(()) 326 | } 327 | } 328 | } 329 | 330 | pub fn register_thread( 331 | &self, 332 | group_name: &std::ffi::CStr, 333 | name: &std::ffi::CStr, 334 | ) -> Result { 335 | unsafe { 336 | let mut thread_id = std::mem::zeroed::(); 337 | 338 | let result = self.interface().RegisterThread.expect("RegisterThread")( 339 | &mut thread_id, 340 | group_name.as_ptr(), 341 | name.as_ptr(), 342 | ); 343 | if result > 0 { 344 | Err(result) 345 | } else { 346 | Ok(thread_id) 347 | } 348 | } 349 | } 350 | 351 | pub fn unregister_thread( 352 | &self, 353 | thread_id: ProfilerThreadId, 354 | ) -> Result<(), ::std::os::raw::c_int> { 355 | unsafe { 356 | let result = self.interface().UnregisterThread.expect("UnregisterThread")(thread_id); 357 | if result > 0 { 358 | Err(result) 359 | } else { 360 | Ok(()) 361 | } 362 | } 363 | } 364 | }; 365 | } 366 | 367 | impl UnityProfiler { 368 | impl_profiler!(); 369 | } 370 | 371 | 372 | define_unity_interface!( 373 | UnityProfilerV2, 374 | IUnityProfilerV2, 375 | 0xB957E0189CB6A30B_u64, 376 | 0x83CE589AE85B9068_u64 377 | ); 378 | 379 | pub type ProfilerCounterStatePtrCallback = UnityProfilerCounterStatePtrCallback; 380 | 381 | pub struct ProfilerCounter { 382 | pub(crate) counter: *mut T, 383 | } 384 | 385 | impl ProfilerCounter { 386 | pub fn value(&self) -> &T { 387 | unsafe { 388 | &*self.counter 389 | } 390 | } 391 | 392 | pub fn value_mut(&mut self) -> &mut T { 393 | unsafe { 394 | &mut *self.counter 395 | } 396 | } 397 | } 398 | 399 | macro_rules! impl_profiler_v2 { 400 | () => { 401 | impl_profiler!(); 402 | 403 | pub fn create_category(&self, name: &std::ffi::CStr, unused: u32) -> Option { 404 | unsafe { 405 | let mut category: UnityProfilerCategoryId = std::mem::zeroed(); 406 | let r = self.interface().CreateCategory.expect("CreateCategory")(&mut category as *mut UnityProfilerCategoryId, name.as_ptr(), unused); 407 | if r > 0 { 408 | Some(category) 409 | } else { 410 | None 411 | } 412 | } 413 | } 414 | 415 | pub unsafe fn create_counter_value(&self, 416 | category: ProfilerCategoryId, 417 | name: &std::ffi::CStr, 418 | flags: ProfilerMarkerFlags, 419 | value_type: ProfilerMarkerDataType, 420 | value_unit: ProfilerMarkerDataUnit, 421 | value_size: usize, 422 | counter_flags: ProfilerCounterFlags, 423 | activate_func: ProfilerCounterStatePtrCallback, 424 | deactivate_func: ProfilerCounterStatePtrCallback, 425 | user_data: *mut ::std::os::raw::c_void) -> *mut ::std::os::raw::c_void { 426 | unsafe { 427 | self.interface().CreateCounterValue.expect("CreateCounterValue")(category, name.as_ptr(), flags.into(), value_type as u8, value_unit as u8, value_size, counter_flags.into(), activate_func, deactivate_func, user_data) 428 | } 429 | } 430 | 431 | pub unsafe fn flush_counter_value(&self, counter: *mut ::std::os::raw::c_void) { 432 | unsafe { 433 | self.interface().FlushCounterValue.expect("FlushCounterValue")(counter) 434 | } 435 | } 436 | 437 | pub unsafe fn create_counter(&self, 438 | category: ProfilerCategoryId, 439 | name: &std::ffi::CStr, 440 | flags: ProfilerMarkerFlags, 441 | value_type: ProfilerMarkerDataType, 442 | value_unit: ProfilerMarkerDataUnit, 443 | counter_flags: ProfilerCounterFlags, 444 | activate_func: ProfilerCounterStatePtrCallback, 445 | deactivate_func: ProfilerCounterStatePtrCallback, 446 | user_data: *mut ::std::os::raw::c_void) -> Option> { 447 | unsafe { 448 | let r = self.create_counter_value(category, name, flags, value_type, value_unit, std::mem::size_of::(), counter_flags.into(), activate_func, deactivate_func, user_data); 449 | if r != null_mut() { 450 | Some(ProfilerCounter:: { counter: r as *mut T }) 451 | } else { 452 | None 453 | } 454 | } 455 | } 456 | 457 | pub unsafe fn flush_counter(&self, counter: &mut ProfilerCounter) { 458 | unsafe { 459 | self.flush_counter_value(counter.counter as *mut ::std::os::raw::c_void); 460 | } 461 | } 462 | } 463 | } 464 | 465 | impl UnityProfilerV2 { 466 | impl_profiler_v2!(); 467 | } 468 | 469 | 470 | #[cfg(test)] 471 | mod test { 472 | use super::*; 473 | 474 | #[test] 475 | fn flags_test() { 476 | assert_eq!( 477 | ::std::mem::size_of::(), 478 | ::std::mem::size_of::() 479 | ); 480 | 481 | let f = [ 482 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptUser, 483 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptInvoke, 484 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagScriptEnterLeave, 485 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityEditor, 486 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagAvailabilityNonDev, 487 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagWarning, 488 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityDebug, 489 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityInternal, 490 | unity_native_plugin_sys::UnityProfilerMarkerFlag__kUnityProfilerMarkerFlagVerbosityAdvanced, 491 | ]; 492 | 493 | let f2 = [ 494 | ProfilerMarkerFlag::ScriptUser, 495 | ProfilerMarkerFlag::ScriptInvoke, 496 | ProfilerMarkerFlag::ScriptEnterLeave, 497 | ProfilerMarkerFlag::AvailabilityEditor, 498 | ProfilerMarkerFlag::AvailabilityNonDev, 499 | ProfilerMarkerFlag::Warning, 500 | ProfilerMarkerFlag::VerbosityDebug, 501 | ProfilerMarkerFlag::VerbosityInternal, 502 | ProfilerMarkerFlag::VerbosityAdvanced, 503 | ]; 504 | 505 | for i in 0..f.len() { 506 | assert!(ProfilerMarkerFlags::from(f[i] as u16).has_flag(f2[i])); 507 | assert_eq!(ProfilerMarkerFlags::new(f2[i]).unset_flag(f2[i]).flag, 0); 508 | } 509 | } 510 | } 511 | -------------------------------------------------------------------------------- /unity-native-plugin/src/profiler_callbacks.rs: -------------------------------------------------------------------------------- 1 | use crate::define_unity_interface; 2 | use crate::interface::UnityInterface; 3 | use crate::profiler::*; 4 | use std::ffi::c_void; 5 | use std::fmt::*; 6 | use unity_native_plugin_sys::*; 7 | 8 | define_unity_interface!( 9 | UnityProfilerCallbacks, 10 | unity_native_plugin_sys::IUnityProfilerCallbacks, 11 | 0x572FDB38CE3C4B1F_u64, 12 | 0xA6071A9A7C4F52D8_u64 13 | ); 14 | 15 | #[derive(Debug)] 16 | pub struct ProfilerCategoryDesc { 17 | pub(crate) native: *const UnityProfilerCategoryDesc, 18 | } 19 | 20 | impl ProfilerCategoryDesc { 21 | pub fn id(&self) -> ProfilerCategoryId { 22 | unsafe { (*self.native).id as ProfilerCategoryId } 23 | } 24 | 25 | pub fn rgba_color(&self) -> u32 { 26 | unsafe { (*self.native).rgbaColor } 27 | } 28 | 29 | pub fn name(&self) -> &std::ffi::CStr { 30 | unsafe { std::ffi::CStr::from_ptr((*self.native).name) } 31 | } 32 | } 33 | 34 | pub struct ProfilerThreadDesc { 35 | pub(crate) native: *const UnityProfilerThreadDesc, 36 | } 37 | 38 | impl ProfilerThreadDesc { 39 | pub fn thread_id(&self) -> ProfilerThreadId { 40 | unsafe { (*self.native).threadId as ProfilerThreadId } 41 | } 42 | 43 | pub fn group_name(&self) -> &std::ffi::CStr { 44 | unsafe { std::ffi::CStr::from_ptr((*self.native).groupName) } 45 | } 46 | 47 | pub fn name(&self) -> &std::ffi::CStr { 48 | unsafe { std::ffi::CStr::from_ptr((*self.native).name) } 49 | } 50 | } 51 | 52 | pub struct ProfilerMarkerEvent<'a> { 53 | pub desc: ProfilerMarkerDesc, 54 | pub event_type: ProfilerMarkerEventType, 55 | event_data: &'a [UnityProfilerMarkerData], 56 | } 57 | 58 | impl<'a> std::fmt::Debug for ProfilerMarkerEvent<'a> { 59 | fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { 60 | write!( 61 | fmt, 62 | "[event desc={:?}, ty={:?}, data_len={:?}]", 63 | self.desc, 64 | self.event_type, 65 | self.event_data.len(), 66 | ) 67 | } 68 | } 69 | 70 | extern "system" fn create_category_bridge( 71 | _desc: *const UnityProfilerCategoryDesc, 72 | _userdata: *mut c_void, 73 | ) { 74 | let ptr = _userdata as *mut Box; 75 | let mut cb = unsafe { Box::from_raw(ptr) }; 76 | 77 | let desc = ProfilerCategoryDesc { native: _desc }; 78 | cb(&desc); 79 | std::mem::forget(cb); 80 | } 81 | 82 | extern "system" fn create_marker_bridge( 83 | _desc: *const UnityProfilerMarkerDesc, 84 | _userdata: *mut c_void, 85 | ) { 86 | let ptr = _userdata as *mut Box; 87 | let mut cb = unsafe { Box::from_raw(ptr) }; 88 | 89 | let desc = ProfilerMarkerDesc { native: _desc }; 90 | cb(&desc); 91 | std::mem::forget(cb); 92 | } 93 | 94 | extern "system" fn marker_event_bridge( 95 | _desc: *const UnityProfilerMarkerDesc, 96 | _event_type: UnityProfilerMarkerEventType, 97 | _event_data_count: u16, 98 | _event_data: *const UnityProfilerMarkerData, 99 | _userdata: *mut c_void, 100 | ) { 101 | let desc = ProfilerMarkerDesc { native: _desc }; 102 | let event_type = match ProfilerMarkerEventType::from(_event_type) { 103 | Some(v) => v, 104 | None => return, 105 | }; 106 | 107 | let event_data = unsafe { std::slice::from_raw_parts(_event_data, _event_data_count as usize) }; 108 | 109 | let desc = ProfilerMarkerEvent { 110 | desc, 111 | event_type, 112 | event_data, 113 | }; 114 | 115 | let ptr = _userdata as *mut Box; 116 | let mut cb = unsafe { Box::from_raw(ptr) }; 117 | 118 | cb(&desc); 119 | std::mem::forget(cb); 120 | } 121 | 122 | extern "system" fn frame_bridge(_userdata: *mut c_void) { 123 | let ptr = _userdata as *mut Box; 124 | let mut cb = unsafe { Box::from_raw(ptr) }; 125 | 126 | cb(); 127 | std::mem::forget(cb); 128 | } 129 | 130 | extern "system" fn create_thread_bridge( 131 | desc: *const UnityProfilerThreadDesc, 132 | _userdata: *mut c_void, 133 | ) { 134 | let desc = ProfilerThreadDesc { native: desc }; 135 | 136 | let ptr = _userdata as *mut Box; 137 | let mut cb = unsafe { Box::from_raw(ptr) }; 138 | 139 | cb(&desc); 140 | std::mem::forget(cb); 141 | } 142 | 143 | pub struct CreateCategoryRegister(*mut c_void); 144 | pub struct CreateMarkerRegister(*mut c_void); 145 | pub struct MarkerEventRegister { 146 | ptr: *mut c_void, 147 | desc: *const UnityProfilerMarkerDesc, 148 | } 149 | pub struct FrameRegister(*mut c_void); 150 | pub struct CreateThreadRegister(*mut c_void); 151 | 152 | macro_rules! iface_fn { 153 | ($self:tt, $name:tt) => { 154 | $self.interface().$name.expect(stringify!($name)) 155 | }; 156 | } 157 | 158 | macro_rules! common_impl { 159 | ($name: tt) => { 160 | impl $name { 161 | pub fn register_create_category( 162 | &self, 163 | f: Box, 164 | ) -> CreateCategoryRegister { 165 | let ptr = Box::into_raw(Box::new(f)) as *mut c_void; 166 | 167 | unsafe { 168 | iface_fn!(self, RegisterCreateCategoryCallback)( 169 | Some(create_category_bridge), 170 | ptr, 171 | ); 172 | } 173 | CreateCategoryRegister(ptr) 174 | } 175 | 176 | pub fn unregister_create_category(&self, register: CreateCategoryRegister) { 177 | unsafe { 178 | iface_fn!(self, UnregisterCreateCategoryCallback)( 179 | Some(create_category_bridge), 180 | register.0, 181 | ); 182 | } 183 | } 184 | 185 | pub fn register_create_marker( 186 | &self, 187 | f: Box, 188 | ) -> CreateMarkerRegister { 189 | let ptr = Box::into_raw(Box::new(f)) as *mut c_void; 190 | 191 | unsafe { 192 | iface_fn!(self, RegisterCreateMarkerCallback)(Some(create_marker_bridge), ptr); 193 | } 194 | CreateMarkerRegister(ptr) 195 | } 196 | 197 | pub fn unregister_create_marker(&self, register: CreateMarkerRegister) { 198 | unsafe { 199 | iface_fn!(self, UnregisterCreateMarkerCallback)( 200 | Some(create_marker_bridge), 201 | register.0, 202 | ); 203 | } 204 | } 205 | 206 | pub fn register_marker_event( 207 | &self, 208 | desc: &ProfilerMarkerDesc, 209 | f: Box, 210 | ) -> MarkerEventRegister { 211 | let ptr = Box::into_raw(Box::new(f)) as *mut c_void; 212 | 213 | unsafe { 214 | iface_fn!(self, RegisterMarkerEventCallback)( 215 | desc.native, 216 | Some(marker_event_bridge), 217 | ptr, 218 | ); 219 | } 220 | MarkerEventRegister { 221 | ptr, 222 | desc: desc.native, 223 | } 224 | } 225 | 226 | pub fn unregister_marker_event(&self, register: MarkerEventRegister) { 227 | unsafe { 228 | iface_fn!(self, UnregisterMarkerEventCallback)( 229 | register.desc, 230 | Some(marker_event_bridge), 231 | register.ptr, 232 | ); 233 | } 234 | } 235 | 236 | pub fn register_frame(&self, f: Box) -> FrameRegister { 237 | let ptr = Box::into_raw(Box::new(f)) as *mut c_void; 238 | 239 | unsafe { 240 | iface_fn!(self, RegisterFrameCallback)(Some(frame_bridge), ptr); 241 | } 242 | FrameRegister(ptr) 243 | } 244 | 245 | pub fn unregister_frame(&self, register: FrameRegister) { 246 | unsafe { 247 | iface_fn!(self, UnregisterFrameCallback)(Some(frame_bridge), register.0); 248 | } 249 | } 250 | 251 | pub fn register_create_thread( 252 | &self, 253 | f: Box, 254 | ) -> CreateThreadRegister { 255 | let ptr = Box::into_raw(Box::new(f)) as *mut c_void; 256 | 257 | unsafe { 258 | iface_fn!(self, RegisterCreateThreadCallback)(Some(create_thread_bridge), ptr); 259 | } 260 | CreateThreadRegister(ptr) 261 | } 262 | 263 | pub fn unregister_create_thread(&self, register: CreateThreadRegister) { 264 | unsafe { 265 | iface_fn!(self, UnregisterCreateThreadCallback)( 266 | Some(create_thread_bridge), 267 | register.0, 268 | ); 269 | } 270 | } 271 | } 272 | }; 273 | } 274 | 275 | common_impl!(UnityProfilerCallbacks); 276 | 277 | define_unity_interface!( 278 | UnityProfilerCallbacksV2, 279 | unity_native_plugin_sys::IUnityProfilerCallbacksV2, 280 | 0x5DEB59E88F2D4571_u64, 281 | 0x81E8583069A5E33C_u64 282 | ); 283 | 284 | #[derive(Clone, Copy, Debug)] 285 | pub struct ProfilerFlowEvent { 286 | pub ty: ProfilerFlowEventType, 287 | pub flow_id: u32, 288 | } 289 | 290 | extern "system" fn flow_event_bridge( 291 | ty: UnityProfilerFlowEventType, 292 | flow_id: u32, 293 | _userdata: *mut c_void, 294 | ) { 295 | let ty = match ProfilerFlowEventType::from(ty) { 296 | Some(ty) => ty, 297 | None => return, 298 | }; 299 | 300 | let desc = ProfilerFlowEvent { ty, flow_id }; 301 | 302 | let ptr = _userdata as *mut Box; 303 | let mut cb = unsafe { Box::from_raw(ptr) }; 304 | 305 | cb(&desc); 306 | std::mem::forget(cb); 307 | } 308 | 309 | pub struct FlowEventRegister(*mut c_void); 310 | 311 | common_impl!(UnityProfilerCallbacksV2); 312 | impl UnityProfilerCallbacksV2 { 313 | pub fn register_flow_event( 314 | &self, 315 | f: Box, 316 | ) -> FlowEventRegister { 317 | let ptr = Box::into_raw(Box::new(f)) as *mut c_void; 318 | 319 | unsafe { 320 | iface_fn!(self, RegisterFlowEventCallback)(Some(flow_event_bridge), ptr); 321 | } 322 | FlowEventRegister(ptr) 323 | } 324 | 325 | pub fn unregister_flow_event(&self, register: FlowEventRegister) { 326 | unsafe { 327 | iface_fn!(self, UnregisterFlowEventCallback)(Some(flow_event_bridge), register.0); 328 | } 329 | } 330 | } 331 | --------------------------------------------------------------------------------