Last active
June 17, 2023 18:05
-
-
Save Jura-Z/03960c9b9ceacb270256a26e80fb77a1 to your computer and use it in GitHub Desktop.
Burst -> Managed C# call
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal static class Burst2ManagedCall<T, Key> | |
{ | |
private static T s_Delegate; | |
// alignment 16 is important to not crash on arm cpu | |
private static readonly SharedStatic<FunctionPointer<T>> s_SharedStatic = SharedStatic<FunctionPointer<T>>.GetOrCreate<FunctionPointer<T>, Key>(16); | |
public static bool IsCreated => s_SharedStatic.Data.IsCreated; | |
public static void Init(T @delegate) | |
{ | |
CheckIsNotCreated(); | |
s_Delegate = @delegate; | |
s_SharedStatic.Data = new FunctionPointer<T>(Marshal.GetFunctionPointerForDelegate(s_Delegate)); | |
} | |
public static ref FunctionPointer<T> Ptr() | |
{ | |
CheckIsCreated(); | |
return ref s_SharedStatic.Data; | |
} | |
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] // ENABLE_UNITY_COLLECTIONS_CHECKS or UNITY_DOTS_DEBUG | |
private static void CheckIsCreated() | |
{ | |
if (IsCreated == false) | |
throw new InvalidOperationException("Burst2ManagedCall was NOT created!"); | |
} | |
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] // ENABLE_UNITY_COLLECTIONS_CHECKS or UNITY_DOTS_DEBUG | |
private static void CheckIsNotCreated() | |
{ | |
if (IsCreated) | |
throw new InvalidOperationException("Burst2ManagedCall was already created!"); | |
} | |
} | |
////////////////////////////// | |
// Usage: | |
// key to avoid conflicts, like in SharedStatic | |
private struct UniqueStructKey{} | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | |
public unsafe delegate void SystemWriteLineDelegate(byte* stringBuffer, int bufferLength, byte newLine); | |
static void Init() | |
{ | |
// somewhere in managed C#: | |
Burst2ManagedCall<SystemWriteLineDelegate, UniqueStructKey>.Init(ConsoleWriteImpl); | |
} | |
// example of the function to call | |
[AOT.MonoPInvokeCallback(typeof(SystemWriteLineDelegate))] | |
private static unsafe void ConsoleWriteImpl(byte* stringBuffer, int bufferLength, byte newLine) | |
{ | |
// C# managed land | |
try | |
{ | |
if (newLine != 0) | |
{ | |
System.Console.WriteLine(System.Text.Encoding.UTF8.GetString(stringBuffer, bufferLength)); | |
} | |
else | |
{ | |
System.Console.Write(System.Text.Encoding.UTF8.GetString(stringBuffer, bufferLength)); | |
} | |
} | |
catch (Exception ex) | |
{ | |
System.Console.WriteLine(ex.Message); | |
} | |
} | |
// Calling from burst: | |
var ptr = Burst2ManagedCall<SystemWriteLineDelegate, UniqueStructKey>.Ptr(); | |
#if CAN_USE_UNMANAGED_DELEGATES | |
unsafe | |
{ | |
// this is better - not going to alloc if burst is disabled | |
((delegate * unmanaged[Cdecl] <byte*, int, byte, void>)ptr.Value)(data, length, newLine); | |
} | |
#else | |
ptr.Invoke(data, length, newLine); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment