_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

@@ -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\");