_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
#include "Engine/Content/Deprecated.h"
Variant::Variant(const CommonValue& value)

View File

@@ -11,6 +11,9 @@ struct CommonValue;
template<typename T>
class AssetReference;
struct ScriptingTypeHandle;
template<typename T>
class DataContainer;
typedef DataContainer<byte> BytesContainer;
/// <summary>
/// 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(const Dictionary<Variant, Variant, HeapAllocation>& v);
explicit Variant(const Span<byte>& v);
explicit Variant(const BytesContainer& v);
explicit Variant(const CommonValue& v);
template<typename T>

View File

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

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#if USE_NETCORE
using FlaxEngine.Assertions;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -322,27 +323,24 @@ namespace FlaxEngine.Interop
#if FLAX_EDITOR
[HideInEditor]
#endif
public struct ManagedToNative
public static class ManagedToNative
{
ManagedHandle handle;
public void FromManaged(object[] managed)
public static object[] ConvertToManaged(NativeArray<IntPtr> unmanaged)
{
if (managed != null)
{
var managedArray = NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
handle = ManagedHandle.Alloc(managedArray, GCHandleType.Weak);
}
if (unmanaged.Data == null)
return null;
return NativeInterop.GCHandleArrayToManagedArray<object>(unmanaged);
}
public IntPtr ToUnmanaged()
public static NativeArray<IntPtr> ConvertToUnmanaged(object[] managed)
{
return ManagedHandle.ToIntPtr(handle);
if (managed == null)
return new NativeArray<IntPtr>();
return NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
}
public void Free()
public static void Free(NativeArray<IntPtr> unmanaged)
{
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
[HideInEditor]
#endif

View File

@@ -188,6 +188,28 @@ namespace FlaxEngine.Interop
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>
/// Converts array of GC Handles from native runtime to managed array.
/// </summary>
@@ -238,6 +260,24 @@ namespace FlaxEngine.Interop
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>
/// Converts array with a custom converter function for each element.
/// </summary>
@@ -270,6 +310,23 @@ namespace FlaxEngine.Interop
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>
/// <param name="assemblyName">The name to find</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)
{
if (byRef)
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
//if (byRef)
// nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
if (nativePtr != IntPtr.Zero)
{
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
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
managedValue = null;

View File

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

View File

@@ -106,7 +106,7 @@ public:
/// </remarks>
/// <param name="instance">The object of given type to get value from.</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>
/// 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>
/// <param name="instance">The object of given type to get value from.</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>
/// 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>
/// <param name="instance">The object of given type to get value from.</param>
/// <returns>The boxed value object.</returns>
MObject* GetValueBoxed(MObject* instance) const;
MObject* GetValueBoxed(const MObject* instance) const;
/// <summary>
/// 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>
/// <param name="instance">The object of given type to set value to.</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:
/// <summary>

View File

@@ -13,6 +13,12 @@
#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;
class CultureInfo;
template<typename AllocationType>
@@ -49,6 +55,12 @@ struct MConverter
{
MObject* Box(const T& data, const MClass* klass);
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 ToManagedArray(MArray* result, const Span<T>& data);
void ToNativeArray(Span<T>& result, const MArray* data);
@@ -61,6 +73,16 @@ struct NativeArray
{
T* data;
int32 length;
FORCE_INLINE operator T*() const
{
return data;
}
FORCE_INLINE Span<T> ToSpan() const
{
return Span<T>(data, length);
}
};
#if USE_NETCORE
@@ -79,6 +101,16 @@ struct MConverter<bool>
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)
{
}
@@ -116,6 +148,16 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
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)
{
Platform::MemoryCopy(MCore::Array::GetAddress(result), data.Get(), data.Length() * sizeof(T));
@@ -162,6 +204,16 @@ struct MConverter<String>
//#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)
{
if (data.Length() == 0)
@@ -212,6 +264,16 @@ struct MConverter<StringAnsi>
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)
{
if (data.Length() == 0)
@@ -262,6 +324,16 @@ struct MConverter<StringView>
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)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -316,6 +388,16 @@ struct MConverter<Variant>
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)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -365,6 +447,18 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
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)
{
if (data.Length() == 0)
@@ -405,9 +499,29 @@ struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Val
return data.GetOrCreateManagedInstance();
}
void ToManagedArray(MArray* result, const Span<T>& data)
void ToManaged(MObject*& result, const T& data)
{
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)
return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -449,6 +563,16 @@ struct MConverter<ScriptingObjectReference<T>>
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)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -501,6 +625,17 @@ struct MConverter<AssetReference<T>>
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)
{
if (data.Length() == 0)
@@ -538,6 +673,29 @@ class SoftAssetReference;
template<typename 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)
{
//PLATFORM_DEBUG_BREAK; // FIXME
@@ -575,6 +733,16 @@ struct MConverter<SoftAssetReference<T>>
template<typename 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)
{
PLATFORM_DEBUG_BREAK; // FIXME
@@ -877,12 +1045,36 @@ namespace MUtils
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>
/// 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>
/*template<typename T, typename AllocationType = HeapAllocation>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
@@ -893,22 +1085,233 @@ namespace MUtils
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>
/// 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> 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
NativeArray<T> arr;
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));
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>
/// 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>

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);
}
void* MCore::Object::Unbox(MObject* obj)
void* MCore::Object::Unbox(const MObject* obj)
{
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"));
return CallStaticMethod<void, void*, void*>(UnboxValuePtr, obj, dest);
return CallStaticMethod<void, const void*, void*>(UnboxValuePtr, obj, dest);
}
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);
}
void MCore::Object::Init(MObject* obj)
void MCore::Object::Init(const MObject* obj)
{
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);
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"));
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"));
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"));
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"));
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"));
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;
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);
}
void MCore::String::Free(MString* obj)
void MCore::String::Free(const MString* obj)
{
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)
@@ -485,7 +485,7 @@ void MCore::Array::Free(const MArray* 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"));
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);
}
MArray* MCore::Array::Unbox(MObject* obj)
MArray* MCore::Array::Unbox(const MObject* obj)
{
static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray"));
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);
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);
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)
@@ -1387,28 +1387,28 @@ int32 MField::GetOffset() const
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"));
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"));
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"));
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"));
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

View File

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

View File

@@ -132,7 +132,7 @@ public:
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)
{

View File

@@ -635,44 +635,60 @@ namespace Flax.Build.Bindings
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (functionInfo.ReturnType.IsArrayOrSpan || returnNativeType == "Array")
{
var elementApiType = functionInfo.ReturnType.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, functionInfo.ReturnType.GenericArgs[0], caller) : null;
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;
if (functionInfo.ReturnType.Type == "BytesContainer")
genericType = "byte";
if (functionInfo.ReturnType.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
genericType = null;
switch (genericType)
{
switch (functionInfo.ReturnType.GenericArgs[0].Type)
{
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
default:
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
case null:
case "":
case "String":
case "StringAnsi":
case "StringView":
unmanagedType = null;
break;
default:
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
unmanagedType = null;
else
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
if (!string.IsNullOrEmpty(unmanagedType))
{
@@ -681,18 +697,22 @@ namespace Flax.Build.Bindings
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"))})";
}
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
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")
{
//[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")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
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[]")
{
// Boolean arrays does not support custom marshalling for some unknown reason
@@ -742,44 +762,65 @@ namespace Flax.Build.Bindings
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (parameterInfo.Type.IsArrayOrSpan || nativeType == "Array")
{
var elementApiType = parameterInfo.Type.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null;
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")
genericType = "byte";
if (parameterInfo.Type.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
genericType = null;
switch (genericType)
{
switch (parameterInfo.Type.GenericArgs[0].Type)
{
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
default:
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
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:
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
unmanagedType = null;
else if (elementApiType == null)
unmanagedType = "Any";
else
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
if (!string.IsNullOrEmpty(unmanagedType))
{
@@ -788,10 +829,28 @@ namespace Flax.Build.Bindings
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"))})";
}
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
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 = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
parameterMarshalType = $"/*marsh5b*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
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.
//if (elementApiType?.MarshalAs != null)
// parameterMarshalType += $"] [MarshalUsing(typeof({elementApiType.MarshalAs}), ElementIndirectionDepth = 1)";
}
else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
@@ -801,7 +860,7 @@ namespace Flax.Build.Bindings
parameterMarshalType = "MarshalAs(UnmanagedType.I2)";
else if (nativeType.EndsWith("[]"))
{
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>))";
parameterMarshalType = $"/*marsh6*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>))";
}
if (!string.IsNullOrEmpty(parameterMarshalType))
@@ -841,7 +900,7 @@ namespace Flax.Build.Bindings
{
// TODO: make this code shared with MarshalUsing selection from the above
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")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
else if (parameterInfo.Type.Type == "CultureInfo")
@@ -1806,11 +1865,22 @@ namespace Flax.Build.Bindings
type = "IntPtr";
else if (marshalType.IsPtr && !originalType.EndsWith("*"))
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);
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")
type = "IntPtr";
@@ -1827,12 +1897,14 @@ namespace Flax.Build.Bindings
}
//else if (type == "Guid")
// 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
toManagedContent.Append("managed.").Append(fieldInfo.Name).Append(" = ");
toNativeContent.Append("unmanaged.").Append(fieldInfo.Name).Append(" = ");
var managedField = $"managed.{fieldInfo.Name}";
var unmanagedField = $"unmanaged.{fieldInfo.Name}";
toManagedContent.Append($"{managedField} = ");
toNativeContent.Append($"{unmanagedField} = ");
if (marshalType.IsObjectRef)
{
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(); }}");
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);
if (internalType)
@@ -1877,17 +1949,17 @@ namespace Flax.Build.Bindings
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";
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.ConvertArray((Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToSpan<{internalElementType}>(), {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;");
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(); }}");
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(); }}");
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.ConvertArray({unmanagedField}.AsSpan(), {originalElementTypeMarshaller}.ToManaged) : null;");
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ConvertArrayNative({managedField}.AsSpan(), {originalElementTypeMarshaller}.ToNative) : new NativeArray<{internalElementType}>();");
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var value in {unmanagedField}.AsReadOnlySpan()) {{ {originalElementTypeMarshaller}.Free(value); }} {unmanagedField}.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)
{
// 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;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name})/*, GCHandleType.Weak*/) : IntPtr.Zero;");
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(); }}");
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>({unmanagedField}) : null;");
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name}) : new NativeArray<IntPtr>();");
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
//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
{
// Blittable array elements
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? (Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToArray<{originalElementType}>() : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak) : IntPtr.Zero;");
freeContents.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 (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? {unmanagedField}.AsReadOnlySpan().ToArray() : null;");
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? new NativeArray<{originalElementType}>({managedField}.AsSpan()) : new NativeArray<{originalElementType}>();");
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
freeContents2.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
}
}
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.
/// </summary>
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
@@ -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> CppVariantFromTypes = new Dictionary<string, TypeInfo>();
private static bool CppNonPodTypesConvertingGeneration = false;
private static bool CppNativeArrayAsParameter = false;
private static StringBuilder CppContentsEnd;
public class ScriptingLangInfo
@@ -88,9 +110,13 @@ namespace Flax.Build.Bindings
"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)
@@ -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)
{
formattingFlags = ParameterFormattingFlags.None;
//CppNativeArrayAsParameter = true;
var nativeToManaged = GenerateCppWrapperNativeToManaged(buildData, paramType, caller, out var managedTypeAsNative, null);
//CppNativeArrayAsParameter = false;
string result;
if (!string.IsNullOrEmpty(nativeToManaged))
{
result = string.Format(nativeToManaged, paramName);
if (managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' && !isRef)
if ((managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' || managedTypeAsNative.StartsWith("NativeArray<")) && !isRef)
{
// Pass pointer value
}
@@ -135,6 +163,7 @@ namespace Flax.Build.Bindings
// Pass as pointer to local variable converted for managed runtime
if (paramType.IsPtr)
result = string.Format(nativeToManaged, '*' + paramName);
contents.Append($" // localvar1 {managedTypeAsNative}, {paramType.ToString()}").AppendLine();
contents.Append($" auto __param_orig_{paramName} = {result};").AppendLine();
contents.Append($" auto __param_{paramName} = __param_orig_{paramName};").AppendLine();
result = $"&__param_{paramName}";
@@ -543,30 +572,28 @@ namespace Flax.Build.Bindings
return "{0}.GetManagedInstance()";
}
// Array or DataContainer
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
#if !USE_NETCORE
// BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
{
var arrayTypeInfo = typeInfo.GenericArgs[0];
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
#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
{
//type = arrayApiType.FullNameNative + "*/*wahho*/";
type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/";
//if (arrayTypeInfo.Type == "bool")
// return "MUtils::ToBoolArray({0})/*bahho*/";
return "MUtils::ToNativeArrayWrapper({0})/*nahhoa7eatra*/";
}
}
type = "MArray*";
return "MUtils::ToArray({0})";
}
// Span
if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null)
{
type = "MonoArray*";
return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
}
#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*";
if (arrayApiType != null && arrayApiType.MarshalAs != null)
{
@@ -576,25 +603,98 @@ namespace Flax.Build.Bindings
var genericArgs = arrayApiType.MarshalAs.GetFullNameNative(buildData, caller);
if (typeInfo.GenericArgs.Count != 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
// Span
if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null)
{
type = "MonoArray*";
return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
}
#if USE_NETCORE
if (typeInfo.Type == "BytesContainer")
{
type = "NativeArray<byte> /*baggo*/";
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
// BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
{
type = "MArray*";
return "MUtils::ToArray({0})";
return "/*custom: " + typeInfo.ToString() + " */MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
}
// 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;
@@ -704,7 +806,7 @@ namespace Flax.Build.Bindings
if (typeInfo.IsArray)
{
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()";
}
@@ -771,7 +873,7 @@ namespace Flax.Build.Bindings
// Array
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
{
formattingFlags.SetFlag(ParameterFormattingFlags.NeedLocalVariable, true);
//formattingFlags.SetFlag(ParameterFormattingFlags.NeedLocalVariable, true);
var arrayTypeInfo = typeInfo.GenericArgs[0];
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
if (arrayApiType != null && arrayApiType.MarshalAs != null)
@@ -791,16 +893,72 @@ namespace Flax.Build.Bindings
genericArgs += ", " + typeInfo.GenericArgs[1];
result = $"Array<{genericArgs}>({result})";
}
else if (arrayApiType?.IsPod ?? false)
#if false
else if (arrayApiType?.IsScriptingObject ?? false)
{
type = arrayApiType.FullNameNative + '*';
result = $"Array<{genericArgs}>(({arrayApiType.FullNameNative}*){{0}}, {{1}})/*xviox1 {arrayTypeInfo.Type}*/";
result += "/*123scriptingobject*/";
}
#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")
{
throw new Exception("huh");
type = "bool*";
result = "Array<bool>({0}, {1})/*xviox2*/\"";
result = "Array<bool>({0}, {1})/*123bool*/\"";
}
#endif
return result;
}
@@ -853,9 +1011,15 @@ namespace Flax.Build.Bindings
// BytesContainer
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);
type = "MArray*";
return "MUtils::LinkArray({0})";
#endif
}
// Function
@@ -876,7 +1040,7 @@ namespace Flax.Build.Bindings
if (apiType != 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)
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)})";
// BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
return $"MUtils::ToArray({value})";
//if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
// return $"MUtils::ToArray({value})";
// Construct native typename for MUtils template argument
var nativeType = new StringBuilder(64);
@@ -1042,6 +1206,13 @@ namespace Flax.Build.Bindings
callerName = callerName;
if (functionInfo.UniqueName == "SetDriveControl")
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#
functionInfo.Glue = new FunctionInfo.GlueInfo
@@ -1055,7 +1226,9 @@ namespace Flax.Build.Bindings
returnType = returnApiType.MarshalAs;
bool returnTypeIsContainer = false;
//CppNativeArrayAsParameter = true;
var returnValueConvert = GenerateCppWrapperNativeToManaged(buildData, functionInfo.ReturnType, caller, out var returnValueType, functionInfo);
//CppNativeArrayAsParameter = false;
if (functionInfo.Glue.UseReferenceForResult)
{
returnValueType = "void";
@@ -1072,7 +1245,7 @@ namespace Flax.Build.Bindings
});
}
#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;
functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo
@@ -1082,6 +1255,21 @@ namespace Flax.Build.Bindings
Type = new TypeInfo("int"),
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
@@ -1137,8 +1325,29 @@ namespace Flax.Build.Bindings
contents.Append(", ");
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;
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)
var isOutWithManagedConverter = parameterInfo.IsOut && !string.IsNullOrEmpty(GenerateCSharpManagedToNativeConverter(buildData, parameterInfo.Type, caller));
@@ -1186,7 +1395,7 @@ namespace Flax.Build.Bindings
}
}
#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
var name = $"__{parameterInfo.Name}Count";
@@ -1213,7 +1422,7 @@ namespace Flax.Build.Bindings
contents.Append(", ");
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);
if (parameterInfo.IsRef || parameterInfo.IsOut || UsePassByReference(buildData, parameterInfo.Type, caller))
contents.Append('*');
@@ -1281,6 +1490,7 @@ namespace Flax.Build.Bindings
// Call native member method
call = $"__obj->{functionInfo.Name}";
}
contents.Append(indent).Append($"// convert values").AppendLine();
string callParams = string.Empty;
separator = false;
for (var i = 0; i < functionInfo.Parameters.Count; i++)
@@ -1311,12 +1521,26 @@ namespace Flax.Build.Bindings
}
else
{
// Convert value
param += string.Format(CppParamsWrappersCache[i], name, countParamName);
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
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)
if (CppParamsThatNeedConversion[i])
else if (CppParamsThatNeedConversion[i])
{
var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, caller);
if (apiType != null)
@@ -1338,6 +1562,9 @@ namespace Flax.Build.Bindings
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&)
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
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
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 += "Temp";
}
@@ -1378,11 +1605,28 @@ namespace Flax.Build.Bindings
contents.AppendLine();
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
#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);
call = string.Format(callFormat, call, callParams);
call += "/*call123*/";
}
if (!string.IsNullOrEmpty(returnValueConvert))
{
@@ -1418,6 +1662,7 @@ namespace Flax.Build.Bindings
// Convert special parameters back to managed world
if (!useInlinedReturn)
{
contents.Append(indent).Append($"// !useInlinedReturn").AppendLine();
for (var i = 0; i < functionInfo.Parameters.Count; i++)
{
var parameterInfo = functionInfo.Parameters[i];
@@ -1427,7 +1672,7 @@ namespace Flax.Build.Bindings
{
var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp");
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
if (parameterInfo.IsOut)
{
@@ -1439,17 +1684,24 @@ namespace Flax.Build.Bindings
#if USE_NETCORE
if (parameterInfo.Type.Type == "Array")
{
if (elementType?.IsPod ?? false)
//if (elementType?.IsPod ?? true)
{
contents.Append(indent).Append($"// isgigs1a").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();
var nativeType = elementType?.FullNameNative;
var internalType = elementType?.FullNameNativeInternal;
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
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
/*else
{
contents.Append(indent).Append($"// isgigs1b").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
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
@@ -1475,20 +1727,24 @@ namespace Flax.Build.Bindings
// BytesContainer
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).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
// 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();
//continue;
#endif
}
else
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();
else
else*/
contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine();
#if USE_NETCORE
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))
return;
if (functionInfo.UniqueName == "CoverageTest1ByRef")
scriptVTableSize = scriptVTableSize;
contents.AppendFormat(" {0} {1}_ManagedWrapper(", functionInfo.ReturnType, functionInfo.UniqueName);
var separator = false;
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
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)
{
//contents.AppendLine($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::{functionInfo.Name}\");");
@@ -1658,6 +1917,7 @@ namespace Flax.Build.Bindings
if (paramIsRef)
{
// 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_{parameterInfo.Name} = __param_orig_{parameterInfo.Name};").AppendLine();
paramValue = $"&__param_{parameterInfo.Name}";
@@ -1719,6 +1979,7 @@ namespace Flax.Build.Bindings
// Invoke method
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)
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)
{
// Direct value convert
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, out var managedType, out var apiType, null, out _);
var passAsParamPtr = managedType.EndsWith("*");
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
var paramName = CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable) ? $"__param_{parameterInfo.Name}" : $"params[{i}]";
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, null, ParameterGeneratorFlags.None, out var managedType, out var apiType, out _);
var passAsParamPtr = managedType.EndsWith("*") || true;
var useLocalVarPointer = !CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable);
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)&{paramName}" : paramName;
if (!string.IsNullOrEmpty(managedToNative))
{
if (!passAsParamPtr)
paramValue = '*' + paramValue;
paramValue = string.Format(managedToNative, paramValue);
paramValue = string.Format(managedToNative, paramValue, $"__param_{parameterInfo.Name}.length");
}
else if (!passAsParamPtr)
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++)
{
var parameterInfo = functionInfo.Parameters[i];
var paramValue = GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, out var apiType, parameterInfo.Name);
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
{
@@ -1779,31 +2047,44 @@ namespace Flax.Build.Bindings
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.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
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ 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)
{
// int: ispod, isvaluetype
// vector: ispod, isvaluetype, isstruct
// guid: ispod, isvaluetype, isstruct, isinbuild
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1b").AppendLine();
if (useThunk || !paramIsValueType)
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($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").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"))
apiType = apiType;
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"))
apiType = apiType;
@@ -1815,9 +2096,17 @@ namespace Flax.Build.Bindings
}
else if (paramValue.Contains("MUtils::ToArray(")) // FIXME
{
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
if (paramIsRef)
if (parameterInfo.Type.Type == "BytesContainer")
{
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();
/*if (useThunk)
{
@@ -1825,16 +2114,41 @@ namespace Flax.Build.Bindings
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::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
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").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)
{
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
// int: ispod, isvaluetype
// vector: ispod, isvaluetype, isstruct
// 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($" 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"))
apiType = apiType;
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"))
apiType = apiType;
//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($" 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)
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 useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
@@ -3231,7 +3546,9 @@ namespace Flax.Build.Bindings
continue;
}
//CppNativeArrayAsParameter = true;
CppParamsWrappersCache[i] = GenerateCppWrapperNativeToManaged(buildData, fieldInfo.Type, apiType, out type, null);
//CppNativeArrayAsParameter = false;
header.AppendFormat(" {0} {1};", type, fieldInfo.Name).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.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(" ::FreeManaged(managed);").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(" {0} managed;", wrapperName).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(" }").AppendLine();
@@ -3272,7 +3589,7 @@ namespace Flax.Build.Bindings
header.AppendFormat(" {0}* resultPtr = ({0}*)MCore::Array::GetAddress(result);", wrapperName).AppendLine();
header.Append(" for (int32 i = 0; i < data.Length(); i++)").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(" }").AppendLine();
header.Append(" }").AppendLine();
@@ -3281,7 +3598,7 @@ namespace Flax.Build.Bindings
header.Append(" {").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(" result[i] = ToNative(dataPtr[i]);").AppendLine();
header.Append(" result[i] = ::ToNative(dataPtr[i]);").AppendLine();
header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data)").AppendLine();
@@ -3311,6 +3628,27 @@ namespace Flax.Build.Bindings
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
header.AppendLine();
header.AppendLine("namespace {");
@@ -3356,7 +3694,7 @@ namespace Flax.Build.Bindings
continue;
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;
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 ispod = (arrayElementType?.IsPod.ToString() ?? "null");
header.Append($" // {fieldInfo.Type.Type}, {fieldType?.FullNameNative}, {fieldType?.Name}, {fieldTypeName}, {ispod}").AppendLine();
if (fieldInfo.Type.IsArrayOrSpan && (arrayElementType?.IsPod ?? false))
header.Append($" // pluh: {fieldInfo.Type.Type}, {fieldType?.FullNameNative}, {fieldType?.Name}, {fieldTypeName}, {ispod}").AppendLine();
//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();
}
else
{
header.AppendFormat(" result.{0} = {1}; /*kaek2 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}", $"value.{fieldInfo.Name}.lengthnot")).AppendLine();
header.AppendFormat(" result.{0} = {1}; /*kaek1 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}", $"value.{fieldInfo.Name}.length")).AppendLine();
}
//var fieldType = FindApiTypeInfo(buildData, fieldInfo.Type, apiType);
//header.AppendFormat(" result.{0} = {1}; /*kaek2*/", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}")).AppendLine();
@@ -3421,7 +3756,7 @@ namespace Flax.Build.Bindings
continue;
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;
if (fieldInfo.Type.IsArray)
@@ -3558,7 +3893,7 @@ namespace Flax.Build.Bindings
continue;
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;
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MField.h");
@@ -3576,6 +3911,18 @@ namespace Flax.Build.Bindings
header.Append(" return result;").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.Append(" {").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");
// Strict standards conformance mode
commonArgs.Add("/permissive-");
commonArgs.Add("/Zc:externC-"); // Required for WindowsMinimal.h
// Generate Intrinsic Functions
if (compileEnvironment.IntrinsicFunctions)
commonArgs.Add("/Oi");

View File

@@ -204,7 +204,7 @@ namespace Flax.Build.Projects.VisualStudio
var filePath = file.Replace('/', '\\'); // Normalize path
var projectPath = Utilities.MakePathRelativeTo(filePath, projectDirectory);
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
var sourceIndex = filePath.LastIndexOf(@"\Source\");