Merge remote-tracking branch 'origin/master' into 1.8

# Conflicts:
#	Source/Editor/Utilities/EditorUtilities.cpp
#	Source/Editor/Utilities/EditorUtilities.h
This commit is contained in:
Wojtek Figat
2024-02-19 22:26:16 +01:00
219 changed files with 4189 additions and 2372 deletions

View File

@@ -90,6 +90,15 @@ namespace Flax.Build.Bindings
"Int4",
};
private static bool GenerateCSharpUseFixedBuffer(string managedType)
{
return managedType == "byte" || managedType == "char" ||
managedType == "short" || managedType == "ushort" ||
managedType == "int" || managedType == "uint" ||
managedType == "long" || managedType == "ulong" ||
managedType == "float" || managedType == "double";
}
private static string GenerateCSharpDefaultValueNativeToManaged(BuildData buildData, string value, ApiTypeInfo caller, TypeInfo valueType = null, bool attribute = false, string managedType = null)
{
if (string.IsNullOrEmpty(value))
@@ -261,7 +270,7 @@ namespace Flax.Build.Bindings
return value;
}
private static string GenerateCSharpNativeToManaged(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
private static string GenerateCSharpNativeToManaged(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, bool marshalling = false)
{
string result;
if (typeInfo?.Type == null)
@@ -271,7 +280,7 @@ namespace Flax.Build.Bindings
if (typeInfo.IsArray)
{
typeInfo.IsArray = false;
result = GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
result = GenerateCSharpNativeToManaged(buildData, typeInfo, caller, marshalling);
typeInfo.IsArray = true;
return result + "[]";
}
@@ -298,7 +307,7 @@ namespace Flax.Build.Bindings
// Object reference property
if (typeInfo.IsObjectRef)
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller);
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling);
if (typeInfo.Type == "SoftTypeReference" || typeInfo.Type == "SoftObjectReference")
return typeInfo.Type;
@@ -308,15 +317,25 @@ namespace Flax.Build.Bindings
#else
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
#endif
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller) + "[]";
{
var arrayTypeInfo = typeInfo.GenericArgs[0];
if (marshalling)
{
// Convert array that uses different type for marshalling
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
if (arrayApiType != null && arrayApiType.MarshalAs != null)
arrayTypeInfo = arrayApiType.MarshalAs;
}
return GenerateCSharpNativeToManaged(buildData, arrayTypeInfo, caller) + "[]";
}
// Dictionary
if (typeInfo.Type == "Dictionary" && typeInfo.GenericArgs != null)
return string.Format("System.Collections.Generic.Dictionary<{0}, {1}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller), GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[1], caller));
return string.Format("System.Collections.Generic.Dictionary<{0}, {1}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling), GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[1], caller, marshalling));
// HashSet
if (typeInfo.Type == "HashSet" && typeInfo.GenericArgs != null)
return string.Format("System.Collections.Generic.HashSet<{0}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller));
return string.Format("System.Collections.Generic.HashSet<{0}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling));
// BitArray
if (typeInfo.Type == "BitArray" && typeInfo.GenericArgs != null)
@@ -339,16 +358,16 @@ namespace Flax.Build.Bindings
// TODO: generate delegates globally in the module namespace to share more code (smaller binary size)
var key = string.Empty;
for (int i = 0; i < typeInfo.GenericArgs.Count; i++)
key += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller);
key += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller, marshalling);
if (!CSharpAdditionalCodeCache.TryGetValue(key, out var delegateName))
{
delegateName = "Delegate" + CSharpAdditionalCodeCache.Count;
var signature = $"public delegate {GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller)} {delegateName}(";
var signature = $"public delegate {GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling)} {delegateName}(";
for (int i = 1; i < typeInfo.GenericArgs.Count; i++)
{
if (i != 1)
signature += ", ";
signature += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller);
signature += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller, marshalling);
signature += $" arg{(i - 1)}";
}
signature += ");";
@@ -381,11 +400,14 @@ namespace Flax.Build.Bindings
{
typeName += '<';
foreach (var arg in typeInfo.GenericArgs)
typeName += GenerateCSharpNativeToManaged(buildData, arg, caller);
typeName += GenerateCSharpNativeToManaged(buildData, arg, caller, marshalling);
typeName += '>';
}
if (apiType != null)
{
if (marshalling && apiType.MarshalAs != null)
return GenerateCSharpNativeToManaged(buildData, apiType.MarshalAs, caller);
// Add reference to the namespace
CSharpUsedNamespaces.Add(apiType.Namespace);
var apiTypeParent = apiType.Parent;
@@ -410,11 +432,11 @@ namespace Flax.Build.Bindings
return typeName;
}
private static string GenerateCSharpManagedToNativeType(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
private static string GenerateCSharpManagedToNativeType(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, bool marshalling = false)
{
// Fixed-size array
if (typeInfo.IsArray)
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller, marshalling);
// Find API type info
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
@@ -430,7 +452,7 @@ namespace Flax.Build.Bindings
}
if (apiType.MarshalAs != null)
return GenerateCSharpManagedToNativeType(buildData, new TypeInfo(apiType.MarshalAs), caller);
return GenerateCSharpManagedToNativeType(buildData, apiType.MarshalAs, caller, marshalling);
if (apiType.IsScriptingObject || apiType.IsInterface)
return "IntPtr";
}
@@ -443,7 +465,7 @@ namespace Flax.Build.Bindings
if (typeInfo.Type == "Function" && typeInfo.GenericArgs != null)
return "IntPtr";
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller, marshalling);
}
private static string GenerateCSharpManagedToNativeConverter(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
@@ -476,6 +498,18 @@ namespace Flax.Build.Bindings
case "Function":
// delegate
return "NativeInterop.GetFunctionPointerForDelegate({0})";
case "Array":
case "Span":
case "DataContainer":
if (typeInfo.GenericArgs != null)
{
// Convert array that uses different type for marshalling
var arrayTypeInfo = typeInfo.GenericArgs[0];
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
if (arrayApiType != null && arrayApiType.MarshalAs != null)
return $"{{0}}.ConvertArray(x => ({GenerateCSharpNativeToManaged(buildData, arrayApiType.MarshalAs, caller)})x)";
}
return string.Empty;
default:
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
if (apiType != null)
@@ -522,9 +556,9 @@ namespace Flax.Build.Bindings
{
var apiType = FindApiTypeInfo(buildData, functionInfo.ReturnType, caller);
if (apiType != null && apiType.MarshalAs != null)
returnValueType = GenerateCSharpNativeToManaged(buildData, new TypeInfo(apiType.MarshalAs), caller);
returnValueType = GenerateCSharpNativeToManaged(buildData, apiType.MarshalAs, caller, true);
else
returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller);
returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller, true);
}
#if USE_NETCORE
@@ -585,7 +619,7 @@ namespace Flax.Build.Bindings
contents.Append(", ");
separator = true;
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller);
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller, true);
#if USE_NETCORE
string parameterMarshalType = "";
if (nativeType == "System.Type")
@@ -638,7 +672,7 @@ namespace Flax.Build.Bindings
contents.Append(", ");
separator = true;
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller);
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller, true);
#if USE_NETCORE
string parameterMarshalType = "";
if (parameterInfo.IsOut && parameterInfo.DefaultValue == "var __resultAsRef")
@@ -751,7 +785,16 @@ namespace Flax.Build.Bindings
}
}
contents.Append(");");
contents.Append(')');
if ((functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer") && functionInfo.ReturnType.GenericArgs != null)
{
// Convert array that uses different type for marshalling
var arrayTypeInfo = functionInfo.ReturnType.GenericArgs[0];
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
if (arrayApiType != null && arrayApiType.MarshalAs != null)
contents.Append($".ConvertArray(x => ({GenerateCSharpNativeToManaged(buildData, arrayTypeInfo, caller)})x)");
}
contents.Append(';');
// Return result
if (functionInfo.Glue.UseReferenceForResult)
@@ -1439,10 +1482,10 @@ namespace Flax.Build.Bindings
indent += " ";
StringBuilder toManagedContent = new StringBuilder();
StringBuilder toNativeContent = new StringBuilder();
StringBuilder freeContents = new StringBuilder();
StringBuilder freeContents2 = new StringBuilder();
var toManagedContent = GetStringBuilder();
var toNativeContent = GetStringBuilder();
var freeContents = GetStringBuilder();
var freeContents2 = GetStringBuilder();
{
// Native struct begin
@@ -1457,10 +1500,9 @@ namespace Flax.Build.Bindings
contents.Append(indent + "{");
indent += " ";
toNativeContent.Append($"return new {structureInfo.Name}Internal() {{ ");
toManagedContent.Append($"return new {structureInfo.Name}() {{ ");
toNativeContent.Append($"var unmanaged = new {structureInfo.Name}Internal();").AppendLine();
toManagedContent.Append($"var managed = new {structureInfo.Name}();").AppendLine();
bool useSeparator = false;
contents.AppendLine();
foreach (var fieldInfo in structureInfo.Fields)
{
@@ -1478,11 +1520,7 @@ namespace Flax.Build.Bindings
else
originalType = type = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type, structureInfo);
contents.Append(indent).Append(GenerateCSharpAccessLevel(fieldInfo.Access));
if (fieldInfo.IsConstexpr)
contents.Append("const ");
else if (fieldInfo.IsStatic)
contents.Append("static ");
contents.Append(indent).Append("public ");
var apiType = FindApiTypeInfo(buildData, fieldInfo.Type, structureInfo);
bool internalType = apiType is StructureInfo fieldStructureInfo && UseCustomMarshalling(buildData, fieldStructureInfo, structureInfo);
@@ -1490,16 +1528,43 @@ namespace Flax.Build.Bindings
if (fieldInfo.Type.IsArray && (fieldInfo.NoArray || structureInfo.IsPod))
{
contents.Append(type).Append(' ').Append(fieldInfo.Name + "0;").AppendLine();
for (int i = 1; i < fieldInfo.Type.ArraySize; i++)
#if USE_NETCORE
if (GenerateCSharpUseFixedBuffer(originalType))
{
contents.AppendLine();
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic);
contents.Append(indent).Append(GenerateCSharpAccessLevel(fieldInfo.Access));
if (fieldInfo.IsStatic)
contents.Append("static ");
contents.Append(type).Append(' ').Append(fieldInfo.Name + i).Append(';').AppendLine();
// Use fixed statement with primitive types of buffers
contents.Append($"fixed {originalType} {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}];").AppendLine();
// Copy fixed-size array
toManagedContent.AppendLine($"FlaxEngine.Utils.MemoryCopy(new IntPtr(managed.{fieldInfo.Name}0), new IntPtr(unmanaged.{fieldInfo.Name}0), sizeof({originalType}) * {fieldInfo.Type.ArraySize}ul);");
toNativeContent.AppendLine($"FlaxEngine.Utils.MemoryCopy(new IntPtr(unmanaged.{fieldInfo.Name}0), new IntPtr(managed.{fieldInfo.Name}0), sizeof({originalType}) * {fieldInfo.Type.ArraySize}ul);");
}
else
#endif
{
// Padding in structs for fixed-size array
contents.Append(type).Append(' ').Append(fieldInfo.Name).Append("0;").AppendLine();
for (int i = 1; i < fieldInfo.Type.ArraySize; i++)
{
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic);
contents.Append(indent).Append("public ");
contents.Append(type).Append(' ').Append(fieldInfo.Name + i).Append(';').AppendLine();
}
// Copy fixed-size array item one-by-one
if (fieldInfo.Access == AccessLevel.Public || fieldInfo.Access == AccessLevel.Internal)
{
for (int i = 0; i < fieldInfo.Type.ArraySize; i++)
{
toManagedContent.AppendLine($"managed.{fieldInfo.Name}{i} = unmanaged.{fieldInfo.Name}{i};");
toNativeContent.AppendLine($"unmanaged.{fieldInfo.Name}{i} = managed.{fieldInfo.Name}{i};");
}
}
else
{
throw new NotImplementedException("TODO: generate utility method to copy private/protected array data items");
}
}
continue;
}
else
{
@@ -1529,34 +1594,17 @@ namespace Flax.Build.Bindings
//else if (type == "Guid")
// type = "GuidNative";
contents.Append(type).Append(' ').Append(fieldInfo.Name);
contents.Append(';').AppendLine();
contents.Append(type).Append(' ').Append(fieldInfo.Name).Append(';').AppendLine();
}
// Generate struct constructor/getter and deconstructor/setter function
if (fieldInfo.NoArray && fieldInfo.Type.IsArray)
continue;
if (useSeparator)
{
toManagedContent.Append(", ");
toNativeContent.Append(", ");
freeContents2.Append("");
freeContents.Append("");
}
useSeparator = true;
toManagedContent.Append(fieldInfo.Name);
toManagedContent.Append(" = ");
toNativeContent.Append(fieldInfo.Name);
toNativeContent.Append(" = ");
toManagedContent.Append("managed.").Append(fieldInfo.Name).Append(" = ");
toNativeContent.Append("unmanaged.").Append(fieldInfo.Name).Append(" = ");
if (fieldInfo.Type.IsObjectRef)
{
var managedType = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type.GenericArgs[0], structureInfo);
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{managedType}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null");
toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero");
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{managedType}>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target) : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero;");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
// Permanent ScriptingObject handle is passed from native side, do not release it
@@ -1564,8 +1612,8 @@ namespace Flax.Build.Bindings
}
else if (fieldInfo.Type.Type == "ScriptingObject")
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<FlaxEngine.Object>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null");
toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero");
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<FlaxEngine.Object>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target) : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero;");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
// Permanent ScriptingObject handle is passed from native side, do not release it
@@ -1573,8 +1621,8 @@ namespace Flax.Build.Bindings
}
else if (fieldInfo.Type.IsPtr && originalType != "IntPtr" && !originalType.EndsWith("*"))
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null");
toNativeContent.Append($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero");
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target) : null;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name} != null ? ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak) : IntPtr.Zero;");
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
// Permanent ScriptingObject handle is passed from native side, do not release it
@@ -1582,8 +1630,8 @@ namespace Flax.Build.Bindings
}
else if (fieldInfo.Type.Type == "Dictionary")
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null");
toNativeContent.Append($"ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak)");
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target) : null;");
toNativeContent.AppendLine($"ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak);");
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(); }}");
}
@@ -1595,16 +1643,16 @@ namespace Flax.Build.Bindings
// Marshal blittable array elements back to original non-blittable elements
string originalElementTypeMarshaller = originalElementType + "Marshaller";
string internalElementType = $"{originalElementTypeMarshaller}.{originalElementType}Internal";
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.ConvertArray((Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target)).ToSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null");
toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(NativeInterop.ConvertArray(managed.{fieldInfo.Name}, {originalElementTypeMarshaller}.ToNative)), GCHandleType.Weak) : IntPtr.Zero");
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}.Free(value); }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
}
else if (fieldInfo.Type.GenericArgs[0].IsObjectRef)
{
// Array elements passed as GCHandles
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>(Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target)) : null");
toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name}), GCHandleType.Weak) : IntPtr.Zero");
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(); }}");
// Permanent ScriptingObject handle is passed from native side, do not release it
@@ -1613,53 +1661,53 @@ namespace Flax.Build.Bindings
else
{
// Blittable array elements
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? (Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target)).ToArray<{originalElementType}>() : null");
toNativeContent.Append($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak) : IntPtr.Zero");
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(); }}");
}
}
else if (fieldInfo.Type.Type == "Version")
{
toManagedContent.Append($"managed.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(managed.{fieldInfo.Name}).Target) : null");
toNativeContent.Append($"ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak)");
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? Unsafe.As<{originalType}>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target) : null;");
toNativeContent.AppendLine($"ManagedHandle.ToIntPtr(managed.{fieldInfo.Name}, GCHandleType.Weak);");
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 (originalType == "string")
{
toManagedContent.Append($"ManagedString.ToManaged(managed.{fieldInfo.Name})");
toNativeContent.Append($"ManagedString.ToNative(managed.{fieldInfo.Name})");
toManagedContent.AppendLine($"ManagedString.ToManaged(unmanaged.{fieldInfo.Name});");
toNativeContent.AppendLine($"ManagedString.ToNative(managed.{fieldInfo.Name});");
freeContents.AppendLine($"ManagedString.Free(unmanaged.{fieldInfo.Name});");
freeContents2.AppendLine($"ManagedString.Free(unmanaged.{fieldInfo.Name});");
}
else if (originalType == "bool")
{
toManagedContent.Append($"managed.{fieldInfo.Name} != 0");
toNativeContent.Append($"managed.{fieldInfo.Name} ? (byte)1 : (byte)0");
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != 0;");
toNativeContent.AppendLine($"managed.{fieldInfo.Name} ? (byte)1 : (byte)0;");
}
else if (fieldInfo.Type.Type == "Variant")
{
// Variant passed as boxed object handle
toManagedContent.Append($"ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(managed.{fieldInfo.Name})");
toNativeContent.Append($"ManagedHandleMarshaller.NativeToManaged.ConvertToUnmanaged(managed.{fieldInfo.Name})");
toManagedContent.AppendLine($"ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged.{fieldInfo.Name});");
toNativeContent.AppendLine($"ManagedHandleMarshaller.NativeToManaged.ConvertToUnmanaged(managed.{fieldInfo.Name});");
}
else if (internalType)
{
toManagedContent.Append($"{internalTypeMarshaller}.ToManaged(managed.{fieldInfo.Name})");
toNativeContent.Append($"{internalTypeMarshaller}.ToNative(managed.{fieldInfo.Name})");
toManagedContent.AppendLine($"{internalTypeMarshaller}.ToManaged(unmanaged.{fieldInfo.Name});");
toNativeContent.AppendLine($"{internalTypeMarshaller}.ToNative(managed.{fieldInfo.Name});");
freeContents.AppendLine($"{internalTypeMarshaller}.Free(unmanaged.{fieldInfo.Name});");
freeContents2.AppendLine($"{internalTypeMarshaller}.Free(unmanaged.{fieldInfo.Name});");
}
/*else if (originalType == "Guid")
{
toManagedContent.Append("(Guid)managed.").Append(fieldInfo.Name);
toManagedContent.Append("(Guid)unmanaged.").Append(fieldInfo.Name);
toNativeContent.Append("(GuidNative)managed.").Append(fieldInfo.Name);
}*/
else
{
toManagedContent.Append("managed.").Append(fieldInfo.Name);
toNativeContent.Append("managed.").Append(fieldInfo.Name);
toManagedContent.Append("unmanaged.").Append(fieldInfo.Name).AppendLine(";");
toNativeContent.Append("managed.").Append(fieldInfo.Name).AppendLine(";");
}
}
@@ -1667,8 +1715,8 @@ namespace Flax.Build.Bindings
indent = indent.Substring(0, indent.Length - 4);
contents.AppendLine(indent + "}").AppendLine();
toManagedContent.AppendLine(" };");
toNativeContent.AppendLine(" };");
toNativeContent.Append("return unmanaged;");
toManagedContent.Append("return managed;");
}
var indent2 = indent + " ";
@@ -1716,7 +1764,7 @@ namespace Flax.Build.Bindings
contents.Append(indent).AppendLine("{").Append(indent2).AppendLine(freeContents.Replace("\n", "\n" + indent2).ToString().TrimEnd()).Append(indent).AppendLine("}");
// Managed/native converters
contents.Append(indent).AppendLine($"internal static {structureInfo.Name} ToManaged({structureInfo.Name}Internal managed)");
contents.Append(indent).AppendLine($"internal static {structureInfo.Name} ToManaged({structureInfo.Name}Internal unmanaged)");
contents.Append(indent).AppendLine("{").Append(indent2).AppendLine(toManagedContent.Replace("\n", "\n" + indent2).ToString().TrimEnd()).Append(indent).AppendLine("}");
contents.Append(indent).AppendLine($"internal static {structureInfo.Name}Internal ToNative({structureInfo.Name} managed)");
contents.Append(indent).AppendLine("{").Append(indent2).AppendLine(toNativeContent.Replace("\n", "\n" + indent2).ToString().TrimEnd()).Append(indent).AppendLine("}");
@@ -1724,6 +1772,11 @@ namespace Flax.Build.Bindings
contents.AppendLine("#pragma warning restore 1591");
indent = indent.Substring(0, indent.Length - 4);
contents.Append(indent).AppendLine("}").AppendLine();
PutStringBuilder(toManagedContent);
PutStringBuilder(toNativeContent);
PutStringBuilder(freeContents);
PutStringBuilder(freeContents2);
}
#endif
// Struct docs
@@ -1771,15 +1824,12 @@ namespace Flax.Build.Bindings
managedType = GenerateCSharpNativeToManaged(buildData, fieldInfo.Type, structureInfo);
fieldInfo.Type.IsArray = true;
#if USE_NETCORE
// Use fixed statement with primitive types of buffers
if (managedType == "char")
if (GenerateCSharpUseFixedBuffer(managedType))
{
// char's are not blittable, store as short instead
contents.Append($"fixed short {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}]; // {managedType}*").AppendLine();
}
else if (managedType == "byte")
{
contents.Append($"fixed byte {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}]; // {managedType}*").AppendLine();
// Use fixed statement with primitive types of buffers
if (managedType == "char")
managedType = "short"; // char's are not blittable, store as short instead
contents.Append($"fixed {managedType} {fieldInfo.Name}0[{fieldInfo.Type.ArraySize}];").AppendLine();
}
else
#endif
@@ -1789,7 +1839,6 @@ namespace Flax.Build.Bindings
for (int i = 1; i < fieldInfo.Type.ArraySize; i++)
{
contents.AppendLine();
GenerateCSharpComment(contents, indent, fieldInfo.Comment);
GenerateCSharpAttributes(buildData, contents, indent, structureInfo, fieldInfo, fieldInfo.IsStatic);
contents.Append(indent).Append(GenerateCSharpAccessLevel(fieldInfo.Access));
if (fieldInfo.IsStatic)