diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 77445e8e5..9ccc66007 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -166,6 +166,7 @@ namespace FlaxEngine public unsafe class ManagedArray { private ManagedHandle pinnedArrayHandle; + private ManagedHandle elementTypeHandle; private IntPtr unmanagedData; private int elementSize; private int length; @@ -185,11 +186,9 @@ namespace FlaxEngine return managedArray; } - internal static ManagedArray AllocateNewArray(int length, int elementSize) - => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, elementSize), length, elementSize); + internal static ManagedArray AllocateNewArray(int length, int elementSize, Type elementType) => new ManagedArray((IntPtr)NativeInterop.NativeAlloc(length, elementSize), length, elementSize, elementType); - internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, int elementSize) - => new ManagedArray(ptr, length, elementSize); + internal static ManagedArray AllocateNewArray(IntPtr ptr, int length, int elementSize, Type elementType) => new ManagedArray(ptr, length, elementSize, elementType); /// /// Returns an instance of ManagedArray from shared pool. @@ -213,7 +212,7 @@ namespace FlaxEngine public static ManagedArray AllocatePooledArray(int length) where T : unmanaged { ManagedArray managedArray = ManagedArrayPool.Get(); - managedArray.Allocate((IntPtr)NativeInterop.NativeAlloc(length, Unsafe.SizeOf()), length, Unsafe.SizeOf()); + managedArray.Allocate((IntPtr)NativeInterop.NativeAlloc(length, Unsafe.SizeOf()), length, Unsafe.SizeOf(), typeof(T)); return managedArray; } @@ -221,29 +220,33 @@ namespace FlaxEngine internal void WrapArray(Array arr) { + var elementType = arr.GetType().GetElementType(); pinnedArrayHandle = ManagedHandle.Alloc(arr, GCHandleType.Pinned); + elementTypeHandle = NativeInterop.GetTypeGCHandle(elementType); unmanagedData = Marshal.UnsafeAddrOfPinnedArrayElement(arr, 0); length = arr.Length; - elementSize = Marshal.SizeOf(arr.GetType().GetElementType()); + elementSize = Marshal.SizeOf(elementType); } internal void Allocate(T* ptr, int length) where T : unmanaged { unmanagedData = new IntPtr(ptr); + elementTypeHandle = NativeInterop.GetTypeGCHandle(typeof(T)); this.length = length; elementSize = Unsafe.SizeOf(); } - internal void Allocate(IntPtr ptr, int length, int elementSize) + internal void Allocate(IntPtr ptr, int length, int elementSize, Type elementType) { unmanagedData = ptr; + elementTypeHandle = NativeInterop.GetTypeGCHandle(elementType); this.length = length; this.elementSize = elementSize; } private ManagedArray() { } - private ManagedArray(IntPtr ptr, int length, int elementSize) => Allocate(ptr, length, elementSize); + private ManagedArray(IntPtr ptr, int length, int elementSize, Type elementType) => Allocate(ptr, length, elementSize, elementType); ~ManagedArray() { @@ -278,10 +281,20 @@ namespace FlaxEngine internal int ElementSize => elementSize; + internal Type ElementType => Unsafe.As(elementTypeHandle.Target); + public Span GetSpan() where T : struct => new Span(unmanagedData.ToPointer(), length); public T[] GetArray() where T : struct => new Span(unmanagedData.ToPointer(), length).ToArray(); + public Array GeSystemArray() + { + Type elementType = Unsafe.As(elementTypeHandle.Target); + Type arrayType = elementType.MakeArrayType(); + IntPtr thisPtr = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(this)); + return (Array)NativeInterop.MarshalToManaged(thisPtr, arrayType); + } + /// /// Provides a pool of pre-allocated ManagedArray that can be re-used. /// @@ -688,6 +701,9 @@ namespace FlaxEngine [CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedIn, typeof(SystemArrayMarshaller.ManagedToNative))] [CustomMarshaller(typeof(Array), MarshalMode.UnmanagedToManagedOut, typeof(SystemArrayMarshaller.ManagedToNative))] + [CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedOut, typeof(SystemArrayMarshaller.NativeToManaged))] + [CustomMarshaller(typeof(Array), MarshalMode.UnmanagedToManagedIn, typeof(SystemArrayMarshaller.NativeToManaged))] + [CustomMarshaller(typeof(Array), MarshalMode.ElementOut, typeof(SystemArrayMarshaller.NativeToManaged))] public static class SystemArrayMarshaller { public struct ManagedToNative @@ -718,6 +734,10 @@ namespace FlaxEngine } } } + public static class NativeToManaged + { + public static Array ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(unmanaged).Target).GeSystemArray() : null; + } } [CustomMarshaller(typeof(Dictionary<,>), MarshalMode.ManagedToUnmanagedIn, typeof(DictionaryMarshaller<,>.ManagedToNative))] @@ -1758,7 +1778,7 @@ namespace FlaxEngine else if (elementType.IsValueType) { // Convert array of custom structures into internal native layout - managedArray = ManagedArray.AllocateNewArray(arr.Length, Marshal.SizeOf(marshalledType)); + managedArray = ManagedArray.AllocateNewArray(arr.Length, Marshal.SizeOf(marshalledType), marshalledType); IntPtr managedArrayPtr = managedArray.GetPointer; for (int i = 0; i < arr.Length; i++) { @@ -2214,7 +2234,7 @@ namespace FlaxEngine Type marshalledType = ArrayFactory.GetMarshalledType(type); if (marshalledType.IsValueType) { - ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, Marshal.SizeOf(marshalledType)); + ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, Marshal.SizeOf(marshalledType), marshalledType); return ManagedHandle.Alloc(managedArray/*, GCHandleType.Weak*/); } else