using System.Runtime.InteropServices;
using AOT;
using Unity.Burst;
using UnityEngine;
[BurstCompile]
public unsafe class FunctionPointerC9Burst : MonoBehaviour {
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int UnmanagedDelegate(int value);
[MonoPInvokeCallback(typeof(UnmanagedDelegate))]
private static int Increment(int value) => ++value;
private static readonly delegate* unmanaged[Cdecl]<int, int> c9Ptr
= (delegate* unmanaged[Cdecl]<int, int>) Marshal.GetFunctionPointerForDelegate((UnmanagedDelegate) Increment);
void Start() {
SuccessfullyCompiled(c9Ptr, 0);
CompilationFailsAndFallbackToManagedCallback(c9Ptr, 0);
}
[BurstCompile]
static void SuccessfullyCompiled(void* unmanagedCallback, int value) {
Debug.Log($"Value: {((delegate* unmanaged[Cdecl]<int, int>) unmanagedCallback)(value)}, RunOnBurst ? {RunOnBurst.IsTrue}");
}
[BurstCompile]
static void CompilationFailsAndFallbackToManagedCallback(delegate* unmanaged[Cdecl]<int, int> unmanagedCallback, int value) {
Debug.Log($"Value: {unmanagedCallback(value)}, RunOnBurst ? {RunOnBurst.IsTrue}");
}
}
public static class RunOnBurst {
public static bool IsTrue {
get {
var runOnBurst = true;
Detector(ref runOnBurst);
return runOnBurst;
}
}
[BurstDiscard] static void Detector(ref bool runOnBurst) => runOnBurst = false;
}
If I pass a c#9 function pointer to the burst code, it does not compile correctly. If I cast the function pointer to void*, it compiles successfully, and it works fine on the actual Android IL2CPP device, so I think it is failing to get the method signature correctly.
Also both JobSystem and IL2CPP fail to recognize the C#9 pointer signature (delegate* unmanaged[Cdecl]), resulting in runtime or compilation errors.
However, if I cast it to void*, it works fine in all cases.
I guess for the c#9 pointer to work correctly, Burst, JobSystem, and IL2CPP all need to be modified to get the method signatures correctly.
If it is technically fixable, I would appreciate your response.
@mm_hohu thanks for reporting this. We’ll take a look at the Burst side of it. I can’t remember why this isn’t already supported, and if there’s a problem with supporting it, I don’t know how deep the problem goes, but we’ll take a look.
What are those errors? If you can let me know, then I’ll route the request to the relevant teams inside Unity.
using System.Runtime.InteropServices;
using AOT;
using Unity.Burst;
using Unity.Jobs;
using UnityEngine;
public unsafe class FunctionPointerC9Burst : MonoBehaviour {
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int UnmanagedDelegate(int value);
[MonoPInvokeCallback(typeof(UnmanagedDelegate))] private static int Increment(int value) => ++value;
private static readonly delegate* unmanaged[Cdecl]<int, int> c9Ptr
= (delegate* unmanaged[Cdecl]<int, int>) Marshal.GetFunctionPointerForDelegate((UnmanagedDelegate) Increment);
private void Start() {
var job = new Job() {fp = c9Ptr, Value = 0};
job.Run();
}
}
[BurstCompile]
public unsafe struct Job : IJob {
public delegate* unmanaged[Cdecl]<int, int> fp;
public int Value;
public void Execute() => Debug.Log($"Value: {fp(Value)}");
}
Thanks for your reply. As for JobSystem, I can reproduce the above error with one file. 2022.3.4f1 (LTS)
@mm_hohu The IL2CPP error is a problem in IL2CPP - could you submit a bug report for that issue.
IL2CPP’s delegate code code is incorrectly handling delegates when the first parameter of the delegate is an unmanaged function pointer type. That isn’t directly in your code, but the it is being generated from:
[BurstCompile] private static void IL2CppError(delegate* unmanaged[Cdecl]<int, int> unmanagedCallback, int value) => Debug.Log($"Call C#9 Function Pointer: {unmanagedCallback(value)}");
As long as the first parameter isn’t an unmanaged function pointer you will not hit the error. So reordering the parameters will work around the error: