Mono build works but IL2CPP throws error

Hello, i’m using microsoft onnxruntime with unity. When i build for android with mono, it works great but if i change it to il2cpp, following error happens:

MarshalDirectiveException: Cannot marshal P/Invoke call through delegate of type '.DOrtGetApi'
      at System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointerInternal (System.IntPtr ptr, System.Type t) [0x00000] in <00000000000000000000000000000000>:0
      at System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer (System.IntPtr ptr, System.Type t) [0x00000] in <00000000000000000000000000000000>:0
      at Microsoft.ML.OnnxRuntime.NativeMethods..cctor () [0x00000] in <00000000000000000000000000000000>:0
      at Microsoft.ML.OnnxRuntime.SessionOptions..ctor () [0x00000] in <00000000000000000000000000000000>:0
      at Microsoft.ML.OnnxRuntime.InferenceSession..ctor (System.String modelPath) [0x00000] in <00000000000000000000000000000000>:0
      at ML.Predict (UnityEngine.Texture2D framecam) [0x00000] in <00000000000000000000000000000000>:0
      at CameraFeed.Update () [0x00000] in <00000000000000000000000000000000>:0
    Rethrow as TypeInitializationException: The type initializer for 'Microsoft.ML.Onnx

Any solution? Thanks.

I’d have to know a bit more about this type .DOrtGetApi to be provide more details. Although Mono is pretty permissive on delegate marshaling, where IL2CPP sticks to the letter of the law and tries to follow all of the marshaling rules.

So it may be that this just happens to work on Mono when it should not work. But this also could be a bug in IL2CPP, where some marshaling case that should be handled is not handled correctly.

Hi there,
Did you find a solution for this issue? I’ve faced with the same error.

Hello,
same error here, works on mono, errors on il2cpp. Using microsoft onnxruntime nuget package.

I work on ONNX Runtime (ORT) (ONNX Runtime | Home) but have no knowledge of IL2CPP or Unity. I can help with more details about OrtGetApi. ORT is implemented in C++. We have C# bindings that wrap the C++ API, which is primarily available through a struct with a collection of function pointers. OrtGetApi is the call to retrieve that struct - see https://github.com/microsoft/onnxruntime/blob/baa17679221807ea332a7134c0d10b81adf4009e/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs#L254

C++ definition of the entry point: https://github.com/microsoft/onnxruntime/blob/baa17679221807ea332a7134c0d10b81adf4009e/include/onnxruntime/core/session/onnxruntime_c_api.h#L541

Implementation is simply returning the address of the struct: https://github.com/microsoft/onnxruntime/blob/baa17679221807ea332a7134c0d10b81adf4009e/onnxruntime/core/session/onnxruntime_c_api.cc#L2561-L2563

Possibly with the error message saying ‘Cannot marshal P/Invoke call through delegate’ it’s the subsequent usage where a function pointer within that struct is called.

1 Like

Thanks for the details @skottmckay !

I wonder if the problem occurs because this delegate returns its argument by reference:

@androidevelopernerd Can you submit a bug report to us for this issue? Unity QA: Building quality with passion

Bug report

1 Like

We’ve now corrected this issue internally, thanks for reporting it! As it turns out, IL2CPP was too aggressive in not allowing marshaling for delegates with by reference return types. I’ve lifted that restriction in the IL2CPP code, and we should get it into Unity releases soon.

3 Likes