_prog
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled

This commit is contained in:
2025-12-27 17:59:40 +02:00
parent 523cad3b2c
commit c7326ea483
15 changed files with 1590 additions and 271 deletions

View File

@@ -889,6 +889,11 @@ Variant::Variant(const Span<byte>& v)
} }
} }
Variant::Variant(const BytesContainer& v)
: Variant((const Span<byte>&)(v))
{
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS PRAGMA_DISABLE_DEPRECATION_WARNINGS
#include "Engine/Content/Deprecated.h" #include "Engine/Content/Deprecated.h"
Variant::Variant(const CommonValue& value) Variant::Variant(const CommonValue& value)

View File

@@ -11,6 +11,9 @@ struct CommonValue;
template<typename T> template<typename T>
class AssetReference; class AssetReference;
struct ScriptingTypeHandle; struct ScriptingTypeHandle;
template<typename T>
class DataContainer;
typedef DataContainer<byte> BytesContainer;
/// <summary> /// <summary>
/// Represents an object type that can be interpreted as more than one type. /// Represents an object type that can be interpreted as more than one type.
@@ -244,6 +247,7 @@ public:
explicit Variant(Dictionary<Variant, Variant, HeapAllocation>&& v); explicit Variant(Dictionary<Variant, Variant, HeapAllocation>&& v);
explicit Variant(const Dictionary<Variant, Variant, HeapAllocation>& v); explicit Variant(const Dictionary<Variant, Variant, HeapAllocation>& v);
explicit Variant(const Span<byte>& v); explicit Variant(const Span<byte>& v);
explicit Variant(const BytesContainer& v);
explicit Variant(const CommonValue& v); explicit Variant(const CommonValue& v);
template<typename T> template<typename T>

View File

@@ -4,7 +4,6 @@
#define USE_GCHANDLE #define USE_GCHANDLE
//#define TRACK_HANDLES //#define TRACK_HANDLES
#if USE_NETCORE #if USE_NETCORE
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
#if USE_NETCORE #if USE_NETCORE
using FlaxEngine.Assertions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@@ -322,27 +323,24 @@ namespace FlaxEngine.Interop
#if FLAX_EDITOR #if FLAX_EDITOR
[HideInEditor] [HideInEditor]
#endif #endif
public struct ManagedToNative public static class ManagedToNative
{ {
ManagedHandle handle; public static object[] ConvertToManaged(NativeArray<IntPtr> unmanaged)
public void FromManaged(object[] managed)
{ {
if (managed != null) if (unmanaged.Data == null)
{ return null;
var managedArray = NativeInterop.ManagedArrayToGCHandleWrappedArray(managed); return NativeInterop.GCHandleArrayToManagedArray<object>(unmanaged);
handle = ManagedHandle.Alloc(managedArray, GCHandleType.Weak);
} }
} public static NativeArray<IntPtr> ConvertToUnmanaged(object[] managed)
public IntPtr ToUnmanaged()
{ {
return ManagedHandle.ToIntPtr(handle); if (managed == null)
return new NativeArray<IntPtr>();
return NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
} }
public static void Free(NativeArray<IntPtr> unmanaged)
public void Free()
{ {
handle.Free(); if (unmanaged.Data != null)
unmanaged.Free();
} }
} }
@@ -661,6 +659,431 @@ namespace FlaxEngine.Interop
} }
} }
#if FLAX_EDITOR
[HideInEditor]
#endif
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(BoxedArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(BoxedArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(BoxedArrayMarshaller<,>))]
[ContiguousCollectionMarshaller]
public static unsafe class BoxedArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class ManagedToNative
{
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
if (managed == null)
{
numElements = 0;
return new NativeArray<TUnmanagedElement>();
}
numElements = managed.Length;
return new NativeArray<TUnmanagedElement>(managed.Length);
}
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
{
if (managed == null)
return null;
return managed.AsSpan();
}
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
return unmanaged.AsSpan();
}
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
{
if (unmanaged.Data != null)
unmanaged.Free();
}
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class NativeToManaged
{
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
Assert.IsTrue(unmanaged.Length == numElements);
return new T[unmanaged.Length];
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
return unmanaged.AsReadOnlySpan();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
if (managed == null)
return null;
return managed.AsSpan();
}
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
{
if (unmanaged.Data == null)
return;
Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public struct Bidirectional
{
//string managed;
//IntPtr unmanaged;
public void FromManaged(T[] managed)
{
throw new NotImplementedException();
}
public T[] ToManaged()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetManagedValuesSource()
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetUnmanagedValuesDestination()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements)
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetManagedValuesDestination(int numElements)
{
throw new NotImplementedException();
}
public NativeArray<TUnmanagedElement> ToUnmanaged()
{
throw new NotImplementedException();
}
public void FromUnmanaged(NativeArray<TUnmanagedElement> unmanaged)
{
throw new NotImplementedException();
}
public void Free()
{
throw new NotImplementedException();
}
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
throw new NotImplementedException();
}
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
{
throw new NotImplementedException();
}
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
[StructLayout(LayoutKind.Sequential)]
public unsafe /*ref*/ struct NativeArray<T> where T : unmanaged
{
public T* Data;
public int Length;
public NativeArray(T* data, int length)
{
Data = data;
Length = length;
}
public NativeArray(Span<T> data)
{
Data = (T*)Marshal.AllocCoTaskMem(data.Length);
Length = data.Length;
for (int i = 0; i < data.Length; i++)
Unsafe.Copy(&Data[i], ref data[i]);
}
public NativeArray(IntPtr data, int length)
{
Data = (T*)data;
Length = length;
}
public NativeArray(int length)
{
Data = (T*)Marshal.AllocCoTaskMem(length);
Length = length;
}
public NativeArray()
{
Data = null;
Length = 0;
}
public void Free() => Marshal.FreeCoTaskMem((IntPtr)Data);
public Span<T> AsSpan() => new Span<T>(Data, Length);
public ReadOnlySpan<T> AsReadOnlySpan() => new Span<T>(Data, Length);
public static bool operator ==(NativeArray<T> left, NativeArray<T> right) => left.Data == right.Data && left.Length == right.Length;
public static bool operator !=(NativeArray<T> left, NativeArray<T> right) => left.Data != right.Data || left.Length != right.Length;
public static bool operator ==(NativeArray<T> left, IntPtr right) => left.Data == (T*)right;
public static bool operator !=(NativeArray<T> left, IntPtr right) => left.Data != (T*)right;
public static bool operator ==(IntPtr left, NativeArray<T> right) => (T*)left == right.Data;
public static bool operator !=(IntPtr left, NativeArray<T> right) => (T*)left != right.Data;
public override bool Equals(object obj)
{
if (obj is null) return false;
if (obj is NativeArray<T> arr) return this == arr;
if (obj is IntPtr ptr) return this == ptr;
return false;
}
public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();
}
#if FLAX_EDITOR
[HideInEditor]
#endif
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(NativeArrayMarshaller<,>))]
[ContiguousCollectionMarshaller]
public static unsafe class NativeArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class ManagedToNative
{
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
public static void Free(NativeArray<TUnmanagedElement> unmanaged) => throw new NotImplementedException();
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class NativeToManaged
{
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return Array.Empty<T>();
Assert.IsTrue(unmanaged.Length == numElements);
return new T[unmanaged.Length];
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
return unmanaged.AsReadOnlySpan();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
if (managed == null)
return null;
return managed.AsSpan();
}
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
{
if (unmanaged.Data == null)
return;
Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
}
#if FLAX_EDITOR
[HideInEditor]
#endif
public struct Bidirectional
{
//string managed;
//IntPtr unmanaged;
public void FromManaged(T[] managed)
{
throw new NotImplementedException();
}
public T[] ToManaged()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetManagedValuesSource()
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetUnmanagedValuesDestination()
{
throw new NotImplementedException();
}
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements)
{
throw new NotImplementedException();
}
public Span<TUnmanagedElement> GetManagedValuesDestination(int numElements)
{
throw new NotImplementedException();
}
public NativeArray<TUnmanagedElement> ToUnmanaged()
{
throw new NotImplementedException();
}
public void FromUnmanaged(NativeArray<TUnmanagedElement> unmanaged)
{
throw new NotImplementedException();
}
public void Free()
{
throw new NotImplementedException();
}
}
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
throw new NotImplementedException();
}
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
{
throw new NotImplementedException();
}
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
{
throw new NotImplementedException();
}
public static Span<T> GetManagedValuesDestination(T[] managed)
{
throw new NotImplementedException();
}
}
#if FLAX_EDITOR #if FLAX_EDITOR
[HideInEditor] [HideInEditor]
#endif #endif

View File

@@ -188,6 +188,28 @@ namespace FlaxEngine.Interop
return Marshal.GetFunctionPointerForDelegate<TDelegate>(d); return Marshal.GetFunctionPointerForDelegate<TDelegate>(d);
} }
/// <summary>
/// Converts array of GC Handles from native runtime to managed array.
/// </summary>
/// <typeparam name="T">Array element type.</typeparam>
/// <param name="ptrArray">Input array.</param>
/// <param name="buffer">Cached memory allocation buffer to use for the result (if size fits).</param>
/// <returns>Output array.</returns>
public static T[] GCHandleArrayToManagedArray<T>(NativeArray<IntPtr> ptrArray, T[] buffer = null) where T : class
{
ReadOnlySpan<IntPtr> span = ptrArray.AsReadOnlySpan();
if (buffer != null)
buffer = buffer;
if (buffer == null || buffer.Length < ptrArray.Length)
buffer = new T[ptrArray.Length];
for (int i = 0; i < ptrArray.Length; i++)
{
IntPtr ptr = span[i];
buffer[i] = ptr != IntPtr.Zero ? (T)ManagedHandle.FromIntPtr(ptr).Target : default;
}
return buffer;
}
/// <summary> /// <summary>
/// Converts array of GC Handles from native runtime to managed array. /// Converts array of GC Handles from native runtime to managed array.
/// </summary> /// </summary>
@@ -238,6 +260,24 @@ namespace FlaxEngine.Interop
return ManagedArray.WrapNewArray(pointerArray, array.GetType()); return ManagedArray.WrapNewArray(pointerArray, array.GetType());
} }
/// <summary>
/// Converts managed array wrapper into array of GC Handles for native runtime.
/// </summary>
/// <param name="array">Input array.</param>
/// <returns>Output array.</returns>
public static NativeArray<IntPtr> ManagedArrayToGCHandleWrappedArray<T>(T[] array)
{
NativeArray<IntPtr> pointerArray = new(array.Length);
for (int i = 0; i < array.Length; i++)
//foreach (var ptr in pointerArray.AsSpan())
{
pointerArray.Data[i] = array[i] != null ? ManagedHandle.ToIntPtr(array[i]) : IntPtr.Zero;
}
return pointerArray;
//IntPtr[] pointerArray = ManagedArrayToGCHandleArray(array);
//return ManagedArray.WrapNewArray(pointerArray, array.GetType());
}
/// <summary> /// <summary>
/// Converts array with a custom converter function for each element. /// Converts array with a custom converter function for each element.
/// </summary> /// </summary>
@@ -270,6 +310,23 @@ namespace FlaxEngine.Interop
return dst; return dst;
} }
/// <summary>
/// Converts array with a custom converter function for each element.
/// </summary>
/// <typeparam name="TSrc">Input data type.</typeparam>
/// <typeparam name="TDst">Output data type.</typeparam>
/// <param name="src">The input array.</param>
/// <param name="convertFunc">Converter callback.</param>
/// <returns>The output array.</returns>
public static NativeArray<TDst> ConvertArrayNative<TSrc, TDst>(this Span<TSrc> src, Func<TSrc, TDst> convertFunc)
where TDst : unmanaged
{
NativeArray<TDst> dst = new(src.Length);
for (int i = 0; i < src.Length; i++)
dst.Data[i] = convertFunc(src[i]);
return dst;
}
/// <summary>Find <paramref name="assemblyName"/> among the scripting assemblies.</summary> /// <summary>Find <paramref name="assemblyName"/> among the scripting assemblies.</summary>
/// <param name="assemblyName">The name to find</param> /// <param name="assemblyName">The name to find</param>
/// <param name="allowPartial">If true, partial names should be allowed to be resolved.</param> /// <param name="allowPartial">If true, partial names should be allowed to be resolved.</param>
@@ -1140,13 +1197,18 @@ namespace FlaxEngine.Interop
internal static void ToManagedArray(ref T[] managedValue, IntPtr nativePtr, bool byRef) internal static void ToManagedArray(ref T[] managedValue, IntPtr nativePtr, bool byRef)
{ {
if (byRef) //if (byRef)
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer()); // nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
if (nativePtr != IntPtr.Zero) if (nativePtr != IntPtr.Zero)
{ {
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target); int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>()); nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
var span = new Span<T>(nativePtr.ToPointer(), length);
managedValue = span.ToArray();
//ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
//managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
} }
else else
managedValue = null; managedValue = null;

View File

@@ -68,13 +68,13 @@ public:
struct FLAXENGINE_API Object struct FLAXENGINE_API Object
{ {
static MObject* Box(void* value, const MClass* klass); static MObject* Box(void* value, const MClass* klass);
static void* Unbox(MObject* obj); static void* Unbox(const MObject* obj);
static void Unbox(MObject* obj, void* dest); static void Unbox(const MObject* obj, void* dest);
static MObject* New(const MClass* klass); static MObject* New(const MClass* klass);
static void Init(MObject* obj); static void Init(const MObject* obj);
static MClass* GetClass(MObject* obj); static MClass* GetClass(const MObject* obj);
static MString* ToString(MObject* obj); static MString* ToString(const MObject* obj);
static int32 GetHashCode(MObject* obj); static int32 GetHashCode(const MObject* obj);
}; };
/// <summary> /// <summary>
@@ -82,11 +82,11 @@ public:
/// </summary> /// </summary>
struct FLAXENGINE_API String struct FLAXENGINE_API String
{ {
static MString* GetEmpty(MDomain* domain = nullptr); static MString* GetEmpty(const MDomain* domain = nullptr);
static MString* New(const char* str, int32 length, MDomain* domain = nullptr); static MString* New(const char* str, int32 length, const MDomain* domain = nullptr);
static MString* New(const Char* str, int32 length, MDomain* domain = nullptr); static MString* New(const Char* str, int32 length, const MDomain* domain = nullptr);
static void Free(MString* obj); static void Free(const MString* obj);
static StringView GetChars(MString* obj); static StringView GetChars(const MString* obj);
}; };
/// <summary> /// <summary>
@@ -96,11 +96,11 @@ public:
{ {
static MArray* New(const MClass* elementKlass, int32 length); static MArray* New(const MClass* elementKlass, int32 length);
static void Free(const MArray* array); static void Free(const MArray* array);
static MClass* GetClass(MClass* elementKlass); static MClass* GetClass(const MClass* elementKlass);
static MClass* GetArrayClass(const MArray* obj); static MClass* GetArrayClass(const MArray* obj);
static int32 GetLength(const MArray* obj); static int32 GetLength(const MArray* obj);
static void* GetAddress(const MArray* obj); static void* GetAddress(const MArray* obj);
static MArray* Unbox(MObject* obj); static MArray* Unbox(const MObject* obj);
template<typename T> template<typename T>
FORCE_INLINE static T* GetAddress(const MArray* obj) FORCE_INLINE static T* GetAddress(const MArray* obj)
@@ -114,8 +114,8 @@ public:
/// </summary> /// </summary>
struct FLAXENGINE_API GCHandle struct FLAXENGINE_API GCHandle
{ {
static MGCHandle New(MObject* obj, bool pinned = false); static MGCHandle New(const MObject* obj, bool pinned = false);
static MGCHandle NewWeak(MObject* obj, bool trackResurrection = false); static MGCHandle NewWeak(const MObject* obj, bool trackResurrection = false);
static MObject* GetTarget(const MGCHandle& handle); static MObject* GetTarget(const MGCHandle& handle);
static void Free(const MGCHandle& handle); static void Free(const MGCHandle& handle);
}; };

View File

@@ -106,7 +106,7 @@ public:
/// </remarks> /// </remarks>
/// <param name="instance">The object of given type to get value from.</param> /// <param name="instance">The object of given type to get value from.</param>
/// <param name="result">The return value of undefined type.</param> /// <param name="result">The return value of undefined type.</param>
void GetValue(MObject* instance, void* result) const; void GetValue(const MObject* instance, void* result) const;
/// <summary> /// <summary>
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. /// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null.
@@ -116,14 +116,14 @@ public:
/// </remarks> /// </remarks>
/// <param name="instance">The object of given type to get value from.</param> /// <param name="instance">The object of given type to get value from.</param>
/// <param name="result">The return value of undefined type.</param> /// <param name="result">The return value of undefined type.</param>
void GetValueReference(MObject* instance, void* result) const; void GetValueReference(const MObject* instance, void* result) const;
/// <summary> /// <summary>
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed. /// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed.
/// </summary> /// </summary>
/// <param name="instance">The object of given type to get value from.</param> /// <param name="instance">The object of given type to get value from.</param>
/// <returns>The boxed value object.</returns> /// <returns>The boxed value object.</returns>
MObject* GetValueBoxed(MObject* instance) const; MObject* GetValueBoxed(const MObject* instance) const;
/// <summary> /// <summary>
/// Sets a value for the field on the specified object instance. If field is static object instance can be null. /// Sets a value for the field on the specified object instance. If field is static object instance can be null.
@@ -133,7 +133,7 @@ public:
/// </remarks> /// </remarks>
/// <param name="instance">The object of given type to set value to.</param> /// <param name="instance">The object of given type to set value to.</param>
/// <param name="value">Th value of undefined type.</param> /// <param name="value">Th value of undefined type.</param>
void SetValue(MObject* instance, void* value) const; void SetValue(const MObject* instance, void* value) const;
public: public:
/// <summary> /// <summary>

View File

@@ -13,6 +13,12 @@
#if USE_CSHARP #if USE_CSHARP
/*static_assert(TIsPODType<int>::Value, "int not pod type?");
static_assert(TIsPODType<Float3>::Value, "Float3 not pod type?");
static_assert(!TIsPODType<ScriptingObject>::Value, "ScriptingObject not pod type?");
static_assert(TIsPODType<Char>::Value, "Char not pod type?");
static_assert(TIsPODType<char>::Value, "char not pod type?");*/
struct Version; struct Version;
class CultureInfo; class CultureInfo;
template<typename AllocationType> template<typename AllocationType>
@@ -49,6 +55,12 @@ struct MConverter
{ {
MObject* Box(const T& data, const MClass* klass); MObject* Box(const T& data, const MClass* klass);
void Unbox(T& result, MObject* data); void Unbox(T& result, MObject* data);
/*template<typename U>
void ToManaged(U& result, const T& data);
template<typename U>
void ToNative(T& result, const U& data);
void ToManaged(MObject*& result, const T& data);
void ToNative(T& result, const MObject*& data);*/
void FreeManaged(MObject* data); void FreeManaged(MObject* data);
void ToManagedArray(MArray* result, const Span<T>& data); void ToManagedArray(MArray* result, const Span<T>& data);
void ToNativeArray(Span<T>& result, const MArray* data); void ToNativeArray(Span<T>& result, const MArray* data);
@@ -61,6 +73,16 @@ struct NativeArray
{ {
T* data; T* data;
int32 length; int32 length;
FORCE_INLINE operator T*() const
{
return data;
}
FORCE_INLINE Span<T> ToSpan() const
{
return Span<T>(data, length);
}
}; };
#if USE_NETCORE #if USE_NETCORE
@@ -79,6 +101,16 @@ struct MConverter<bool>
MCore::Object::Unbox(data, &result); MCore::Object::Unbox(data, &result);
} }
void ToManaged(bool& result, const bool& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(bool& result, const bool& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
} }
@@ -116,6 +148,16 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
MCore::Object::Unbox(data, &result); MCore::Object::Unbox(data, &result);
} }
void ToManaged(T& result, const T& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(T& result, const T& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<T>& data) void ToManagedArray(MArray* result, const Span<T>& data)
{ {
Platform::MemoryCopy(MCore::Array::GetAddress(result), data.Get(), data.Length() * sizeof(T)); Platform::MemoryCopy(MCore::Array::GetAddress(result), data.Get(), data.Length() * sizeof(T));
@@ -162,6 +204,16 @@ struct MConverter<String>
//#endif //#endif
} }
void ToManaged(String& result, const String& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(String& result, const String& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<String>& data) void ToManagedArray(MArray* result, const Span<String>& data)
{ {
if (data.Length() == 0) if (data.Length() == 0)
@@ -212,6 +264,16 @@ struct MConverter<StringAnsi>
result = MUtils::ToStringAnsi((MString*)data); result = MUtils::ToStringAnsi((MString*)data);
} }
void ToManaged(StringAnsi& result, const StringAnsi& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(StringAnsi& result, const StringAnsi& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<StringAnsi>& data) void ToManagedArray(MArray* result, const Span<StringAnsi>& data)
{ {
if (data.Length() == 0) if (data.Length() == 0)
@@ -262,6 +324,16 @@ struct MConverter<StringView>
result = MUtils::ToString((MString*)data); result = MUtils::ToString((MString*)data);
} }
void ToManaged(StringView& result, const StringView& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(StringView& result, const StringView& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<StringView>& data) void ToManagedArray(MArray* result, const Span<StringView>& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME PLATFORM_DEBUG_BREAK; // FIXME
@@ -316,6 +388,16 @@ struct MConverter<Variant>
result = MUtils::UnboxVariant(data); result = MUtils::UnboxVariant(data);
} }
void ToManaged(Variant& result, const Variant& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(Variant& result, const Variant& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<Variant>& data) void ToManagedArray(MArray* result, const Span<Variant>& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME PLATFORM_DEBUG_BREAK; // FIXME
@@ -365,6 +447,18 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
result = (T*)ScriptingObject::ToNative(data); result = (T*)ScriptingObject::ToNative(data);
} }
void ToManaged(MObject*& result, const T* data)
{
//PLATFORM_DEBUG_BREAK; // FIXME
result = data ? data->GetOrCreateManagedInstance() : nullptr;
}
void ToNative(T*& result, const MObject* data)
{
PLATFORM_DEBUG_BREAK; // FIXME
result = (T*)ScriptingObject::ToNative(data);
}
void ToManagedArray(MArray* result, const Span<T*>& data) void ToManagedArray(MArray* result, const Span<T*>& data)
{ {
if (data.Length() == 0) if (data.Length() == 0)
@@ -405,9 +499,29 @@ struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Val
return data.GetOrCreateManagedInstance(); return data.GetOrCreateManagedInstance();
} }
void ToManagedArray(MArray* result, const Span<T>& data) void ToManaged(MObject*& result, const T& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(T& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
/*void ToManaged(MObject*& result, const T*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(T*& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}*/
void ToManagedArray(MArray* result, const Span<T>& data)
{
//PLATFORM_DEBUG_BREAK; // FIXME
if (data.Length() == 0) if (data.Length() == 0)
return; return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*)); MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -449,6 +563,16 @@ struct MConverter<ScriptingObjectReference<T>>
result = (T*)ScriptingObject::ToNative(data); result = (T*)ScriptingObject::ToNative(data);
} }
void ToManaged(MObject*& result, const ScriptingObjectReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(ScriptingObjectReference<T>& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<ScriptingObjectReference<T>>& data) void ToManagedArray(MArray* result, const Span<ScriptingObjectReference<T>>& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME PLATFORM_DEBUG_BREAK; // FIXME
@@ -501,6 +625,17 @@ struct MConverter<AssetReference<T>>
result = (T*)ScriptingObject::ToNative(data); result = (T*)ScriptingObject::ToNative(data);
} }
void ToManaged(MObject*& result, const AssetReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
result = data.GetManagedInstance();
}
void ToNative(AssetReference<T>& result, const MObject* data)
{
result = (T*)ScriptingObject::ToNative(data);
}
void ToManagedArray(MArray* result, const Span<AssetReference<T>>& data) void ToManagedArray(MArray* result, const Span<AssetReference<T>>& data)
{ {
if (data.Length() == 0) if (data.Length() == 0)
@@ -538,6 +673,29 @@ class SoftAssetReference;
template<typename T> template<typename T>
struct MConverter<SoftAssetReference<T>> struct MConverter<SoftAssetReference<T>>
{ {
template <typename U>
void ToManaged(U& result, const SoftAssetReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
template <typename U>
void ToNative(SoftAssetReference<T>& result, const U& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManaged(MObject*& result, const SoftAssetReference<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(SoftAssetReference<T>& result, const MObject*& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToManagedArray(MArray* result, const Span<SoftAssetReference<T>>& data) void ToManagedArray(MArray* result, const Span<SoftAssetReference<T>>& data)
{ {
//PLATFORM_DEBUG_BREAK; // FIXME //PLATFORM_DEBUG_BREAK; // FIXME
@@ -575,6 +733,16 @@ struct MConverter<SoftAssetReference<T>>
template<typename T> template<typename T>
struct MConverter<Array<T>> struct MConverter<Array<T>>
{ {
void ToManaged(Array<T>& result, const Array<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
void ToNative(Array<T>& result, const Array<T>& data)
{
PLATFORM_DEBUG_BREAK; // FIXME
}
MObject* Box(const Array<T>& data, const MClass* klass) MObject* Box(const Array<T>& data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME PLATFORM_DEBUG_BREAK; // FIXME
@@ -877,12 +1045,36 @@ namespace MUtils
return arr; return arr;
} }
/// <summary>
/// Allocates new managed array of data and copies contents from given native array.
/// </summary>
/// <param name="data">The array object.</param>
/// <param name="valueClass">The array values type class.</param>
/// <returns>The output array.</returns>
/*template<typename T, typename U>
NativeArray<U> ToManagedArrayWrapper(const Span<T>& data, const MClass* valueClass)
{
if (!valueClass)
return nullptr;
MArray* result = MCore::Array::New(valueClass, data.Length());
MConverter<T> converter;
converter.ToManagedArray(result, data);
return result;
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<U> arr;
arr.length = data.Count();
arr.data = (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true);
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(U));
return arr;
}*/
/// <summary> /// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data. /// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary> /// </summary>
/// <param name="data">The input data.</param> /// <param name="data">The input data.</param>
/// <returns>The output array.</returns> /// <returns>The output array.</returns>
template<typename T, typename AllocationType = HeapAllocation> /*template<typename T, typename AllocationType = HeapAllocation>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Array<T, AllocationType>& data) FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
{ {
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer // System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
@@ -893,22 +1085,233 @@ namespace MUtils
return arr; return arr;
} }
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename U, typename AllocationType = HeapAllocation>
FORCE_INLINE NativeArray<U> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<U> arr;
arr.length = data.Count();
arr.data = (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true);
// Convert to managed
MConverter<T, U> converter;
for (int i = 0; i < arr.length; ++i)
arr.data[i] = converter.ToManaged(data[i]);
return arr;
}*/
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename U>
FORCE_INLINE NativeArray<U> ToManagedArrayWrapperConvert(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<U> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true) : nullptr;
// Convert to managed
MConverter<T, U> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToManaged(arr.data[i], data[i]);
return arr;
}
/// <summary> /// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data. /// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary> /// </summary>
/// <param name="data">The input data.</param> /// <param name="data">The input data.</param>
/// <returns>The output array.</returns> /// <returns>The output array.</returns>
template<typename T> template<typename T>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Span<T>& data) FORCE_INLINE NativeArray<T> ToNativeArrayWrapperConvertGeneric(const Span<MObject*>& data)
{ {
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer // System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr; NativeArray<T> arr;
arr.length = data.Length(); arr.length = data.Length();
arr.data = (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true); arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
// Convert to managed
MConverter<T> converter;
for (int i = 0; i < arr.length; ++i)
{
converter.ToNative(arr.data[i], data[i]);
}
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename AllocationType = HeapAllocation>
FORCE_INLINE void ToNativeArrayWrapperConvertGeneric(const Span<MObject*>& data, Array<T, AllocationType>& array)
{
if (!array.IsEmpty())
PLATFORM_DEBUG_BREAK; // TODO: does the array require ClearDelete instead?
auto length = data.Length();
array.Resize(length, false);
//array.Clear();
//array.EnsureCapacity(length);
MConverter<T> converter;
for (int i = 0; i < length; ++i)
{
// Make sure the destination is default initialized first
//array.AddUninitialized();
//array.AddDefault();
//T& dest = array.Get()[i];
//new(&dest)AssetReference<T>();
// Convert from managed
converter.ToNative(array.Get()[i], data[i]);
}
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename U>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperConvert(const Span<U>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
// Convert to managed
MConverter<T, U> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToNative(arr.data[i], data[i]);
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperCopy(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T)); Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr; return arr;
} }
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
/*FORCE_INLINE NativeArray<Char> ToManagedArrayWrapper(const Span<Char>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<Char> arr;
arr.length = data.Length();
arr.data = (Char*)MCore::GC::AllocateMemory(arr.length * sizeof(Char), true);
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(Char));
return arr;
}*/
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToManagedArrayWrapperConvert(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
//Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
// Convert to managed
MConverter<T> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToManaged(arr.data[i], data[i]);
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToManagedArrayWrapperCopy(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
/*template<typename T>
FORCE_INLINE NativeArray<MObject*> ToManagedArrayWrapperPointer(const Span<T*>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<MObject*> arr;
arr.length = data.Length();
arr.data = (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), true);
// Convert to managed
MConverter<T*> converter;
for (int i = 0; i < arr.length; ++i)
{
MObject*& ptr = arr.data[i];
const T& asd = data[i];
converter.ToManaged(ptr, asd);
}
return arr;
}*/
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<class T>
FORCE_INLINE NativeArray<MObject*> ToManagedArrayWrapperPointer(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<MObject*> arr;
arr.length = data.Length();
arr.data = arr.length > 0 ? (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), true) : nullptr;
// Convert to managed
MConverter<T> converter;
for (int i = 0; i < arr.length; ++i)
converter.ToManaged(arr.data[i], data[i]);
return arr;
}
/// <summary> /// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data. /// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary> /// </summary>

View File

@@ -399,15 +399,15 @@ MObject* MCore::Object::Box(void* value, const MClass* klass)
return (MObject*)CallStaticMethod<void*, void*, void*>(BoxValuePtr, klass->_handle, value); return (MObject*)CallStaticMethod<void*, void*, void*>(BoxValuePtr, klass->_handle, value);
} }
void* MCore::Object::Unbox(MObject* obj) void* MCore::Object::Unbox(const MObject* obj)
{ {
CRASH; // Should not be used anymore CRASH; // Should not be used anymore
} }
void MCore::Object::Unbox(MObject* obj, void* dest) void MCore::Object::Unbox(const MObject* obj, void* dest)
{ {
static void* UnboxValuePtr = GetStaticMethodPointer(TEXT("UnboxValue")); static void* UnboxValuePtr = GetStaticMethodPointer(TEXT("UnboxValue"));
return CallStaticMethod<void, void*, void*>(UnboxValuePtr, obj, dest); return CallStaticMethod<void, const void*, void*>(UnboxValuePtr, obj, dest);
} }
MObject* MCore::Object::New(const MClass* klass) MObject* MCore::Object::New(const MClass* klass)
@@ -416,61 +416,61 @@ MObject* MCore::Object::New(const MClass* klass)
return (MObject*)CallStaticMethod<void*, void*>(NewObjectPtr, klass->_handle); return (MObject*)CallStaticMethod<void*, void*>(NewObjectPtr, klass->_handle);
} }
void MCore::Object::Init(MObject* obj) void MCore::Object::Init(const MObject* obj)
{ {
static void* ObjectInitPtr = GetStaticMethodPointer(TEXT("ObjectInit")); static void* ObjectInitPtr = GetStaticMethodPointer(TEXT("ObjectInit"));
CallStaticMethod<void, void*>(ObjectInitPtr, obj); CallStaticMethod<void, const void*>(ObjectInitPtr, obj);
} }
MClass* MCore::Object::GetClass(MObject* obj) MClass* MCore::Object::GetClass(const MObject* obj)
{ {
ASSERT(obj); ASSERT(obj);
static void* GetObjectClassPtr = GetStaticMethodPointer(TEXT("GetObjectClass")); static void* GetObjectClassPtr = GetStaticMethodPointer(TEXT("GetObjectClass"));
return (MClass*)CallStaticMethod<MClass*, void*>(GetObjectClassPtr, obj); return (MClass*)CallStaticMethod<MClass*, const void*>(GetObjectClassPtr, obj);
} }
MString* MCore::Object::ToString(MObject* obj) MString* MCore::Object::ToString(const MObject* obj)
{ {
static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectString")); static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectString"));
return (MString*)CallStaticMethod<void*, void*>(GetObjectStringPtr, obj); return (MString*)CallStaticMethod<void*, const void*>(GetObjectStringPtr, obj);
} }
int32 MCore::Object::GetHashCode(MObject* obj) int32 MCore::Object::GetHashCode(const MObject* obj)
{ {
static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectHashCode")); static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectHashCode"));
return CallStaticMethod<int32, void*>(GetObjectStringPtr, obj); return CallStaticMethod<int32, const void*>(GetObjectStringPtr, obj);
} }
MString* MCore::String::GetEmpty(MDomain* domain) MString* MCore::String::GetEmpty(const MDomain* domain)
{ {
static void* GetStringEmptyPtr = GetStaticMethodPointer(TEXT("GetStringEmpty")); static void* GetStringEmptyPtr = GetStaticMethodPointer(TEXT("GetStringEmpty"));
return (MString*)CallStaticMethod<void*>(GetStringEmptyPtr); return (MString*)CallStaticMethod<void*>(GetStringEmptyPtr);
} }
MString* MCore::String::New(const char* str, int32 length, MDomain* domain) MString* MCore::String::New(const char* str, int32 length, const MDomain* domain)
{ {
static void* NewStringUTF8Ptr = GetStaticMethodPointer(TEXT("NewStringUTF8")); static void* NewStringUTF8Ptr = GetStaticMethodPointer(TEXT("NewStringUTF8"));
return (MString*)CallStaticMethod<void*, const char*, int>(NewStringUTF8Ptr, str, length); return (MString*)CallStaticMethod<void*, const char*, int>(NewStringUTF8Ptr, str, length);
} }
MString* MCore::String::New(const Char* str, int32 length, MDomain* domain) MString* MCore::String::New(const Char* str, int32 length, const MDomain* domain)
{ {
static void* NewStringUTF16Ptr = GetStaticMethodPointer(TEXT("NewStringUTF16")); static void* NewStringUTF16Ptr = GetStaticMethodPointer(TEXT("NewStringUTF16"));
return (MString*)CallStaticMethod<void*, const Char*, int>(NewStringUTF16Ptr, str, length); return (MString*)CallStaticMethod<void*, const Char*, int>(NewStringUTF16Ptr, str, length);
} }
StringView MCore::String::GetChars(MString* obj) StringView MCore::String::GetChars(const MString* obj)
{ {
int32 length = 0; int32 length = 0;
static void* GetStringPointerPtr = GetStaticMethodPointer(TEXT("GetStringPointer")); static void* GetStringPointerPtr = GetStaticMethodPointer(TEXT("GetStringPointer"));
const Char* chars = CallStaticMethod<const Char*, void*, int*>(GetStringPointerPtr, obj, &length); const Char* chars = CallStaticMethod<const Char*, const void*, int*>(GetStringPointerPtr, obj, &length);
return StringView(chars, length); return StringView(chars, length);
} }
void MCore::String::Free(MString* obj) void MCore::String::Free(const MString* obj)
{ {
static void* FreeStringPtr = GetStaticMethodPointer(TEXT("FreeString")); static void* FreeStringPtr = GetStaticMethodPointer(TEXT("FreeString"));
CallStaticMethod<void, void*>(FreeStringPtr, obj); CallStaticMethod<void, const void*>(FreeStringPtr, obj);
} }
MArray* MCore::Array::New(const MClass* elementKlass, int32 length) MArray* MCore::Array::New(const MClass* elementKlass, int32 length)
@@ -485,7 +485,7 @@ void MCore::Array::Free(const MArray* array)
CallStaticMethod<void, void*>(FreeArrayPtr, (void*)array); CallStaticMethod<void, void*>(FreeArrayPtr, (void*)array);
} }
MClass* MCore::Array::GetClass(MClass* elementKlass) MClass* MCore::Array::GetClass(const MClass* elementKlass)
{ {
static void* GetArrayTypeFromElementTypePtr = GetStaticMethodPointer(TEXT("GetArrayTypeFromElementType")); static void* GetArrayTypeFromElementTypePtr = GetStaticMethodPointer(TEXT("GetArrayTypeFromElementType"));
MType* typeHandle = (MType*)CallStaticMethod<void*, void*>(GetArrayTypeFromElementTypePtr, elementKlass->_handle); MType* typeHandle = (MType*)CallStaticMethod<void*, void*>(GetArrayTypeFromElementTypePtr, elementKlass->_handle);
@@ -511,24 +511,24 @@ void* MCore::Array::GetAddress(const MArray* obj)
return CallStaticMethod<void*, void*>(GetArrayPointerPtr, (void*)obj); return CallStaticMethod<void*, void*>(GetArrayPointerPtr, (void*)obj);
} }
MArray* MCore::Array::Unbox(MObject* obj) MArray* MCore::Array::Unbox(const MObject* obj)
{ {
static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray")); static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray"));
return (MArray*)CallStaticMethod<void*, void*>(GetArrayPtr, (void*)obj); return (MArray*)CallStaticMethod<void*, void*>(GetArrayPtr, (void*)obj);
} }
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned) MGCHandle MCore::GCHandle::New(const MObject* obj, bool pinned)
{ {
ASSERT(obj); ASSERT(obj);
static void* NewGCHandlePtr = GetStaticMethodPointer(TEXT("NewGCHandle")); static void* NewGCHandlePtr = GetStaticMethodPointer(TEXT("NewGCHandle"));
return (MGCHandle)CallStaticMethod<void*, void*, bool>(NewGCHandlePtr, obj, pinned); return (MGCHandle)CallStaticMethod<void*, const void*, bool>(NewGCHandlePtr, obj, pinned);
} }
MGCHandle MCore::GCHandle::NewWeak(MObject* obj, bool trackResurrection) MGCHandle MCore::GCHandle::NewWeak(const MObject* obj, bool trackResurrection)
{ {
ASSERT(obj); ASSERT(obj);
static void* NewGCHandleWeakPtr = GetStaticMethodPointer(TEXT("NewGCHandleWeak")); static void* NewGCHandleWeakPtr = GetStaticMethodPointer(TEXT("NewGCHandleWeak"));
return (MGCHandle)CallStaticMethod<void*, void*, bool>(NewGCHandleWeakPtr, obj, trackResurrection); return (MGCHandle)CallStaticMethod<void*, const void*, bool>(NewGCHandleWeakPtr, obj, trackResurrection);
} }
MObject* MCore::GCHandle::GetTarget(const MGCHandle& handle) MObject* MCore::GCHandle::GetTarget(const MGCHandle& handle)
@@ -1387,28 +1387,28 @@ int32 MField::GetOffset() const
return _fieldOffset; return _fieldOffset;
} }
void MField::GetValue(MObject* instance, void* result) const void MField::GetValue(const MObject* instance, void* result) const
{ {
static void* FieldGetValuePtr = GetStaticMethodPointer(TEXT("FieldGetValue")); static void* FieldGetValuePtr = GetStaticMethodPointer(TEXT("FieldGetValue"));
CallStaticMethod<void, void*, void*, void*>(FieldGetValuePtr, instance, _handle, result); CallStaticMethod<void, const void*, void*, void*>(FieldGetValuePtr, instance, _handle, result);
} }
void MField::GetValueReference(MObject* instance, void* result) const void MField::GetValueReference(const MObject* instance, void* result) const
{ {
static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReference")); static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReference"));
CallStaticMethod<void, void*, void*, int, void*>(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result); CallStaticMethod<void, const void*, void*, int, void*>(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result);
} }
MObject* MField::GetValueBoxed(MObject* instance) const MObject* MField::GetValueBoxed(const MObject* instance) const
{ {
static void* FieldGetValueBoxedPtr = GetStaticMethodPointer(TEXT("FieldGetValueBoxed")); static void* FieldGetValueBoxedPtr = GetStaticMethodPointer(TEXT("FieldGetValueBoxed"));
return CallStaticMethod<MObject*, void*, void*>(FieldGetValueBoxedPtr, instance, _handle); return CallStaticMethod<MObject*, const void*, void*>(FieldGetValueBoxedPtr, instance, _handle);
} }
void MField::SetValue(MObject* instance, void* value) const void MField::SetValue(const MObject* instance, void* value) const
{ {
static void* FieldSetValuePtr = GetStaticMethodPointer(TEXT("FieldSetValue")); static void* FieldSetValuePtr = GetStaticMethodPointer(TEXT("FieldSetValue"));
CallStaticMethod<void, void*, void*, void*>(FieldSetValuePtr, instance, _handle, value); CallStaticMethod<void, const void*, void*, void*>(FieldSetValuePtr, instance, _handle, value);
} }
bool MField::HasAttribute(const MClass* klass) const bool MField::HasAttribute(const MClass* klass) const

View File

@@ -245,7 +245,7 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand
return result; return result;
} }
ScriptingObject* ScriptingObject::ToNative(MObject* obj) ScriptingObject* ScriptingObject::ToNative(const MObject* obj)
{ {
ScriptingObject* ptr = nullptr; ScriptingObject* ptr = nullptr;
#if USE_CSHARP #if USE_CSHARP

View File

@@ -132,7 +132,7 @@ public:
return (T*)ToInterface(obj, T::TypeInitializer); return (T*)ToInterface(obj, T::TypeInitializer);
} }
static ScriptingObject* ToNative(MObject* obj); static ScriptingObject* ToNative(const MObject* obj);
FORCE_INLINE static MObject* ToManaged(const ScriptingObject* obj) FORCE_INLINE static MObject* ToManaged(const ScriptingObject* obj)
{ {

View File

@@ -635,10 +635,16 @@ namespace Flax.Build.Bindings
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))"; returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (functionInfo.ReturnType.IsArrayOrSpan || returnNativeType == "Array") else if (functionInfo.ReturnType.IsArrayOrSpan || returnNativeType == "Array")
{ {
var elementApiType = functionInfo.ReturnType.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, functionInfo.ReturnType.GenericArgs[0], caller) : null;
string unmanagedType = ""; string unmanagedType = "";
if (functionInfo.ReturnType.GenericArgs != null && functionInfo.ReturnType.GenericArgs[0].IsPod(buildData, caller)) //if (functionInfo.ReturnType.GenericArgs != null && functionInfo.ReturnType.GenericArgs[0].IsPod(buildData, caller))
{ var genericType = functionInfo.ReturnType.GenericArgs?[0].Type;
switch (functionInfo.ReturnType.GenericArgs[0].Type) if (functionInfo.ReturnType.Type == "BytesContainer")
genericType = "byte";
if (functionInfo.ReturnType.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
genericType = null;
switch (genericType)
{ {
case "bool": unmanagedType = "U1"; break; case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break; case "byte": unmanagedType = "U1"; break;
@@ -668,12 +674,22 @@ namespace Flax.Build.Bindings
unmanagedType = "Any"; // FIXME unmanagedType = "Any"; // FIXME
break; break;
case null:
case "":
case "String":
case "StringAnsi":
case "StringView":
unmanagedType = null;
break;
default: default:
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
unmanagedType = null;
else
unmanagedType = "Any"; unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'"); //Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break; break;
} }
}
if (!string.IsNullOrEmpty(unmanagedType)) if (!string.IsNullOrEmpty(unmanagedType))
{ {
string arraySubType = ""; string arraySubType = "";
@@ -681,18 +697,22 @@ namespace Flax.Build.Bindings
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, "; arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
returnMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__returnCount"))})"; returnMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__returnCount"))})";
} }
else if (genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
returnMarshalType = $"/*marsh2c*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<string, IntPtr>), CountElementName = \"__returnCount\")";
else if (elementApiType?.IsValueType ?? true)
returnMarshalType = $"/*marsh2a*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<,>), CountElementName = \"__returnCount\")";
else else
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")"; returnMarshalType = $"/*marsh2b*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__returnCount\")";
} }
else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BytesContainer" || returnNativeType == "Array") else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BytesContainer" || returnNativeType == "Array")
{ {
//[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 8)] //[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 8)]
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = nameof(__returnCount))"; returnMarshalType = "/*marsh3*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
} }
else if (functionInfo.ReturnType.Type == "Dictionary") else if (functionInfo.ReturnType.Type == "Dictionary")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)"; returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
else if (returnValueType == "byte[]") else if (returnValueType == "byte[]")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")"; returnMarshalType = "/*marsh4*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__returnCount\")";
else if (returnValueType == "bool[]") else if (returnValueType == "bool[]")
{ {
// Boolean arrays does not support custom marshalling for some unknown reason // Boolean arrays does not support custom marshalling for some unknown reason
@@ -742,10 +762,15 @@ namespace Flax.Build.Bindings
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))"; parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (parameterInfo.Type.IsArrayOrSpan || nativeType == "Array") else if (parameterInfo.Type.IsArrayOrSpan || nativeType == "Array")
{ {
var elementApiType = parameterInfo.Type.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null;
string unmanagedType = ""; string unmanagedType = "";
if (parameterInfo.Type.GenericArgs != null && parameterInfo.Type.GenericArgs[0].IsPod(buildData, caller)) var genericType = parameterInfo.Type.GenericArgs?[0].Type;
{ if (parameterInfo.Type.Type == "BytesContainer")
switch (parameterInfo.Type.GenericArgs[0].Type) genericType = "byte";
if (parameterInfo.Type.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
genericType = null;
switch (genericType)
{ {
case "bool": unmanagedType = "U1"; break; case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break; case "byte": unmanagedType = "U1"; break;
@@ -775,12 +800,28 @@ namespace Flax.Build.Bindings
unmanagedType = "Any"; // FIXME unmanagedType = "Any"; // FIXME
break; break;
case null:
case "":
case "String":
case "StringAnsi":
case "StringView":
unmanagedType = null;
break;
case "AntiRollBar":
unmanagedType = "Any"; // FIXME: This looks like a POD-type but isn't one?
break;
default: default:
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
unmanagedType = null;
else if (elementApiType == null)
unmanagedType = "Any";
else
unmanagedType = "Any"; unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'"); //Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break; break;
} }
}
if (!string.IsNullOrEmpty(unmanagedType)) if (!string.IsNullOrEmpty(unmanagedType))
{ {
string arraySubType = ""; string arraySubType = "";
@@ -788,10 +829,28 @@ namespace Flax.Build.Bindings
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, "; arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
parameterMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__{parameterInfo.Name}Count"))})"; parameterMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__{parameterInfo.Name}Count"))})";
} }
else if (genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
parameterMarshalType = $"/*marsh5c*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<string, IntPtr>), CountElementName = \"__{parameterInfo.Name}Count\")";
else if (elementApiType.IsValueType)
{
var nativeName = parameterInfo.Type.GetFullNameNative(buildData, caller);
var nativeInternalName = GenerateCppManagedWrapperName(elementApiType);
var marshallerName = (!string.IsNullOrEmpty(elementApiType?.Namespace) ? $"{elementApiType?.Namespace}.Interop." : "") + $"{elementApiType.Name}Marshaller";
//parameterMarshalType = $"/*marsh5a pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
if (/*nativeName != nativeInternalName && */elementApiType.MarshalAs != null)
parameterMarshalType = $"/*marsh5a1 pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
else else
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")"; parameterMarshalType = $"/*marsh5a2 pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<{elementApiType.Name},{marshallerName}.{elementApiType.Name}Internal>), CountElementName = \"__{parameterInfo.Name}Count\")";
//parameterMarshalType += $"] [MarshalUsing(typeof({marshallerName}), ElementIndirectionDepth = 1)";
// [MarshalUsing(typeof(ExampleMarshaller), ElementIndirectionDepth = 1)]
}
else
parameterMarshalType = $"/*marsh5b*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
if (!parameterInfo.IsOut && !parameterInfo.IsRef) if (!parameterInfo.IsOut && !parameterInfo.IsRef)
parameterMarshalType += ", In"; // The usage of 'LibraryImportAttribute' does not follow recommendations. It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. parameterMarshalType += ", In"; // The usage of 'LibraryImportAttribute' does not follow recommendations. It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters.
//if (elementApiType?.MarshalAs != null)
// parameterMarshalType += $"] [MarshalUsing(typeof({elementApiType.MarshalAs}), ElementIndirectionDepth = 1)";
} }
else if (parameterInfo.Type.Type == "Dictionary") else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)"; parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
@@ -801,7 +860,7 @@ namespace Flax.Build.Bindings
parameterMarshalType = "MarshalAs(UnmanagedType.I2)"; parameterMarshalType = "MarshalAs(UnmanagedType.I2)";
else if (nativeType.EndsWith("[]")) else if (nativeType.EndsWith("[]"))
{ {
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>))"; parameterMarshalType = $"/*marsh6*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>))";
} }
if (!string.IsNullOrEmpty(parameterMarshalType)) if (!string.IsNullOrEmpty(parameterMarshalType))
@@ -841,7 +900,7 @@ namespace Flax.Build.Bindings
{ {
// TODO: make this code shared with MarshalUsing selection from the above // TODO: make this code shared with MarshalUsing selection from the above
if (parameterInfo.Type.IsArrayOrSpan) if (parameterInfo.Type.IsArrayOrSpan)
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")"; parameterMarshalType = $"/*marsh1*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
else if (parameterInfo.Type.Type == "Dictionary") else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)"; parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
else if (parameterInfo.Type.Type == "CultureInfo") else if (parameterInfo.Type.Type == "CultureInfo")
@@ -1806,11 +1865,22 @@ namespace Flax.Build.Bindings
type = "IntPtr"; type = "IntPtr";
else if (marshalType.IsPtr && !originalType.EndsWith("*")) else if (marshalType.IsPtr && !originalType.EndsWith("*"))
type = "IntPtr"; type = "IntPtr";
else if (marshalType.Type == "Array" || marshalType.Type == "Span" || marshalType.Type == "DataContainer" || marshalType.Type == "BytesContainer") else if (marshalType.IsArrayOrSpan)
{ {
type = "IntPtr";
apiType = FindApiTypeInfo(buildData, marshalType.GenericArgs[0], structureInfo); apiType = FindApiTypeInfo(buildData, marshalType.GenericArgs[0], structureInfo);
internalType = apiType is StructureInfo elementStructureInfo && UseCustomMarshalling(buildData, elementStructureInfo, structureInfo); internalType = apiType is StructureInfo elementStructureInfo && UseCustomMarshalling(buildData, elementStructureInfo, structureInfo);
string originalElementType = originalType.Substring(0, originalType.Length - 2);
if (internalType)
{
string originalElementTypeMarshaller = (!string.IsNullOrEmpty(apiType?.Namespace) ? $"{apiType?.Namespace}.Interop." : "") + $"{originalElementType}Marshaller";
string originalElementTypeName = originalElementType.Substring(originalElementType.LastIndexOf('.') + 1); // Strip namespace
string internalElementType = $"{originalElementTypeMarshaller}.{originalElementTypeName}Internal";
type = $"NativeArray<{internalElementType}>";
}
else if (marshalType.GenericArgs[0].IsObjectRef)
type = "NativeArray<IntPtr>";
else
type = $"NativeArray<{originalElementType}>";
} }
else if (marshalType.Type == "Version") else if (marshalType.Type == "Version")
type = "IntPtr"; type = "IntPtr";
@@ -1827,12 +1897,14 @@ namespace Flax.Build.Bindings
} }
//else if (type == "Guid") //else if (type == "Guid")
// type = "GuidNative"; // type = "GuidNative";
structContents.Append($"{type} {fieldInfo.Name};").Append(type == "IntPtr" ? $" // {originalType}" : "").AppendLine(); structContents.Append($"{type} {fieldInfo.Name};").Append(type != originalType ? $" // {originalType}" : "").AppendLine();
} }
// Generate struct constructor/getter and deconstructor/setter function // Generate struct constructor/getter and deconstructor/setter function
toManagedContent.Append("managed.").Append(fieldInfo.Name).Append(" = "); var managedField = $"managed.{fieldInfo.Name}";
toNativeContent.Append("unmanaged.").Append(fieldInfo.Name).Append(" = "); var unmanagedField = $"unmanaged.{fieldInfo.Name}";
toManagedContent.Append($"{managedField} = ");
toNativeContent.Append($"{unmanagedField} = ");
if (marshalType.IsObjectRef) if (marshalType.IsObjectRef)
{ {
var managedType = GenerateCSharpNativeToManaged(buildData, marshalType.GenericArgs[0], structureInfo); var managedType = GenerateCSharpNativeToManaged(buildData, marshalType.GenericArgs[0], structureInfo);
@@ -1868,7 +1940,7 @@ namespace Flax.Build.Bindings
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}"); freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
} }
else if (marshalType.Type == "Array" || marshalType.Type == "Span" || marshalType.Type == "DataContainer" || marshalType.Type == "BytesContainer") else if (marshalType.IsArrayOrSpan)
{ {
string originalElementType = originalType.Substring(0, originalType.Length - 2); string originalElementType = originalType.Substring(0, originalType.Length - 2);
if (internalType) if (internalType)
@@ -1877,17 +1949,17 @@ namespace Flax.Build.Bindings
string originalElementTypeMarshaller = (!string.IsNullOrEmpty(apiType?.Namespace) ? $"{apiType?.Namespace}.Interop." : "") + $"{originalElementType}Marshaller"; string originalElementTypeMarshaller = (!string.IsNullOrEmpty(apiType?.Namespace) ? $"{apiType?.Namespace}.Interop." : "") + $"{originalElementType}Marshaller";
string originalElementTypeName = originalElementType.Substring(originalElementType.LastIndexOf('.') + 1); // Strip namespace string originalElementTypeName = originalElementType.Substring(originalElementType.LastIndexOf('.') + 1); // Strip namespace
string internalElementType = $"{originalElementTypeMarshaller}.{originalElementTypeName}Internal"; string internalElementType = $"{originalElementTypeMarshaller}.{originalElementTypeName}Internal";
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.ConvertArray((Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null;"); toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.ConvertArray({unmanagedField}.AsSpan(), {originalElementTypeMarshaller}.ToManaged) : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(NativeInterop.ConvertArray(managed.{fieldInfo.Name}, {originalElementTypeMarshaller}.ToNative)), GCHandleType.Weak) : IntPtr.Zero;"); toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ConvertArrayNative({managedField}.AsSpan(), {originalElementTypeMarshaller}.ToNative) : new NativeArray<{internalElementType}>();");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}"); freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var value in {unmanagedField}.AsReadOnlySpan()) {{ {originalElementTypeMarshaller}.Free(value); }} {unmanagedField}.Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.NativeToManaged.Free(value); }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}"); freeContents2.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var value in {unmanagedField}.AsReadOnlySpan()) {{ {originalElementTypeMarshaller}.NativeToManaged.Free(value); }} {unmanagedField}.Free(); }}");
} }
else if (marshalType.GenericArgs[0].IsObjectRef) else if (marshalType.GenericArgs[0].IsObjectRef)
{ {
// Array elements passed as GCHandles // Array elements passed as GCHandles
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>(Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)) : null;"); toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>({unmanagedField}) : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name})/*, GCHandleType.Weak*/) : IntPtr.Zero;"); toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name}) : new NativeArray<IntPtr>();");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<IntPtr> ptrs = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<IntPtr>(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}"); freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var ptr in {unmanagedField}.AsReadOnlySpan()) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} {unmanagedField}.Free(); }}");
// Permanent ScriptingObject handle is passed from native side, do not release it // Permanent ScriptingObject handle is passed from native side, do not release it
//freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<IntPtr> ptrs = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<IntPtr>(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}"); //freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<IntPtr> ptrs = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<IntPtr>(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
@@ -1895,10 +1967,10 @@ namespace Flax.Build.Bindings
else else
{ {
// Blittable array elements // Blittable array elements
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? (Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToArray<{originalElementType}>() : null;"); toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? {unmanagedField}.AsReadOnlySpan().ToArray() : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak) : IntPtr.Zero;"); toNativeContent.AppendLine($"{managedField}?.Length > 0 ? new NativeArray<{originalElementType}>({managedField}.AsSpan()) : new NativeArray<{originalElementType}>();");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}"); freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}"); freeContents2.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
} }
} }
else if (marshalType.Type == "Version") else if (marshalType.Type == "Version")

View File

@@ -18,6 +18,27 @@ namespace Flax.Build.Bindings
/// The parameter needs to be assigned to local variable first. /// The parameter needs to be assigned to local variable first.
/// </summary> /// </summary>
NeedLocalVariable = 1 << 0, NeedLocalVariable = 1 << 0,
/// <summary>
/// The parameter needs an additional length parameter.
/// </summary>
LengthParameter = 2 << 0,
/// <summary>
/// The parameter needs to be assigned as a parameter reference.
/// </summary>
AssignAsReference = 3 << 0,
}
[Flags]
public enum ParameterGeneratorFlags
{
None = 0,
/// <summary>
/// The parameter needs to be assigned as a parameter reference.
/// </summary>
AssignAsReference = 1 << 0,
} }
partial class BindingsGenerator partial class BindingsGenerator
@@ -38,6 +59,7 @@ namespace Flax.Build.Bindings
private static readonly Dictionary<string, TypeInfo> CppVariantToTypes = new Dictionary<string, TypeInfo>(); private static readonly Dictionary<string, TypeInfo> CppVariantToTypes = new Dictionary<string, TypeInfo>();
private static readonly Dictionary<string, TypeInfo> CppVariantFromTypes = new Dictionary<string, TypeInfo>(); private static readonly Dictionary<string, TypeInfo> CppVariantFromTypes = new Dictionary<string, TypeInfo>();
private static bool CppNonPodTypesConvertingGeneration = false; private static bool CppNonPodTypesConvertingGeneration = false;
private static bool CppNativeArrayAsParameter = false;
private static StringBuilder CppContentsEnd; private static StringBuilder CppContentsEnd;
public class ScriptingLangInfo public class ScriptingLangInfo
@@ -88,9 +110,13 @@ namespace Flax.Build.Bindings
"Rectangle", "Rectangle",
}; };
private static ParameterFormattingFlags SetFlag(this ParameterFormattingFlags flags, ParameterFormattingFlags value, bool enable) private static ParameterFormattingFlags SetFlag(this ref ParameterFormattingFlags flags, ParameterFormattingFlags value, bool enable)
{ {
return enable ? (flags | value) : (flags & ~value); return flags = enable ? (flags | value) : (flags & ~value);
}
private static ParameterGeneratorFlags SetFlag(this ref ParameterGeneratorFlags flags, ParameterGeneratorFlags value, bool enable)
{
return flags = enable ? (flags | value) : (flags & ~value);
} }
private static bool GenerateCppIsTemplateInstantiationType(ApiTypeInfo typeInfo) private static bool GenerateCppIsTemplateInstantiationType(ApiTypeInfo typeInfo)
@@ -121,12 +147,14 @@ namespace Flax.Build.Bindings
private static string GenerateCppWrapperNativeToManagedParam(BuildData buildData, StringBuilder contents, TypeInfo paramType, string paramName, ApiTypeInfo caller, bool isRef, out ParameterFormattingFlags formattingFlags) private static string GenerateCppWrapperNativeToManagedParam(BuildData buildData, StringBuilder contents, TypeInfo paramType, string paramName, ApiTypeInfo caller, bool isRef, out ParameterFormattingFlags formattingFlags)
{ {
formattingFlags = ParameterFormattingFlags.None; formattingFlags = ParameterFormattingFlags.None;
//CppNativeArrayAsParameter = true;
var nativeToManaged = GenerateCppWrapperNativeToManaged(buildData, paramType, caller, out var managedTypeAsNative, null); var nativeToManaged = GenerateCppWrapperNativeToManaged(buildData, paramType, caller, out var managedTypeAsNative, null);
//CppNativeArrayAsParameter = false;
string result; string result;
if (!string.IsNullOrEmpty(nativeToManaged)) if (!string.IsNullOrEmpty(nativeToManaged))
{ {
result = string.Format(nativeToManaged, paramName); result = string.Format(nativeToManaged, paramName);
if (managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' && !isRef) if ((managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' || managedTypeAsNative.StartsWith("NativeArray<")) && !isRef)
{ {
// Pass pointer value // Pass pointer value
} }
@@ -135,6 +163,7 @@ namespace Flax.Build.Bindings
// Pass as pointer to local variable converted for managed runtime // Pass as pointer to local variable converted for managed runtime
if (paramType.IsPtr) if (paramType.IsPtr)
result = string.Format(nativeToManaged, '*' + paramName); result = string.Format(nativeToManaged, '*' + paramName);
contents.Append($" // localvar1 {managedTypeAsNative}, {paramType.ToString()}").AppendLine();
contents.Append($" auto __param_orig_{paramName} = {result};").AppendLine(); contents.Append($" auto __param_orig_{paramName} = {result};").AppendLine();
contents.Append($" auto __param_{paramName} = __param_orig_{paramName};").AppendLine(); contents.Append($" auto __param_{paramName} = __param_orig_{paramName};").AppendLine();
result = $"&__param_{paramName}"; result = $"&__param_{paramName}";
@@ -543,30 +572,28 @@ namespace Flax.Build.Bindings
return "{0}.GetManagedInstance()"; return "{0}.GetManagedInstance()";
} }
// Array or DataContainer #if !USE_NETCORE
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null) // BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
{ {
var arrayTypeInfo = typeInfo.GenericArgs[0]; type = "MArray*";
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller); return "MUtils::ToArray({0})";
#if USE_NETCORE
if (arrayApiType?.IsPod ?? false)
{
if (functionInfo == null)
{
// Storage type should be wrapped
type = $"NativeArray<{arrayApiType.FullNameNative}>";
return $"MUtils::ToNativeArrayWrapper<{arrayApiType.FullNameNative}>({{0}})/*sahho*/";
} }
else
// Span
if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null)
{ {
//type = arrayApiType.FullNameNative + "*/*wahho*/"; type = "MonoArray*";
type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/"; return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
//if (arrayTypeInfo.Type == "bool")
// return "MUtils::ToBoolArray({0})/*bahho*/";
return "MUtils::ToNativeArrayWrapper({0})/*nahhoa7eatra*/";
}
} }
#endif #endif
// Array or DataContainer
if (typeInfo.IsArrayOrSpan)
{
var arrayTypeInfo = typeInfo.GenericArgs?.Count > 0 ? typeInfo.GenericArgs[0] : null;
var arrayApiType = arrayTypeInfo != null ? FindApiTypeInfo(buildData, arrayTypeInfo, caller) : null;
type = "MArray*"; type = "MArray*";
if (arrayApiType != null && arrayApiType.MarshalAs != null) if (arrayApiType != null && arrayApiType.MarshalAs != null)
{ {
@@ -576,25 +603,98 @@ namespace Flax.Build.Bindings
var genericArgs = arrayApiType.MarshalAs.GetFullNameNative(buildData, caller); var genericArgs = arrayApiType.MarshalAs.GetFullNameNative(buildData, caller);
if (typeInfo.GenericArgs.Count != 1) if (typeInfo.GenericArgs.Count != 1)
genericArgs += ", " + typeInfo.GenericArgs[1]; genericArgs += ", " + typeInfo.GenericArgs[1];
return "MUtils::ToArray(Array<" + genericArgs + ">({0}), " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")"; return "MUtils::ToArray(Array<" + genericArgs + ">({0}), " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")/*marshalas*/";
}
return "MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
} }
#if !USE_NETCORE #if USE_NETCORE
// Span if (typeInfo.Type == "BytesContainer")
if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null)
{ {
type = "MonoArray*"; type = "NativeArray<byte> /*baggo*/";
return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")"; return "MUtils::ToManagedArrayWrapperCopy<byte>({0})/*bagtgaggag*/";
}
else //if (arrayApiType?.IsValueType ?? true)
{
var nativeName = /*arrayApiType?.FullNameNative ?? */arrayTypeInfo.GetFullNameNative(buildData, caller);
var nativeInternalName = nativeName;
var converter = "{0}";
var castType = nativeName;
bool pod = true;
if (arrayApiType != null && arrayApiType.IsStruct && !arrayApiType.IsPod)
{
if (!CppUsedNonPodTypes.Contains(arrayApiType))
CppUsedNonPodTypes.Add(arrayApiType);
pod = false;
// Requires conversion
//converter = "ToManaged({0})";
//nativeInternalName = !string.IsNullOrEmpty(arrayApiType?.FullNameNativeInternal) ? arrayApiType.FullNameNativeInternal + "Managed" : null;
nativeInternalName = GenerateCppManagedWrapperName(arrayApiType);
castType = nativeInternalName;
//nativeName = nativeInternalName;
}
/*if (arrayTypeInfo.GenericArgs?.Count > 0)
{
nativeInternalName += "<";
for (int i=0; i< arrayTypeInfo.GenericArgs.Count; ++i)
{
if (i != 0)
nativeInternalName += ", ";
nativeInternalName += arrayTypeInfo.GenericArgs[i].Type;
}
nativeInternalName += ">";
}*/
//else
// nativeInternalName = nativeName;
if (typeInfo.Type != "Span")
{
//converter = "ToSpan({0})";
/*if (arrayTypeInfo.IsObjectRef || (arrayApiType != null && arrayApiType.IsScriptingObject))
converter = $"(const Span<{nativeName}*>&)ToSpan({{0}})";
else*/
converter = $"(const Span<{nativeName}>&)ToSpan({{0}})";
//converter = $"Span<{nativeInternalName}>({{0}}.Get(), {{0}}.Count())";
}
if (CppNativeArrayAsParameter)
{
type = nativeName + $"*/*wahho2 pod:{pod}*/";
//type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/";
//if (arrayTypeInfo.Type == "bool")
// return "MUtils::ToBoolArray({0})/*bahho*/";
return $"({castType}*)MUtils::ToManagedArrayWrapperCopy({converter})/*sahho1*/";
}
else if (arrayTypeInfo.IsObjectRef || (arrayApiType != null && arrayApiType.IsScriptingObject))
{
type = $"NativeArray<MObject*>/*wahho5 object*/";
return $"MUtils::ToManagedArrayWrapperPointer<{nativeName}>({converter})/*sahho3a*/";
}
else if (arrayApiType != null && arrayApiType.IsScriptingObject)
{
type = $"NativeArray<{nativeInternalName}*>/*wahho3 class pod:{pod}*/";
//type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/";
//if (arrayTypeInfo.Type == "bool")
// return "MUtils::ToBoolArray({0})/*bahho*/";
if (nativeName == nativeInternalName)
return $"MUtils::ToManagedArrayWrapperCopy<{nativeName}*>({converter})/*sahho3a*/";
return $"MUtils::ToManagedArrayWrapperConvert<{nativeName}, {nativeInternalName}>({converter})/*sahho3b*/";
}
else if (nativeName == "String" || nativeName == "StringView" || nativeName == "StringAnsi")
{
}
else
{
// Storage type should be wrapped
type = $"NativeArray<{nativeInternalName}>/*wahho1 pod:{pod}*/";
//type = nativeName + "*/*wahho1: {caller?.Name}*/";
if (nativeName == nativeInternalName)
return $"MUtils::ToManagedArrayWrapperCopy<{nativeName}>({converter})/*sahho2a*/";
return $"MUtils::ToManagedArrayWrapperConvert<{nativeName}, {nativeInternalName}>({converter})/*sahho2b*/";
}
} }
#endif #endif
return "/*custom: " + typeInfo.ToString() + " */MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
// BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
{
type = "MArray*";
return "MUtils::ToArray({0})";
} }
// Dictionary // Dictionary
@@ -692,7 +792,9 @@ namespace Flax.Build.Bindings
} }
} }
private static string GenerateCppWrapperManagedToNative(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, out string type, out ApiTypeInfo apiType, FunctionInfo functionInfo, out ParameterFormattingFlags formattingFlags) private static string GenerateCppWrapperManagedToNative(BuildData buildData, TypeInfo typeInfo,
ApiTypeInfo caller, FunctionInfo functionInfo, ParameterGeneratorFlags generatorFlags, out string type,
out ApiTypeInfo apiType, out ParameterFormattingFlags formattingFlags)
{ {
formattingFlags = ParameterFormattingFlags.None; formattingFlags = ParameterFormattingFlags.None;
@@ -704,7 +806,7 @@ namespace Flax.Build.Bindings
if (typeInfo.IsArray) if (typeInfo.IsArray)
{ {
var arrayType = new TypeInfo { Type = "Array", GenericArgs = new List<TypeInfo> { new TypeInfo(typeInfo) { IsArray = false } } }; var arrayType = new TypeInfo { Type = "Array", GenericArgs = new List<TypeInfo> { new TypeInfo(typeInfo) { IsArray = false } } };
var result = GenerateCppWrapperManagedToNative(buildData, arrayType, caller, out type, out _, functionInfo, out formattingFlags); var result = GenerateCppWrapperManagedToNative(buildData, arrayType, caller, functionInfo, generatorFlags, out type, out _, out formattingFlags);
return result + ".Get()"; return result + ".Get()";
} }
@@ -771,7 +873,7 @@ namespace Flax.Build.Bindings
// Array // Array
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null) if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
{ {
formattingFlags.SetFlag(ParameterFormattingFlags.NeedLocalVariable, true); //formattingFlags.SetFlag(ParameterFormattingFlags.NeedLocalVariable, true);
var arrayTypeInfo = typeInfo.GenericArgs[0]; var arrayTypeInfo = typeInfo.GenericArgs[0];
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller); var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
if (arrayApiType != null && arrayApiType.MarshalAs != null) if (arrayApiType != null && arrayApiType.MarshalAs != null)
@@ -791,16 +893,72 @@ namespace Flax.Build.Bindings
genericArgs += ", " + typeInfo.GenericArgs[1]; genericArgs += ", " + typeInfo.GenericArgs[1];
result = $"Array<{genericArgs}>({result})"; result = $"Array<{genericArgs}>({result})";
} }
else if (arrayApiType?.IsPod ?? false) #if false
else if (arrayApiType?.IsScriptingObject ?? false)
{ {
type = arrayApiType.FullNameNative + '*'; result += "/*123scriptingobject*/";
result = $"Array<{genericArgs}>(({arrayApiType.FullNameNative}*){{0}}, {{1}})/*xviox1 {arrayTypeInfo.Type}*/";
} }
#endif
else// if (arrayApiType?.IsValueType ?? true)
{
var nativeName = arrayTypeInfo.GetFullNameNative(buildData, caller);//(arrayApiType?.FullNameNative ?? arrayTypeInfo.Type);
var nativeInternalName = nativeName;
var converter = "{0}";
if (arrayApiType != null && arrayApiType.IsStruct && !arrayApiType.IsPod)
{
if (!CppUsedNonPodTypes.Contains(arrayApiType))
CppUsedNonPodTypes.Add(arrayApiType);
//pod = false;
// Requires conversion
//converter = "ToManaged({0})";
//nativeInternalName = !string.IsNullOrEmpty(arrayApiType?.FullNameNativeInternal) ? arrayApiType.FullNameNativeInternal + "Managed" : null;
nativeInternalName = GenerateCppManagedWrapperName(arrayApiType);
//castType = nativeInternalName;
//nativeName = nativeInternalName;
converter = $"/*lol1*/MUtils::ToNativeArrayWrapperConvert<{nativeName}, {nativeInternalName}>(ToSpan(({{0}}).data, {{1}})).data";
type = $"NativeArray<{nativeInternalName}>";
result = $"Array<{genericArgs}>(/*({nativeName}*)*/{converter}, {{1}})/*456valuetype {arrayTypeInfo.Type}*/";
}
else if (nativeName == "String" || nativeName == "StringAnsi" || nativeName == "StringView")
{
//result += "/*234stringy*/";
}
else if (arrayTypeInfo.IsObjectRef || (arrayApiType != null && arrayApiType.IsScriptingObject))
{
//nativeInternalName = GenerateCppManagedWrapperName(arrayApiType);
//castType = nativeInternalName;
//nativeName = nativeInternalName;
type = $"NativeArray<MObject*>";
if (generatorFlags.HasFlag(ParameterGeneratorFlags.AssignAsReference))
{
converter = $"/*aar123A*/ MUtils::ToNativeArrayWrapperConvertGeneric<{genericArgs}>(ToSpan(({{0}}).data, {{1}}), {{2}})";
result = $"{converter}/*789object {arrayTypeInfo.Type}*/";
formattingFlags.SetFlag(ParameterFormattingFlags.AssignAsReference, true);
}
else
{
converter = $"/*aar123B*/ MUtils::ToNativeArrayWrapperConvertGeneric<{nativeName}>(ToSpan(({{0}}).data, {{1}})).data";
result = $"Array<{genericArgs}>({converter}, {{1}})/*678object {arrayTypeInfo.Type}*/";
}
formattingFlags.SetFlag(ParameterFormattingFlags.LengthParameter, true);
}
else
{
type = $"NativeArray<{nativeInternalName}>";
result = $"Array<{genericArgs}>(/*({nativeName}*)*/{converter}, {{1}})/*123valuetype {arrayTypeInfo.Type}*/";
}
}
#if false
else if (arrayApiType?.Name == "bool") else if (arrayApiType?.Name == "bool")
{ {
throw new Exception("huh");
type = "bool*"; type = "bool*";
result = "Array<bool>({0}, {1})/*xviox2*/\""; result = "Array<bool>({0}, {1})/*123bool*/\"";
} }
#endif
return result; return result;
} }
@@ -853,9 +1011,15 @@ namespace Flax.Build.Bindings
// BytesContainer // BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null) if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
{ {
#if USE_NETCORE
//formattingFlags.SetFlag(FormattingFlags.NeedLocalVariable, true);
type = "byte*";
return "BytesContainer({0}, {1})";
#else
formattingFlags.SetFlag(FormattingFlags.NeedLocalVariable, true); formattingFlags.SetFlag(FormattingFlags.NeedLocalVariable, true);
type = "MArray*"; type = "MArray*";
return "MUtils::LinkArray({0})"; return "MUtils::LinkArray({0})";
#endif
} }
// Function // Function
@@ -876,7 +1040,7 @@ namespace Flax.Build.Bindings
if (apiType != null) if (apiType != null)
{ {
if (apiType.MarshalAs != null) if (apiType.MarshalAs != null)
return GenerateCppWrapperManagedToNative(buildData, apiType.MarshalAs, caller, out type, out apiType, functionInfo, out formattingFlags); return GenerateCppWrapperManagedToNative(buildData, apiType.MarshalAs, caller, functionInfo, generatorFlags, out type, out apiType, out formattingFlags);
// Scripting Object (for non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code) // Scripting Object (for non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
if (CppNonPodTypesConvertingGeneration && apiType.IsScriptingObject && typeInfo.IsPtr) if (CppNonPodTypesConvertingGeneration && apiType.IsScriptingObject && typeInfo.IsPtr)
@@ -964,8 +1128,8 @@ namespace Flax.Build.Bindings
return $"MUtils::ToArray({value}, {GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, null)})"; return $"MUtils::ToArray({value}, {GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, null)})";
// BytesContainer // BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null) //if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
return $"MUtils::ToArray({value})"; // return $"MUtils::ToArray({value})";
// Construct native typename for MUtils template argument // Construct native typename for MUtils template argument
var nativeType = new StringBuilder(64); var nativeType = new StringBuilder(64);
@@ -1042,6 +1206,13 @@ namespace Flax.Build.Bindings
callerName = callerName; callerName = callerName;
if (functionInfo.UniqueName == "SetDriveControl") if (functionInfo.UniqueName == "SetDriveControl")
callerName = callerName; callerName = callerName;
if (functionInfo.UniqueName == "ProcessText2")
callerName = callerName;
if (functionInfo.UniqueName == "CoverageTest4")
callerName = callerName;
if (functionInfo.UniqueName == "SetFallbackFonts")
callerName = callerName;
// Setup function binding glue to ensure that wrapper method signature matches for C++ and C# // Setup function binding glue to ensure that wrapper method signature matches for C++ and C#
functionInfo.Glue = new FunctionInfo.GlueInfo functionInfo.Glue = new FunctionInfo.GlueInfo
@@ -1055,7 +1226,9 @@ namespace Flax.Build.Bindings
returnType = returnApiType.MarshalAs; returnType = returnApiType.MarshalAs;
bool returnTypeIsContainer = false; bool returnTypeIsContainer = false;
//CppNativeArrayAsParameter = true;
var returnValueConvert = GenerateCppWrapperNativeToManaged(buildData, functionInfo.ReturnType, caller, out var returnValueType, functionInfo); var returnValueConvert = GenerateCppWrapperNativeToManaged(buildData, functionInfo.ReturnType, caller, out var returnValueType, functionInfo);
//CppNativeArrayAsParameter = false;
if (functionInfo.Glue.UseReferenceForResult) if (functionInfo.Glue.UseReferenceForResult)
{ {
returnValueType = "void"; returnValueType = "void";
@@ -1072,7 +1245,7 @@ namespace Flax.Build.Bindings
}); });
} }
#if USE_NETCORE #if USE_NETCORE
else if (returnType.Type == "Array" || returnType.Type == "Span" || returnType.Type == "DataContainer" || returnType.Type == "BitArray" || returnType.Type == "BytesContainer") else if (returnType.IsArrayOrSpan || returnType.Type == "BitArray")
{ {
returnTypeIsContainer = true; returnTypeIsContainer = true;
functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo
@@ -1082,6 +1255,21 @@ namespace Flax.Build.Bindings
Type = new TypeInfo("int"), Type = new TypeInfo("int"),
IsOut = true, IsOut = true,
}); });
var arrayElementType = returnType.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, returnType.GenericArgs[0], caller) : null;
if (returnType.Type == "BytesContainer" || ((arrayElementType?.IsValueType ?? true) && (arrayElementType != null && arrayElementType.MarshalAs == null)))
{
//returnValueConvert += ".data/*hellooy*/";
returnValueConvert += "/*hellooy*/";
}
else if (arrayElementType == null)
{
returnValueConvert += "/*gagagaghf*/";
}
else
{
returnValueConvert += "/*BUUH*/";
}
} }
#endif #endif
@@ -1137,8 +1325,29 @@ namespace Flax.Build.Bindings
contents.Append(", "); contents.Append(", ");
separator = true; separator = true;
var genFlags = ParameterGeneratorFlags.None;
if (functionInfo.UniqueName.StartsWith("Set") && !functionInfo.Name.StartsWith("Set"))
{
// Special case for setters: try to set the field value via parameter reference so existing allocation in arrays can be reused.
genFlags.SetFlag(ParameterGeneratorFlags.AssignAsReference, true);
if (functionInfo.Parameters.Count != 1)
separator = separator;
}
//else
// genFlags.SetFlag(ParameterGeneratorFlags.AssignAsReference, true);
CppParamsThatNeedConversion[i] = false; CppParamsThatNeedConversion[i] = false;
CppParamsWrappersCache[i] = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, out var managedType, out var apiType, functionInfo, out CppParamsFormattingFlags[i]); //CppNativeArrayAsParameter = true;
CppParamsWrappersCache[i] = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, functionInfo, genFlags, out var managedType, out var apiType, out CppParamsFormattingFlags[i]);
//CppNativeArrayAsParameter = false;
if (functionInfo.UniqueName.StartsWith("Set") && !functionInfo.Name.StartsWith("Set"))
{ }
else if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
{
}
// Out parameters that need additional converting will be converted at the native side (eg. object reference) // Out parameters that need additional converting will be converted at the native side (eg. object reference)
var isOutWithManagedConverter = parameterInfo.IsOut && !string.IsNullOrEmpty(GenerateCSharpManagedToNativeConverter(buildData, parameterInfo.Type, caller)); var isOutWithManagedConverter = parameterInfo.IsOut && !string.IsNullOrEmpty(GenerateCSharpManagedToNativeConverter(buildData, parameterInfo.Type, caller));
@@ -1186,7 +1395,7 @@ namespace Flax.Build.Bindings
} }
} }
#if USE_NETCORE #if USE_NETCORE
if (parameterInfo.Type.IsArray || parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "BytesContainer" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BitArray") if (parameterInfo.Type.IsArray || parameterInfo.Type.IsArrayOrSpan || parameterInfo.Type.Type == "BitArray")
{ {
// We need additional output parameters for array sizes // We need additional output parameters for array sizes
var name = $"__{parameterInfo.Name}Count"; var name = $"__{parameterInfo.Name}Count";
@@ -1213,7 +1422,7 @@ namespace Flax.Build.Bindings
contents.Append(", "); contents.Append(", ");
separator = true; separator = true;
GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, out var managedType, out _, functionInfo, out _); GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, functionInfo, ParameterGeneratorFlags.None, out var managedType, out _, out _);
contents.Append(managedType); contents.Append(managedType);
if (parameterInfo.IsRef || parameterInfo.IsOut || UsePassByReference(buildData, parameterInfo.Type, caller)) if (parameterInfo.IsRef || parameterInfo.IsOut || UsePassByReference(buildData, parameterInfo.Type, caller))
contents.Append('*'); contents.Append('*');
@@ -1281,6 +1490,7 @@ namespace Flax.Build.Bindings
// Call native member method // Call native member method
call = $"__obj->{functionInfo.Name}"; call = $"__obj->{functionInfo.Name}";
} }
contents.Append(indent).Append($"// convert values").AppendLine();
string callParams = string.Empty; string callParams = string.Empty;
separator = false; separator = false;
for (var i = 0; i < functionInfo.Parameters.Count; i++) for (var i = 0; i < functionInfo.Parameters.Count; i++)
@@ -1311,12 +1521,26 @@ namespace Flax.Build.Bindings
} }
else else
{ {
if (functionInfo.UniqueName == "SetFallbackFonts")
callerName = callerName;
if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
{
callerName = callerName;
if (functionInfo.UniqueName.StartsWith("Set") && !functionInfo.Name.StartsWith("Set"))
callerName = callerName; // setter
else
callerName = callerName;
}
// Convert value // Convert value
param += string.Format(CppParamsWrappersCache[i], name, countParamName); param += string.Format(CppParamsWrappersCache[i], name, countParamName, "{0}");
} }
if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
{
callParams += param;
}
// Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter) // Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter)
if (CppParamsThatNeedConversion[i]) else if (CppParamsThatNeedConversion[i])
{ {
var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, caller); var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, caller);
if (apiType != null) if (apiType != null)
@@ -1338,6 +1562,9 @@ namespace Flax.Build.Bindings
callParams += "Temp"; callParams += "Temp";
} }
} }
/*else if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
{
}*/
// Special case for parameter that cannot be passed directly to the function from the wrapper method input parameter (eg. MArray* converted into BytesContainer uses as BytesContainer&) // Special case for parameter that cannot be passed directly to the function from the wrapper method input parameter (eg. MArray* converted into BytesContainer uses as BytesContainer&)
else if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable)) else if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable))
{ {
@@ -1356,9 +1583,9 @@ namespace Flax.Build.Bindings
{ {
// Non-const lvalue reference parameters needs to be passed via temporary value // Non-const lvalue reference parameters needs to be passed via temporary value
if (parameterInfo.IsOut || parameterInfo.IsRef) if (parameterInfo.IsOut || parameterInfo.IsRef)
contents.Append(indent).AppendFormat("{2}& {0}Temp = {1};", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine(); contents.Append(indent).AppendFormat("{2}& {0}Temp = {1}; // non-const lvalue1", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine();
else else
contents.Append(indent).AppendFormat("{2} {0}Temp = {1};", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine(); contents.Append(indent).AppendFormat("{2} {0}Temp = {1}; // non-const lvalue1", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine();
callParams += parameterInfo.Name; callParams += parameterInfo.Name;
callParams += "Temp"; callParams += "Temp";
} }
@@ -1378,11 +1605,28 @@ namespace Flax.Build.Bindings
contents.AppendLine(); contents.AppendLine();
contents.Append(callBegin); contents.Append(callBegin);
} }
else if (callParams.Contains("{0}"))
{
if (callFormat == "{0} = {1}" && functionInfo.Parameters.Count > 0 && CppParamsFormattingFlags[0].HasFlag(ParameterFormattingFlags.AssignAsReference))
{
// Assignment is done via ref parameter
callFormat = "{1}";
callParams = string.Format(callParams, call);
}
contents.Append(indent).Append($"//callbegin123: {callFormat}").AppendLine();
contents.Append(callBegin);
call = string.Format(callFormat, call, callParams);
call += "/*call123*/";
}
else else
#endif #endif
{ {
if (callFormat == "{0} = {1}" && functionInfo.Parameters.Count > 0 && CppParamsFormattingFlags[0].HasFlag(ParameterFormattingFlags.AssignAsReference))
callFormat = callFormat;
contents.Append(indent).Append($"//callbegin123: {callFormat}").AppendLine();
contents.Append(callBegin); contents.Append(callBegin);
call = string.Format(callFormat, call, callParams); call = string.Format(callFormat, call, callParams);
call += "/*call123*/";
} }
if (!string.IsNullOrEmpty(returnValueConvert)) if (!string.IsNullOrEmpty(returnValueConvert))
{ {
@@ -1418,6 +1662,7 @@ namespace Flax.Build.Bindings
// Convert special parameters back to managed world // Convert special parameters back to managed world
if (!useInlinedReturn) if (!useInlinedReturn)
{ {
contents.Append(indent).Append($"// !useInlinedReturn").AppendLine();
for (var i = 0; i < functionInfo.Parameters.Count; i++) for (var i = 0; i < functionInfo.Parameters.Count; i++)
{ {
var parameterInfo = functionInfo.Parameters[i]; var parameterInfo = functionInfo.Parameters[i];
@@ -1427,7 +1672,7 @@ namespace Flax.Build.Bindings
{ {
var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp"); var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp");
var elementType = parameterInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null; var elementType = parameterInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null;
var convertedType = CppParamsThatNeedConversionTypes[i];
// MObject* parameters returned by reference need write barrier for GC // MObject* parameters returned by reference need write barrier for GC
if (parameterInfo.IsOut) if (parameterInfo.IsOut)
{ {
@@ -1439,17 +1684,24 @@ namespace Flax.Build.Bindings
#if USE_NETCORE #if USE_NETCORE
if (parameterInfo.Type.Type == "Array") if (parameterInfo.Type.Type == "Array")
{ {
if (elementType?.IsPod ?? false) //if (elementType?.IsPod ?? true)
{ {
contents.Append(indent).Append($"// isgigs1a").AppendLine(); var nativeType = elementType?.FullNameNative;
contents.Append(indent).Append($"*{parameterInfo.Name} = ({parameterInfo.Type.GenericArgs[0]}*)MCore::GC::AllocateMemory(sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine(); var internalType = elementType?.FullNameNativeInternal;
contents.Append(indent).Append($"Platform::MemoryCopy(*{parameterInfo.Name}, {parameterInfo.Name}Temp.Get(), sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine(); contents.Append(indent).Append($"// isgigs1a, {elementType?.ToString()}, native: {nativeType}, internal: {internalType}, value: {value}").AppendLine();
} contents.Append(indent).Append($"*{parameterInfo.Name} = {value};").AppendLine();
/*if (string.IsNullOrEmpty(internalType) || nativeType == internalType)
contents.Append(indent).Append($"*{parameterInfo.Name} = MUtils::ToNativeArrayWrapper<{nativeType}>(ToSpan({parameterInfo.Name}Temp));").AppendLine();
else else
contents.Append(indent).Append($"*{parameterInfo.Name} = MUtils::ToNativeArrayWrapper<{nativeType}, {internalType}>(ToSpan({parameterInfo.Name}Temp));").AppendLine();*/
//contents.Append(indent).Append($"*{parameterInfo.Name} = ({parameterInfo.Type.GenericArgs[0]}*)MCore::GC::AllocateMemory(sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
//contents.Append(indent).Append($"Platform::MemoryCopy(*{parameterInfo.Name}, {parameterInfo.Name}Temp.Get(), sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
}
/*else
{ {
contents.Append(indent).Append($"// isgigs1b").AppendLine(); contents.Append(indent).Append($"// isgigs1b").AppendLine();
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine(); contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
} }*/
// Array marshallers need to know amount of items written in the buffer // Array marshallers need to know amount of items written in the buffer
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
@@ -1475,20 +1727,24 @@ namespace Flax.Build.Bindings
// BytesContainer // BytesContainer
if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null) if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null)
{ {
#if USE_NETCORE
contents.Append(indent).AppendFormat("*{0} = {1}; //123bytescontainerout", parameterInfo.Name, value).AppendLine();
#else
contents.Append(indent).Append($"// hshsf").AppendLine(); contents.Append(indent).Append($"// hshsf").AppendLine();
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine(); contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
// Array marshallers need to know amount of items written in the buffer // Array marshallers need to know amount of items written in the buffer
//contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); //contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
//continue; //continue;
#endif
} }
else else
throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'"); throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'");
} }
} }
else if (parameterInfo.Type.Type == "Array" && (elementType?.IsPod ?? false)) /*else if (parameterInfo.Type.Type == "Array" && (elementType?.IsPod ?? false))
contents.Append(indent).AppendFormat("*{0} = {1}.data;", parameterInfo.Name, value).AppendLine(); contents.Append(indent).AppendFormat("*{0} = {1}.data;", parameterInfo.Name, value).AppendLine();
else else*/
contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine(); contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine();
#if USE_NETCORE #if USE_NETCORE
if (parameterInfo.Type.Type == "Array" || (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null)) if (parameterInfo.Type.Type == "Array" || (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null))
@@ -1569,6 +1825,9 @@ namespace Flax.Build.Bindings
{ {
if (!EngineConfiguration.WithCSharp(buildData.TargetOptions)) if (!EngineConfiguration.WithCSharp(buildData.TargetOptions))
return; return;
if (functionInfo.UniqueName == "CoverageTest1ByRef")
scriptVTableSize = scriptVTableSize;
contents.AppendFormat(" {0} {1}_ManagedWrapper(", functionInfo.ReturnType, functionInfo.UniqueName); contents.AppendFormat(" {0} {1}_ManagedWrapper(", functionInfo.ReturnType, functionInfo.UniqueName);
var separator = false; var separator = false;
for (var i = 0; i < functionInfo.Parameters.Count; i++) for (var i = 0; i < functionInfo.Parameters.Count; i++)
@@ -1637,7 +1896,7 @@ namespace Flax.Build.Bindings
// If platform supports JITed code execution then use method thunk, otherwise fallback to generic runtime invoke // If platform supports JITed code execution then use method thunk, otherwise fallback to generic runtime invoke
var returnType = functionInfo.ReturnType; var returnType = functionInfo.ReturnType;
var useThunk = buildData.Platform.HasDynamicCodeExecutionSupport && Configuration.AOTMode == DotNetAOTModes.None; var useThunk = false;//buildData.Platform.HasDynamicCodeExecutionSupport && Configuration.AOTMode == DotNetAOTModes.None;
if (useThunk) if (useThunk)
{ {
//contents.AppendLine($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::{functionInfo.Name}\");"); //contents.AppendLine($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::{functionInfo.Name}\");");
@@ -1658,6 +1917,7 @@ namespace Flax.Build.Bindings
if (paramIsRef) if (paramIsRef)
{ {
// Pass as pointer to value when using ref/out parameter // Pass as pointer to value when using ref/out parameter
contents.Append($" localvar2 // {apiType.FullNameNative}").AppendLine();
contents.Append($" auto __param_orig_{parameterInfo.Name} = {paramValue};").AppendLine(); contents.Append($" auto __param_orig_{parameterInfo.Name} = {paramValue};").AppendLine();
contents.Append($" auto __param_{parameterInfo.Name} = __param_orig_{parameterInfo.Name};").AppendLine(); contents.Append($" auto __param_{parameterInfo.Name} = __param_orig_{parameterInfo.Name};").AppendLine();
paramValue = $"&__param_{parameterInfo.Name}"; paramValue = $"&__param_{parameterInfo.Name}";
@@ -1719,6 +1979,7 @@ namespace Flax.Build.Bindings
// Invoke method // Invoke method
contents.AppendLine(" MObject* __result = method->Invoke(object->GetOrCreateManagedInstance(), params, &exception);"); contents.AppendLine(" MObject* __result = method->Invoke(object->GetOrCreateManagedInstance(), params, &exception);");
contents.AppendLine(" // convert to native");
// Convert parameter values back from managed to native (could be modified there) // Convert parameter values back from managed to native (could be modified there)
for (var i = 0; i < functionInfo.Parameters.Count; i++) for (var i = 0; i < functionInfo.Parameters.Count; i++)
{ {
@@ -1726,15 +1987,16 @@ namespace Flax.Build.Bindings
if ((parameterInfo.IsRef || parameterInfo.IsOut) && !parameterInfo.Type.IsConst) if ((parameterInfo.IsRef || parameterInfo.IsOut) && !parameterInfo.Type.IsConst)
{ {
// Direct value convert // Direct value convert
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, out var managedType, out var apiType, null, out _); var paramName = CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable) ? $"__param_{parameterInfo.Name}" : $"params[{i}]";
var passAsParamPtr = managedType.EndsWith("*"); var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, null, ParameterGeneratorFlags.None, out var managedType, out var apiType, out _);
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType; var passAsParamPtr = managedType.EndsWith("*") || true;
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]"; var useLocalVarPointer = !CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable);
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)&{paramName}" : paramName;
if (!string.IsNullOrEmpty(managedToNative)) if (!string.IsNullOrEmpty(managedToNative))
{ {
if (!passAsParamPtr) if (!passAsParamPtr)
paramValue = '*' + paramValue; paramValue = '*' + paramValue;
paramValue = string.Format(managedToNative, paramValue); paramValue = string.Format(managedToNative, paramValue, $"__param_{parameterInfo.Name}.length");
} }
else if (!passAsParamPtr) else if (!passAsParamPtr)
paramValue = '*' + paramValue; paramValue = '*' + paramValue;
@@ -1761,12 +2023,18 @@ namespace Flax.Build.Bindings
} }
} }
// Release GCHandles of boxed values // Release temporary managed resources
for (var i = 0; i < functionInfo.Parameters.Count; i++) for (var i = 0; i < functionInfo.Parameters.Count; i++)
{ {
var parameterInfo = functionInfo.Parameters[i]; var parameterInfo = functionInfo.Parameters[i];
var paramValue = GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, out var apiType, parameterInfo.Name); var paramValue = GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, out var apiType, parameterInfo.Name);
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut; var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
var paramIsValueType = apiType?.IsValueType ?? true;
var elementApiType = apiType != null && parameterInfo.Type.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], apiType) : null;
var elementIsValueType = elementApiType?.IsValueType ?? true;
var elementIsClass = elementApiType?.IsClass ?? false;
var elementIsPod = elementApiType?.IsPod ?? true;
var elementIsObject = (parameterInfo.Type.GenericArgs?[0].IsObjectRef ?? false) || (elementApiType?.IsScriptingObject ?? false);
if (paramValue.Contains("MUtils::Box<")) // FIXME if (paramValue.Contains("MUtils::Box<")) // FIXME
{ {
@@ -1779,31 +2047,44 @@ namespace Flax.Build.Bindings
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{parameterInfo.Name}) //asdf1a").AppendLine(); contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{parameterInfo.Name}) //asdf1a").AppendLine();
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine(); contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
}*/ }*/
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
if (useThunk) //var ispod = parameterInfo.Type.IsPod(buildData, apiType);
//contents.Append($" // {parameterInfo.Type.Type} is pod: {ispod}||{apiType.IsPod}, valuetype: {apiType.IsValueType}, classtype: {apiType.IsClass} // doerp1").AppendLine();
if (useThunk || !paramIsValueType)
{ {
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)__param_{parameterInfo.Name}); // darr1").AppendLine();
// Release the original handle // Release the original handle
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").AppendLine(); contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").AppendLine();
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)__param_orig_{parameterInfo.Name});").AppendLine(); contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)__param_orig_{parameterInfo.Name});").AppendLine();
} }
else if (paramIsValueType)
{
contents.Append($" //durr2").AppendLine();
}
else if (CppParamsThatNeedConversion[i])
{
contents.Append($" FreeManaged(__param_{parameterInfo.Name}); //durr1").AppendLine();
}
} }
else if (apiType != null && !apiType.IsInBuild) else if (apiType != null && !apiType.IsInBuild)
{ {
// int: ispod, isvaluetype // int: ispod, isvaluetype
// vector: ispod, isvaluetype, isstruct // vector: ispod, isvaluetype, isstruct
// guid: ispod, isvaluetype, isstruct, isinbuild // guid: ispod, isvaluetype, isstruct, isinbuild
if (useThunk || !paramIsValueType)
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1b").AppendLine(); contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1b").AppendLine();
//contents.Append($" auto __param{i}_handle = *(MGCHandle*)&params[{i}]; // asdf1b").AppendLine(); //contents.Append($" auto __param{i}_handle = *(MGCHandle*)&params[{i}]; // asdf1b").AppendLine();
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine(); //contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
//contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine(); //contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
} }
else if (apiType != null && !apiType.IsValueType) else if (apiType != null && !paramIsValueType)
{ {
if (parameterInfo.Type.Type.ToLower().Contains("string")) if (parameterInfo.Type.Type.ToLower().Contains("string"))
apiType = apiType; apiType = apiType;
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1d").AppendLine(); contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1d").AppendLine();
} }
else //if (apiType != null) else if (useThunk)//if (apiType != null)
{ {
if (parameterInfo.Type.Type.ToLower().Contains("string")) if (parameterInfo.Type.Type.ToLower().Contains("string"))
apiType = apiType; apiType = apiType;
@@ -1815,9 +2096,17 @@ namespace Flax.Build.Bindings
} }
else if (paramValue.Contains("MUtils::ToArray(")) // FIXME else if (paramValue.Contains("MUtils::ToArray(")) // FIXME
{ {
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false); if (parameterInfo.Type.Type == "BytesContainer")
if (paramIsRef)
{ {
if (useThunk)
contents.Append($" MUtils::FreeManagedArray<byte>((MArray*)params[{i}]); //fgfgh8").AppendLine();
else
contents.Append($" MCore::GC::FreeMemory(__param_{parameterInfo.Name}.data, true); //fgfghdf8").AppendLine();
//contents.Append($" MUtils::FreeManagedArray<byte>((MArray*)params[{i}]); //fgfgh8").AppendLine();
}
else if (paramIsRef)
{
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
//contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine(); //contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
/*if (useThunk) /*if (useThunk)
{ {
@@ -1825,16 +2114,41 @@ namespace Flax.Build.Bindings
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{parameterInfo.Name}) //asdf1a").AppendLine(); contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{parameterInfo.Name}) //asdf1a").AppendLine();
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine(); contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
}*/ }*/
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_{parameterInfo.Name}); //fgfgh3").AppendLine();
if (useThunk) //var isPod = parameterInfo.Type.GenericArgs.Count > 0 ? parameterInfo.Type.GenericArgs[0].IsPod(buildData, apiType) : false;
contents.Append($" // {parameterInfo.Type} is pod: {elementApiType?.IsPod}, valuetype: {paramIsValueType}, classtype: {apiType.IsClass} // huah").AppendLine();
if (useThunk /*|| CppParamsThatNeedConversion[i]*/ || genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
{ {
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_{parameterInfo.Name}); //fgfgh3").AppendLine();
// Release the original handle // Release the original handle
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").AppendLine(); contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").AppendLine();
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_orig_{parameterInfo.Name}); //fgfgh4").AppendLine(); contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_orig_{parameterInfo.Name}); //fgfgh4").AppendLine();
} }
/*else if (elementIsValueType)
{
contents.Append($" // huhhah free").AppendLine();
}*/
else// if (CppParamsThatNeedConversion[i])
{
contents.Append($" MCore::GC::FreeMemory(__param_{parameterInfo.Name}.data, true); //jfgfgh7").AppendLine();
// Release the original handle
contents.Append($" if (__param_orig_{parameterInfo.Name}.data != __param_{parameterInfo.Name}.data)").AppendLine();
contents.Append($" MCore::GC::FreeMemory(__param_orig_{parameterInfo.Name}.data, true); //fgfgh8").AppendLine();
}
}
else if (elementApiType?.IsPod ?? false)
{
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable))
contents.Append($" MCore::GC::FreeMemory(__param_{parameterInfo.Name}.data, true); //kfgfgh7a").AppendLine();
else
contents.Append($" MCore::GC::FreeMemory(params[{i}], true); //kfgfgh7b").AppendLine();
} }
else if (apiType != null && !apiType.IsInBuild) else if (apiType != null && !apiType.IsInBuild)
{ {
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
// int: ispod, isvaluetype // int: ispod, isvaluetype
// vector: ispod, isvaluetype, isstruct // vector: ispod, isvaluetype, isstruct
// guid: ispod, isvaluetype, isstruct, isinbuild // guid: ispod, isvaluetype, isstruct, isinbuild
@@ -1843,8 +2157,9 @@ namespace Flax.Build.Bindings
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine(); //contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
//contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine(); //contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
} }
else if (apiType != null && !apiType.IsValueType) else if (apiType != null && !paramIsValueType)
{ {
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
if (parameterInfo.Type.Type.ToLower().Contains("string")) if (parameterInfo.Type.Type.ToLower().Contains("string"))
apiType = apiType; apiType = apiType;
contents.Append($" MUtils::FreeManagedArray<{genericType}>((MArray*)params[{i}]); //fgfgh6").AppendLine(); contents.Append($" MUtils::FreeManagedArray<{genericType}>((MArray*)params[{i}]); //fgfgh6").AppendLine();
@@ -1854,7 +2169,7 @@ namespace Flax.Build.Bindings
if (parameterInfo.Type.Type.ToLower().Contains("string")) if (parameterInfo.Type.Type.ToLower().Contains("string"))
apiType = apiType; apiType = apiType;
//contents.Append($" //asdf1c {parameterInfo.Type.Type}").AppendLine(); //contents.Append($" //asdf1c {parameterInfo.Type.Type}").AppendLine();
contents.Append($" auto __param{i}_handle = *(MGCHandle*)&params[{i}]; //fgfgh7").AppendLine(); contents.Append($" auto __param{i}_handle = *(MGCHandle*)&params[{i}]; //nfgfgh7").AppendLine();
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine(); //contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine(); contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
} }
@@ -2299,7 +2614,7 @@ namespace Flax.Build.Bindings
{ {
// Convert value back from managed to native (could be modified there) // Convert value back from managed to native (could be modified there)
paramType.IsRef = false; paramType.IsRef = false;
var managedToNative = GenerateCppWrapperManagedToNative(buildData, paramType, classInfo, out var managedType, out var apiType, null, out _); var managedToNative = GenerateCppWrapperManagedToNative(buildData, paramType, classInfo, null, ParameterGeneratorFlags.None, out var managedType, out var apiType, out _);
var passAsParamPtr = managedType.EndsWith("*"); var passAsParamPtr = managedType.EndsWith("*");
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType; var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]"; var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
@@ -3231,7 +3546,9 @@ namespace Flax.Build.Bindings
continue; continue;
} }
//CppNativeArrayAsParameter = true;
CppParamsWrappersCache[i] = GenerateCppWrapperNativeToManaged(buildData, fieldInfo.Type, apiType, out type, null); CppParamsWrappersCache[i] = GenerateCppWrapperNativeToManaged(buildData, fieldInfo.Type, apiType, out type, null);
//CppNativeArrayAsParameter = false;
header.AppendFormat(" {0} {1};", type, fieldInfo.Name).AppendLine(); header.AppendFormat(" {0} {1};", type, fieldInfo.Name).AppendLine();
} }
header.Append('}').Append(';').AppendLine(); header.Append('}').Append(';').AppendLine();
@@ -3251,7 +3568,7 @@ namespace Flax.Build.Bindings
header.AppendFormat(" DLLEXPORT USED MObject* Box(const {0}& data, const MClass* klass)", fullName).AppendLine(); header.AppendFormat(" DLLEXPORT USED MObject* Box(const {0}& data, const MClass* klass)", fullName).AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
header.Append(" auto managed = ToManaged(data);").AppendLine(); header.Append(" auto managed = ::ToManaged(data);").AppendLine();
header.Append(" auto boxed = MCore::Object::Box((void*)&managed, klass);").AppendLine(); header.Append(" auto boxed = MCore::Object::Box((void*)&managed, klass);").AppendLine();
header.Append(" ::FreeManaged(managed);").AppendLine(); header.Append(" ::FreeManaged(managed);").AppendLine();
header.Append(" return boxed;").AppendLine(); header.Append(" return boxed;").AppendLine();
@@ -3262,7 +3579,7 @@ namespace Flax.Build.Bindings
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine(); //header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
header.AppendFormat(" {0} managed;", wrapperName).AppendLine(); header.AppendFormat(" {0} managed;", wrapperName).AppendLine();
header.Append(" MCore::Object::Unbox(data, &managed);").AppendLine(); header.Append(" MCore::Object::Unbox(data, &managed);").AppendLine();
header.Append(" result = ToNative(managed);").AppendLine(); header.Append(" result = ::ToNative(managed);").AppendLine();
header.Append(" ::FreeManaged(managed);").AppendLine(); header.Append(" ::FreeManaged(managed);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
@@ -3272,7 +3589,7 @@ namespace Flax.Build.Bindings
header.AppendFormat(" {0}* resultPtr = ({0}*)MCore::Array::GetAddress(result);", wrapperName).AppendLine(); header.AppendFormat(" {0}* resultPtr = ({0}*)MCore::Array::GetAddress(result);", wrapperName).AppendLine();
header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine(); header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
header.Append(" auto managed = ToManaged(data[i]);").AppendLine(); header.Append(" auto managed = ::ToManaged(data[i]);").AppendLine();
header.Append(" MCore::GC::WriteValue(&resultPtr[i], &managed, 1, klass);").AppendLine(); header.Append(" MCore::GC::WriteValue(&resultPtr[i], &managed, 1, klass);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
@@ -3281,7 +3598,7 @@ namespace Flax.Build.Bindings
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
header.AppendFormat(" {0}* dataPtr = ({0}*)MCore::Array::GetAddress(data);", wrapperName).AppendLine(); header.AppendFormat(" {0}* dataPtr = ({0}*)MCore::Array::GetAddress(data);", wrapperName).AppendLine();
header.Append(" for (int32 i = 0; i < result.Length(); i++)").AppendLine(); header.Append(" for (int32 i = 0; i < result.Length(); i++)").AppendLine();
header.Append(" result[i] = ToNative(dataPtr[i]);").AppendLine(); header.Append(" result[i] = ::ToNative(dataPtr[i]);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data)").AppendLine(); header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data)").AppendLine();
@@ -3311,6 +3628,27 @@ namespace Flax.Build.Bindings
header.Append('}').Append(';').AppendLine(); header.Append('}').Append(';').AppendLine();
// Generate MConverter for a structure
header.Append("template<>").AppendLine();
header.AppendFormat("struct MConverter<{0}, {1}>", fullName, wrapperName).AppendLine();
header.Append('{').AppendLine();
header.AppendFormat(" DLLEXPORT USED void ToManaged({1}& result, const {0}& data) const /*struct*/", fullName, wrapperName).AppendLine();
header.Append(" {").AppendLine();
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
//header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
header.Append(" result = ::ToManaged(data);").AppendLine();
header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void ToNative({0}& result, const {1}& data) const", fullName, wrapperName).AppendLine();
header.Append(" {").AppendLine();
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
//header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
header.Append(" result = ::ToNative(data);").AppendLine();
header.Append(" }").AppendLine();
header.Append('}').Append(';').AppendLine();
// Generate converting function native -> managed // Generate converting function native -> managed
header.AppendLine(); header.AppendLine();
header.AppendLine("namespace {"); header.AppendLine("namespace {");
@@ -3356,7 +3694,7 @@ namespace Flax.Build.Bindings
continue; continue;
CppNonPodTypesConvertingGeneration = true; CppNonPodTypesConvertingGeneration = true;
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var fieldTypeName, out var fieldType, null, out _); var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, null, ParameterGeneratorFlags.None, out var fieldTypeName, out var fieldType, out _);
CppNonPodTypesConvertingGeneration = false; CppNonPodTypesConvertingGeneration = false;
var arrayCountName = $"value.{fieldInfo.Name}.length"; var arrayCountName = $"value.{fieldInfo.Name}.length";
@@ -3387,15 +3725,12 @@ namespace Flax.Build.Bindings
{ {
var arrayElementType = fieldInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, fieldInfo.Type.GenericArgs[0], apiType) : null; var arrayElementType = fieldInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, fieldInfo.Type.GenericArgs[0], apiType) : null;
var ispod = (arrayElementType?.IsPod.ToString() ?? "null"); var ispod = (arrayElementType?.IsPod.ToString() ?? "null");
header.Append($" // {fieldInfo.Type.Type}, {fieldType?.FullNameNative}, {fieldType?.Name}, {fieldTypeName}, {ispod}").AppendLine(); header.Append($" // pluh: {fieldInfo.Type.Type}, {fieldType?.FullNameNative}, {fieldType?.Name}, {fieldTypeName}, {ispod}").AppendLine();
if (fieldInfo.Type.IsArrayOrSpan && (arrayElementType?.IsPod ?? false)) //if (fieldInfo.Type.IsArrayOrSpan && (arrayElementType?.IsValueType ?? false))
{ {
header.AppendFormat(" result.{0} = {1}; /*kaek1 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}.data", $"value.{fieldInfo.Name}.length")).AppendLine(); header.AppendFormat(" result.{0} = {1}; /*kaek1 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}", $"value.{fieldInfo.Name}.length")).AppendLine();
}
else
{
header.AppendFormat(" result.{0} = {1}; /*kaek2 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}", $"value.{fieldInfo.Name}.lengthnot")).AppendLine();
} }
//var fieldType = FindApiTypeInfo(buildData, fieldInfo.Type, apiType); //var fieldType = FindApiTypeInfo(buildData, fieldInfo.Type, apiType);
//header.AppendFormat(" result.{0} = {1}; /*kaek2*/", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}")).AppendLine(); //header.AppendFormat(" result.{0} = {1}; /*kaek2*/", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}")).AppendLine();
@@ -3421,7 +3756,7 @@ namespace Flax.Build.Bindings
continue; continue;
CppNonPodTypesConvertingGeneration = true; CppNonPodTypesConvertingGeneration = true;
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var managedType, out var fieldApiType, null, out _); var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, null, ParameterGeneratorFlags.None, out var managedType, out var fieldApiType, out _);
CppNonPodTypesConvertingGeneration = false; CppNonPodTypesConvertingGeneration = false;
if (fieldInfo.Type.IsArray) if (fieldInfo.Type.IsArray)
@@ -3558,7 +3893,7 @@ namespace Flax.Build.Bindings
continue; continue;
CppNonPodTypesConvertingGeneration = true; CppNonPodTypesConvertingGeneration = true;
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var type, out _, null, out _); var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, null, ParameterGeneratorFlags.None, out var type, out _, out _);
CppNonPodTypesConvertingGeneration = false; CppNonPodTypesConvertingGeneration = false;
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MField.h"); CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MField.h");
@@ -3576,6 +3911,18 @@ namespace Flax.Build.Bindings
header.Append(" return result;").AppendLine(); header.Append(" return result;").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void ToManaged({1}& result, const {0}& data) const /*class*/", fullName, fullName).AppendLine();
header.Append(" {").AppendLine();
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void ToNative({0}& result, const {1}& data) const", fullName, fullName).AppendLine();
header.Append(" {").AppendLine();
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void ToManagedArray(MArray* result, const Span<{0}>& data)", fullName).AppendLine(); header.AppendFormat(" DLLEXPORT USED void ToManagedArray(MArray* result, const Span<{0}>& data)", fullName).AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine(); header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine();

View File

@@ -487,6 +487,10 @@ namespace Flax.Build.Platforms
} }
commonArgs.Add("/Zc:__cplusplus"); commonArgs.Add("/Zc:__cplusplus");
// Strict standards conformance mode
commonArgs.Add("/permissive-");
commonArgs.Add("/Zc:externC-"); // Required for WindowsMinimal.h
// Generate Intrinsic Functions // Generate Intrinsic Functions
if (compileEnvironment.IntrinsicFunctions) if (compileEnvironment.IntrinsicFunctions)
commonArgs.Add("/Oi"); commonArgs.Add("/Oi");

View File

@@ -204,7 +204,7 @@ namespace Flax.Build.Projects.VisualStudio
var filePath = file.Replace('/', '\\'); // Normalize path var filePath = file.Replace('/', '\\'); // Normalize path
var projectPath = Utilities.MakePathRelativeTo(filePath, projectDirectory); var projectPath = Utilities.MakePathRelativeTo(filePath, projectDirectory);
string linkPath = null; string linkPath = null;
if (!filePath.StartsWith(rootPath)) if (!filePath.StartsWith(rootPath)) // TODO: FIXME for FlaxEngine project in game solutions
{ {
// Create folder structure for project external files // Create folder structure for project external files
var sourceIndex = filePath.LastIndexOf(@"\Source\"); var sourceIndex = filePath.LastIndexOf(@"\Source\");