Skip to content

Zero-allocation Unity bindings using Span<byte> and NativeArray<byte> via IL injection. Exposes internal Unity methods for high-performance operations without managed array overhead. Full IL2CPP support.

License

Notifications You must be signed in to change notification settings

Cosmin-B/unity-native-exposed-bindings

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Unity Exposed Bindings

High-Performance Unity Internal Bindings for Zero-Allocation Operations

Unity C# IL2CPP Cross Platform License

Overview

com.cosminb.unity-internals is a high-performance Unity library that exposes internal bindings to enable zero-allocation operations using Span<byte> and NativeArray<byte>. This package allows direct interaction with Unity's native code methods, eliminating managed array overhead for critical performance-sensitive operations.

How It Works

This library uses a sophisticated build pipeline to safely expose Unity's internal methods:

Runtime~/ (Source Code) → ProcessAssembly.sh → Compilation → Cecil IL Injection → ExposedBindings.dll
  1. Source Code (Runtime~/): Contains C# extension methods and stub implementations
  2. ProcessAssembly.sh: Orchestrates the build process
  3. Compilation: Creates a standard .NET assembly
  4. Cecil Processing: Injects IL code to call Unity's internal _Injected methods
  5. Final DLL: The processed assembly with direct native bindings

The Runtime~ folder (with ~ suffix) prevents Unity from compiling the source directly, as the code requires Cecil processing to function properly.

Key Features

  • Zero-Allocation Image Loading: Load textures directly from Span<byte> or NativeArray<byte>
  • Optimized AssetBundle Loading: Load asset bundles without unnecessary memory allocations
  • Cross-Platform Compatibility: Tested on Android, WebGL, macOS, Windows, Linux, and iOS
  • IL2CPP Support: Seamless integration with development and release builds
  • Minimal Performance Overhead: Utilizes Mono.Cecil for efficient method exposure

Requirements

  • Unity 6000.0.31f1 or later
  • .NET 6.0 SDK (for Cecil processing)
  • Mono.Cecil NuGet package

Installation

Option 1: Install via Git URL (Recommended)

Unity Package Manager supports installing packages from Git subfolders using the ?path= parameter:

  1. Open Unity Package Manager (Window > Package Manager)
  2. Click the + button and select "Add package from git URL"
  3. Enter:
    https://github.com/Cosmin-B/unity-native-exposed-bindings.git?path=Assets/Packages/com.cosminb.unity-internals
    

Alternatively, add directly to your Packages/manifest.json:

{
  "dependencies": {
    "com.cosminb.unity-internals": "https://github.com/Cosmin-B/unity-native-exposed-bindings.git?path=Assets/Packages/com.cosminb.unity-internals"
  }
}

Option 2: Local Installation

Via Package Manager:

  1. Clone or download this repository
  2. Open Unity Package Manager
  3. Click + → "Add package from disk"
  4. Navigate to Assets/Packages/com.cosminb.unity-internals/package.json

Manual Copy:

  1. Clone or download this repository
  2. Copy Assets/Packages/com.cosminb.unity-internals to either:
    • Your project's Packages/ folder (recommended)
    • Your project's Assets/ folder

Post-Installation: Processing the Assembly

Note: The package includes a pre-built ExposedBindings.dll that works with Unity 6000.0.31f1+.

If you need to rebuild for a different Unity version:

  1. Copy ProcessAssembly.sh and CecilProcessor/ from this repository to your project root
  2. Run:
    chmod +x ProcessAssembly.sh
    ./ProcessAssembly.sh

Usage Examples

using Unity.Collections;
using ExposedBindings;

// Load texture from NativeArray
NativeArray<byte> imageData = ...;
Texture2D texture = new Texture2D(2, 2);
bool success = texture.LoadImageNative(imageData);

// Load AssetBundle from Span
Span<byte> bundleData = ...;
var request = AssetBundleExtensions.LoadFromMemoryAsyncSpan(bundleData);

Technical Implementation

The library uses Mono.Cecil to:

  • Recreate Unity's internal ManagedSpanWrapper
  • Replace stub method bodies
  • Enable direct access to Unity's internal methods
  • Minimize runtime performance impact

Compatibility

  • Platforms: Android, WebGL, macOS, Windows, Linux, iOS
  • Build Types: Mono and IL2CPP
  • Unity Version: 6000.0.31f1 and later

Performance Benefits

  • Reduced GC pressure
  • Eliminated array copying overhead
  • Direct NativeArray usage in Jobs
  • Potential Burst compatibility

Why Cecil Over Reflection?

Unlike reflection-based approaches, this library uses Mono.Cecil for IL injection because:

  • Zero Runtime Overhead: IL injection happens at build time, not runtime
  • No Allocations: Direct method calls without boxing/unboxing
  • Burst Compatible: Potential for Burst compilation (reflection blocks this)
  • IL2CPP Safe: Works seamlessly with IL2CPP builds
  • Performance: Direct native calls without reflection overhead

Limitations

  • Unity Version Dependency: Internal method signatures can change between Unity versions
  • Cecil Processing Required: Must run ProcessAssembly.sh after package updates
  • Blittable Types Only: Only supports types that can be directly mapped to memory
  • No Multi-dimensional Arrays: Limited to single-dimensional arrays
  • Platform Testing Required: Test on each target platform before shipping

Safety & Compatibility

⚠️ Important: Unity's internal layouts can change between major AND minor versions!

  • Always test thoroughly after Unity updates
  • Rebuild the assembly when upgrading Unity versions
  • The CecilProcessor may need adjustments for new Unity versions
  • Consider maintaining version-specific branches for different Unity releases

Building from Source (For Contributors)

If you want to modify the library or rebuild for a different Unity version:

Prerequisites

  1. Clone this repository
  2. Ensure you have .NET 6.0 SDK installed
  3. Unity 6000.0.31f1 or your target version installed

Building the Assembly

# Make the script executable
chmod +x ProcessAssembly.sh

# Run the processor
./ProcessAssembly.sh

This will:

  • Build the CecilProcessor from source
  • Compile the source code from Runtime~/
  • Process the assembly with Cecil to inject IL code
  • Output ExposedBindings.dll to the Plugins/ folder

Customizing for Different Unity Versions

  1. Update Unity path in ProcessAssembly.sh if needed
  2. Modify CecilProcessor/Program.cs if internal signatures changed
  3. Test thoroughly on your target Unity version

Build and Distribution (For Maintainers)

  1. Process assembly with Cecil
  2. Include processed assembly in Plugins/
  3. Update package.json version
  4. Create GitHub release
  5. Publish to UPM registry (optional)

Credits & Inspiration

This project is inspired by Sebastian Schöner's excellent blog post: Unmanaging Unity

Key insights from Sebastian's work:

  • Unity's internal ManagedSpanWrapper structure for zero-copy operations
  • The existence of _Injected methods that accept spans directly
  • How Unity's internal marshalling works with native code

Our improvements:

  • Using Mono.Cecil for compile-time IL injection instead of runtime reflection
  • Full IL2CPP compatibility without runtime overhead
  • Cleaner API with extension methods
  • Comprehensive platform testing

Extending the Library

Want to expose more Unity internal methods? Check out our guide on extending internals which covers:

  • Finding Unity's internal methods
  • Understanding IL injection with Cecil
  • Adding new exposed methods
  • Testing and compatibility

License

MIT License - See LICENSE file for details

Author

Cosmin Bararu

About

Zero-allocation Unity bindings using Span<byte> and NativeArray<byte> via IL injection. Exposes internal Unity methods for high-performance operations without managed array overhead. Full IL2CPP support.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published