Unity Native Plugin API for Rust
=====
[LICENSE (MIT)](LICENSE)
## How to use
* Define in Cargo.toml
```cargo
[dependencies]
unity-native-plugin = { version = "*", features = ["d3d11"] }
# * Support features
# * d3d11 - IUnityGraphicsD3D11
# * d3d12 - IUnityGraphicsD3D12
# * vulkan - IUnityGraphicsVulkan
# * metal - IUnityGraphicsMetal
# * profiler - IUnityProfiler / IUnityProfilerCallbacks
```
* Vulkan support has been integrated into `unity-native-plugin`. No separate crate needs to be added to your dependencies.
### Platform-specific features
The graphics features are gated by both a feature flag **and** a target `cfg`:
| `d3d11`, `d3d12` | Windows (`cfg(windows)`) |
| `metal` | Apple platforms (`cfg(target_vendor = "apple")`) |
| `vulkan` | Cross-platform |
| `profiler` | Cross-platform |
Enabling a feature on a non-matching platform compiles silently as a no-op — the flag is accepted but the corresponding module (`unity_native_plugin::d3d11`, `unity_native_plugin::metal`, etc.) will not be present. This is intentional so that you can write a single `Cargo.toml` such as:
```toml
[dependencies]
unity-native-plugin = { version = "*", features = ["d3d11", "d3d12", "metal", "vulkan"] }
```
without per-platform `[target.'cfg(...)'.dependencies]` blocks. The unused features
have no runtime cost.
* Use a macro in lib.rs to define your entry points. Without this definition, UnityInterfaces cannot be used.
```rust
unity_native_plugin::unity_native_plugin_entry_point! {
fn unity_plugin_load(interfaces: &unity_native_plugin::interface::UnityInterfaces) {
}
fn unity_plugin_unload() {
}
}
```
* Use UnityInterface::interface, which is equivalent to IUnityInterfaces::GetInterface, to get the interface.
```rust
let intf = unity_native_plugin::interface::UnityInterfaces::get()
.interface::<unity_native_plugin::d3d11::UnityGraphicsD3D11>();
```
## Examples
* [unity-native-plugin-sample](./unity-native-plugin-sample)
* [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)
* [Event tracing example for unity](./unity-native-plugin-sample-profiler) - similar to ["TraceEventProfiler from Unity-Technologies"](https://github.com/Unity-Technologies/TraceEventProfiler)
## Migration guide: 0.8 → 0.9
### `Cargo.toml`
* **The `unity-native-plugin-vulkan` crate has been removed.** Vulkan support is now an opt-in feature of `unity-native-plugin` itself.
```toml
# Before (0.8)
unity-native-plugin = "0.8"
unity-native-plugin-vulkan = "0.8"
# After (0.9)
unity-native-plugin = { version = "0.9", features = ["vulkan"] }
```
* **The `profiler_callbacks` feature has been merged into `profiler`.** Enabling `profiler` now exposes both `IUnityProfiler` and `IUnityProfilerCallbacks`.
```toml
# Before
features = ["profiler", "profiler_callbacks"]
# After
features = ["profiler"]
```
### Module paths
* `unity_native_plugin_vulkan::vulkan::*` → `unity_native_plugin::vulkan::*`
* `unity_native_plugin::d3d11::ComPtr` / `unity_native_plugin::d3d12::ComPtr` → `unity_native_plugin::windows::ComPtr`
### Methods are now provided through traits
The inherent `impl` blocks on the wrapper types have been replaced with traits. Each trait is published under **two names**:
* a Rust-conventional `*Interface` name (the canonical one — e.g. `UnityGraphicsD3D11Interface`)
* an `IUnity*` alias that matches Unity's C header name 1:1 (e.g. `IUnityGraphicsD3D11`)
Use whichever name you prefer; they refer to the same trait. To call any method, bring it into scope:
```rust
// Pick either form per import; both resolve to the same trait.
use unity_native_plugin::graphics::UnityGraphicsInterface; // or IUnityGraphics
use unity_native_plugin::log::UnityLogInterface; // or IUnityLog
use unity_native_plugin::memory_manager::UnityMemoryManagerInterface; // or IUnityMemoryManager
use unity_native_plugin::profiler::{UnityProfilerInterface, UnityProfilerV2Interface};
use unity_native_plugin::profiler_callbacks::{
UnityProfilerCallbacksInterface, UnityProfilerCallbacksV2Interface,
};
use unity_native_plugin::d3d11::UnityGraphicsD3D11Interface;
use unity_native_plugin::d3d12::{
UnityGraphicsD3D12Interface, // for UnityGraphicsD3D12
UnityGraphicsD3D12v2Interface, // for UnityGraphicsD3D12v2
UnityGraphicsD3D12v3Interface, // ... v3 .. v8 for the corresponding interface versions
};
use unity_native_plugin::metal::{UnityGraphicsMetalV1Interface, UnityGraphicsMetalV2Interface};
use unity_native_plugin::vulkan::{UnityGraphicsVulkanInterface, UnityGraphicsVulkanV2Interface};
```
Without the corresponding `use`, methods such as `renderer()`, `log()`, `device()`, `command_queue()`, `emit_event()`, `register_create_marker()` etc. will appear to be missing.
Notes:
* The marker trait `unity_native_plugin::interface::UnityInterface` is **not** a Unity-API wrapper — it is a Rust-only marker used by `UnityInterfaces::interface::<T>()` for GUID-based lookup. It does not have an `IUnity*` alias because it does not correspond 1:1 to any Unity header type.
### Renamed identifiers
* D3D11 typo fixes (call sites must be updated):
* `texture_from_natvie_texture` → `texture_from_native_texture`
* `srv_from_natvie_texture` → `srv_from_native_texture`
* `graphics::GfxRenderer::ReservedCFE` → `graphics::GfxRenderer::Nvn2`
### Vulkan: `VulkanInstance::get_instance_proc_addr` return type
The return type changed from a sys-defined enum to the standard `ash` function-pointer type, so the caller now matches on `Option` instead of the custom `None` variant.
```rust
// Before (0.8)
match instance.get_instance_proc_addr(name) {
PFN_vkVoidFunction::None => { /* not found */ }
other => { /* use other */ }
}
// After (0.9)
if let Some(f) = instance.get_instance_proc_addr(name) {
// use f
}
```