Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resolved Burst throws an uninformative error when casting to a function pointer

Discussion in 'Burst' started by rohan-zatun, Mar 23, 2021.

  1. rohan-zatun

    rohan-zatun

    Joined:
    Jan 13, 2021
    Posts:
    14
    In my existing code, I have a raw chunk of memory containing a function pointer, and Burst for some reason throws an error when performing that cast.

    For a sample code, think of something like this:
    Code (CSharp):
    1.  
    2. using Unity.Burst;
    3. using Unity.Collections;
    4. using Unity.Collections.LowLevel.Unsafe;
    5. using Unity.Jobs;
    6.  
    7. namespace UnityEngine.Internal
    8. {
    9.     public delegate float SomeDelegate(float a, float b);
    10.    
    11.     [BurstCompile]
    12.     public static class FnLib
    13.     {
    14.         [BurstCompile, AOT.MonoPInvokeCallback(typeof(SomeDelegate))]
    15.         public static float DoSomething(float a, float b) => a + b;
    16.     }
    17.    
    18.     public class FunctionPointerCastTest : MonoBehaviour
    19.     {
    20.         private FunctionPointer<SomeDelegate> _fnPtr = default;
    21.         private void Awake()
    22.         {
    23.             _fnPtr = BurstCompiler.CompileFunctionPointer<SomeDelegate>(FnLib.DoSomething);
    24.         }
    25.  
    26.         [InspectorButton(nameof(Test))] [SerializeField] private Stub s = default; // <-- ignore this, just draws a button on inspector.
    27.         public unsafe void Test()
    28.         {
    29.             var na = new NativeArray<byte>(sizeof(FunctionPointer<SomeDelegate>), Allocator.TempJob);
    30.             var ptr = na.GetUnsafePtr();
    31.             (*(FunctionPointer<SomeDelegate>*) ptr) = _fnPtr;
    32.             new SomeJob {Data = (byte*) na.GetUnsafeReadOnlyPtr()}.Schedule().Complete();
    33.             na.Dispose();
    34.         }
    35.     }
    36.  
    37.     [BurstCompile] // <-- comment/uncomment this
    38.     public unsafe struct SomeJob : IJob
    39.     {
    40.         [NativeDisableUnsafePtrRestriction] public byte* Data;
    41.        
    42.         public void Execute()
    43.         {
    44.             (*(FunctionPointer<SomeDelegate>*) Data).Invoke(34, 56);
    45.         }
    46.     }
    47. }
    48.  
    Obviously, my actual code doesn't ignore the result of a pure method but just bear with me for the sake of an example, please.

    If the job is *not* burst compiled, it works just fine, no issues, but if it is, then it spits out the following error:
    A majority of what I am working on is actually dependent on being able to cast raw memory into a function pointer. Can someone please help me out with this?
     
  2. rohan-zatun

    rohan-zatun

    Joined:
    Jan 13, 2021
    Posts:
    14
    I researched a bit more over this and seems like it is because FunctionPointer is a generic type, and Burst breaks when it tries to interpret it.

    As a workaround, currently, I am using a switch and const ushort identifiers, directly burst compiled, but it's quite a bit of boilerplate every time. How I wish C# had preprocessor macros, or that Unity had some C++ API.

    There's a major problem with this though, I need to update the registry EVERY time I need to add a new function, throwing the modularity of the code out the window.
     
    Last edited: Mar 23, 2021
  3. rohan-zatun

    rohan-zatun

    Joined:
    Jan 13, 2021
    Posts:
    14
    Okay, finally found a solution, you can use UnsafeUtility.As<U, T>(ref U value) to reinterpret cast like it were C++.
     
    mailey99 likes this.