diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cs b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
index 476219960..9ceba0bbe 100644
--- a/Source/Editor/CustomEditors/CustomEditorsUtil.cs
+++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
@@ -139,7 +139,7 @@ namespace FlaxEditor.CustomEditors
return new GenericEditor();
}
- [LibraryImport("FlaxEngine", EntryPoint = "CustomEditorsUtilInternal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "CustomEditorsUtilInternal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalUsing(typeof(SystemTypeMarshaller))]
internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
}
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index aef5385d0..fe65abcdc 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -69,18 +69,18 @@ namespace FlaxEditor
///
/// Gets a value indicating whether this Editor is running a dev instance of the engine.
///
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsDevInstance", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsDevInstance")]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool IsDevInstance();
///
/// Gets a value indicating whether this Editor is running as official build (distributed via Flax services).
///
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsOfficialBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsOfficialBuild")]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool IsOfficialBuild();
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsPlayMode")]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_IsPlayMode();
@@ -1647,96 +1647,103 @@ namespace FlaxEditor
}
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_ReadOutputLogs", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
- internal static partial int Internal_ReadOutputLogs([MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref string[] outMessages, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref byte[] outLogTypes, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref long[] outLogTimes, int outCapacity);
+ internal static partial int Internal_ReadOutputLogs([MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller), CountElementName = "outCapacity")] ref string[] outMessages, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 3)] ref byte[] outLogTypes, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I8, SizeParamIndex = 3)] ref long[] outLogTimes, int outCapacity);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetPlayMode")]
internal static partial void Internal_SetPlayMode([MarshalAs(UnmanagedType.U1)] bool value);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
- internal static partial string Internal_GetProjectPath();
+ internal static string Internal_GetProjectPath()
+ {
+ Internal_GetProjectPath(out string projectPath);
+ return projectPath;
+ }
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
+ internal static partial void Internal_GetProjectPath([MarshalUsing(typeof(FlaxEngine.Interop.StringViewMarshaller))] out string projectPath);
+
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAudioClipMetadata", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAudioClipMetadata")]
internal static partial void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CopyCache", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CopyCache")]
internal static partial void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_BakeLightmaps", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_BakeLightmaps")]
internal static partial void Internal_BakeLightmaps([MarshalAs(UnmanagedType.U1)] bool cancel);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
+ [return: MarshalUsing(typeof(FlaxEngine.Interop.StringViewMarshaller))]
internal static partial string Internal_GetShaderAssetSourceCode(IntPtr obj);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetCollisionWires", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
- internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "trianglesCount")] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "indicesCount")] out int[] indices, out int trianglesCount, out int indicesCount);
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetCollisionWires")]
+ internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = "trianglesCount")] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "indicesCount")] out int[] indices, out int trianglesCount, out int indicesCount);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetEditorBoxWithChildren", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetEditorBoxWithChildren")]
internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetOptions")]
internal static partial void Internal_SetOptions(ref InternalOptions options);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DrawNavMesh", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DrawNavMesh")]
internal static partial void Internal_DrawNavMesh();
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloseSplashScreen")]
internal static partial void Internal_CloseSplashScreen();
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
internal static partial string Internal_CanImport(string extension);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CanExport(string path);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_Export(string inputPath, string outputFolder);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsEveryAssemblyLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsEveryAssemblyLoaded")]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_GetIsEveryAssemblyLoaded();
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetLastProjectOpenedEngineBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetLastProjectOpenedEngineBuild")]
internal static partial int Internal_GetLastProjectOpenedEngineBuild();
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsCSGActive", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsCSGActive")]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_GetIsCSGActive();
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_RunVisualScriptBreakpointLoopTick")]
internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_LoadAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_LoadAsset")]
internal static partial void Internal_LoadAsset(ref Guid id);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanSetToRoot", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanSetToRoot")]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime")]
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
- [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
+ [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetAnimationTime")]
internal static partial void Internal_SetAnimationTime(IntPtr animatedModel, float time);
#endregion
diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp
index 2220fb0f3..8af15a43b 100644
--- a/Source/Editor/Managed/ManagedEditor.Internal.cpp
+++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp
@@ -58,22 +58,22 @@ void OnLogMessage(LogType type, const StringView& msg)
{
ScopeLock lock(CachedLogDataLocker);
- CachedLogData.EnsureCapacity(4 + 8 + 4 + msg.Length() * 2);
+ CachedLogData.EnsureCapacity(sizeof(int32) + sizeof(DateTime) + sizeof(int32) + msg.Length() * sizeof(Char));
// Log Type
int32 buf = (int32)type;
- CachedLogData.Add((byte*)&buf, 4);
+ CachedLogData.Add((byte*)&buf, sizeof(int32));
// Time
auto time = DateTime::Now();
- CachedLogData.Add((byte*)&time.Ticks, 8);
+ CachedLogData.Add((byte*)&time.Ticks, sizeof(DateTime));
// Message Length
buf = msg.Length();
- CachedLogData.Add((byte*)&buf, 4);
+ CachedLogData.Add((byte*)&buf, sizeof(int32));
// Message
- CachedLogData.Add((byte*)msg.Get(), msg.Length() * 2);
+ CachedLogData.Add((byte*)msg.Get(), msg.Length() * sizeof(Char));
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_IsDevInstance()
@@ -99,7 +99,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_IsPlayMode()
return Editor::IsPlayMode;
}
-DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MArray** outMessages, MArray** outLogTypes, MArray** outLogTimes, int outArraySize)
+DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(NativeArray* outMessages, NativeArray* outLogTypes, NativeArray* outLogTimes, int outArraySize)
{
ScopeLock lock(CachedLogDataLocker);
if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr)
@@ -108,27 +108,30 @@ DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MArray** outMessages,
int32 count = 0;
const int32 maxCount = outArraySize;
+ String* messages = &outMessages->data[0];
byte* ptr = CachedLogData.Get();
byte* end = ptr + CachedLogData.Count();
- byte* outLogTypesPtr = MCore::Array::GetAddress(*outLogTypes);
- int64* outLogTimesPtr = MCore::Array::GetAddress(*outLogTimes);
+ byte* outLogTypesPtr = outLogTypes->data;
+ int64* outLogTimesPtr = outLogTimes->data;
while (count < maxCount && ptr != end)
{
auto type = (byte)*(int32*)ptr;
- ptr += 4;
+ ptr += sizeof(int32);
auto time = *(int64*)ptr;
- ptr += 8;
+ ptr += sizeof(int64);
auto length = *(int32*)ptr;
- ptr += 4;
+ ptr += sizeof(int32);
auto msg = (Char*)ptr;
- ptr += length * 2;
+ ptr += length * sizeof(Char);
- auto msgObj = MUtils::ToString(StringView(msg, length));
+ auto msgObj = String(msg, length);
- MCore::GC::WriteArrayRef(*outMessages, (MObject*)msgObj, count);
+ String& str = messages[count];
+ ASSERT(str.Get() == nullptr && str.Length() == 0);
+ str = msgObj;
outLogTypesPtr[count] = type;
outLogTimesPtr[count] = time;
@@ -147,9 +150,9 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_SetPlayMode(bool value)
Editor::IsPlayMode = value;
}
-DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetProjectPath()
+DEFINE_INTERNAL_CALL(void) EditorInternal_GetProjectPath(StringView* projectPath)
{
- return MUtils::ToString(Editor::Project->ProjectPath);
+ *projectPath = Editor::Project->ProjectPath;
}
DEFINE_INTERNAL_CALL(void) EditorInternal_CloseSplashScreen()
@@ -159,6 +162,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_CloseSplashScreen()
DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MString* dstPathObj, MString* srcPathObj, Guid* dstId)
{
+ PLATFORM_DEBUG_BREAK;
// Get normalized paths
String dstPath, srcPath;
MUtils::ToString(dstPathObj, dstPath);
@@ -172,6 +176,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MString* dstPathObj, MS
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPathObj, MString* baseTypenameObj)
{
+ PLATFORM_DEBUG_BREAK;
String outputPath;
MUtils::ToString(outputPathObj, outputPath);
FileSystem::NormalizePath(outputPath);
@@ -182,6 +187,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPath
DEFINE_INTERNAL_CALL(MString*) EditorInternal_CanImport(MString* extensionObj)
{
+ PLATFORM_DEBUG_BREAK;
String extension;
MUtils::ToString(extensionObj, extension);
if (extension.Length() > 0 && extension[0] == '.')
@@ -199,6 +205,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_GetAudioClipMetadata(AudioClip* clip,
DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MString* outputPathObj, MString* dataObj, MString* dataTypeNameObj)
{
+ PLATFORM_DEBUG_BREAK;
String outputPath;
MUtils::ToString(outputPathObj, outputPath);
FileSystem::NormalizePath(outputPath);
@@ -216,6 +223,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MString* outputPathObj,
DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MString* pathObj)
{
+ PLATFORM_DEBUG_BREAK;
#if COMPILE_WITH_ASSETS_EXPORTER
String path;
MUtils::ToString(pathObj, path);
@@ -229,6 +237,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MString* pathObj)
DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MString* inputPathObj, MString* outputFolderObj)
{
+ PLATFORM_DEBUG_BREAK;
#if COMPILE_WITH_ASSETS_EXPORTER
String inputPath;
MUtils::ToString(inputPathObj, inputPath);
@@ -246,6 +255,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MString* inputPathObj, MString*
DEFINE_INTERNAL_CALL(void) EditorInternal_CopyCache(Guid* dstId, Guid* srcId)
{
+ PLATFORM_DEBUG_BREAK;
ShaderCacheManager::CopyCache(*dstId, *srcId);
}
@@ -260,6 +270,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_BakeLightmaps(bool cancel)
DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetShaderAssetSourceCode(BinaryAsset* obj)
{
+ PLATFORM_DEBUG_BREAK;
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
if (obj->WaitForLoaded())
DebugLog::ThrowNullReference();
@@ -287,6 +298,7 @@ DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetShaderAssetSourceCode(BinaryAss
DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
{
+ PLATFORM_DEBUG_BREAK;
#if COMPILE_WITH_PHYSICS_COOKING
CollisionCooking::Argument arg;
String path;
@@ -307,6 +319,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MString* pathObj, Co
DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* collisionData, MArray** triangles, MArray** indices, int* trianglesCount, int* indicesCount)
{
+ PLATFORM_DEBUG_BREAK;
if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None)
return;
@@ -332,6 +345,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* colli
DEFINE_INTERNAL_CALL(void) EditorInternal_GetEditorBoxWithChildren(Actor* obj, BoundingBox* result)
{
+ PLATFORM_DEBUG_BREAK;
INTERNAL_CALL_CHECK(obj);
*result = obj->GetEditorBoxChildren();
}
@@ -461,6 +475,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
DEFINE_INTERNAL_CALL(void) EditorInternal_DeserializeSceneObject(SceneObject* sceneObject, MString* jsonObj)
{
+ PLATFORM_DEBUG_BREAK;
PROFILE_CPU_NAMED("DeserializeSceneObject");
StringAnsi json;
@@ -531,10 +546,9 @@ DEFINE_INTERNAL_CALL(MTypeObject*) CustomEditorsUtilInternal_GetCustomEditor(MTy
return CustomEditorsUtil::GetCustomEditor(targetType);
}
-DEFINE_INTERNAL_CALL(MArray*) LayersAndTagsSettingsInternal_GetCurrentLayers(int* layersCount)
+DEFINE_INTERNAL_CALL(NativeSpan) LayersAndTagsSettingsInternal_GetCurrentLayers()
{
- *layersCount = Math::Max(1, Level::GetNonEmptyLayerNamesCount());
- return MUtils::ToArray(Span(Level::Layers, *layersCount));
+ return NativeSpan::AsSpan(Level::Layers, Math::Max(1, Level::GetNonEmptyLayerNamesCount()));
}
DEFINE_INTERNAL_CALL(void) GameSettingsInternal_Apply()
diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs
index 52555f564..982970057 100644
--- a/Source/Editor/Windows/OutputLogWindow.cs
+++ b/Source/Editor/Windows/OutputLogWindow.cs
@@ -878,7 +878,7 @@ namespace FlaxEditor.Windows
Message = _outMessages[i],
};
_entries.Add(entry);
- _outMessages[i] = null;
+ _outMessages[i] = null; // Prevent passing old strings back to native side
_isDirty = true;
}
} while (logCount != 0);
diff --git a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
index c127e86f3..cdbdb2ef1 100644
--- a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
+++ b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
@@ -47,6 +47,7 @@ static_assert(sizeof(InternalImpulse) == sizeof(AnimGraphImpulse), "Please updat
DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* context, int32 boxId)
{
+ PLATFORM_DEBUG_BREAK;
const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -55,6 +56,7 @@ DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* cont
DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext* context, int32 boxId)
{
+ PLATFORM_DEBUG_BREAK;
const auto box = context->Node->TryGetBox(boxId);
if (box == nullptr)
DebugLog::ThrowArgumentOutOfRange("boxId");
@@ -72,6 +74,7 @@ DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext*
DEFINE_INTERNAL_CALL(AnimGraphImpulse*) AnimGraphInternal_GetOutputImpulseData(InternalContext* context)
{
+ PLATFORM_DEBUG_BREAK;
const auto nodes = context->Node->GetNodes(context->GraphExecutor);
context->GraphExecutor->InitNodes(nodes);
return nodes;
diff --git a/Source/Engine/Core/Config/LayersAndTagsSettings.cs b/Source/Engine/Core/Config/LayersAndTagsSettings.cs
index 650b53268..3832a4886 100644
--- a/Source/Engine/Core/Config/LayersAndTagsSettings.cs
+++ b/Source/Engine/Core/Config/LayersAndTagsSettings.cs
@@ -27,7 +27,7 @@ namespace FlaxEditor.Content.Settings
/// The layers.
public static string[] GetCurrentLayers()
{
- return GetCurrentLayers(out int _);
+ return Internal_GetCurrentLayers();
}
///
@@ -56,7 +56,7 @@ namespace FlaxEditor.Content.Settings
}
[LibraryImport("FlaxEngine", EntryPoint = "LayersAndTagsSettingsInternal_GetCurrentLayers", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
- [return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "layerCount")]
- internal static partial string[] GetCurrentLayers(out int layerCount);
+ [return: MarshalUsing(typeof(FlaxEngine.Interop.NativeSpanMarshaller), ConstantElementCount = FlaxEngine.Interop.MarshallerFlags.SkipDisposeElements)]
+ internal static partial string[] Internal_GetCurrentLayers();
}
}
diff --git a/Source/Engine/Engine/NativeInterop.Invoker.cs b/Source/Engine/Engine/NativeInterop.Invoker.cs
index 8c3cd4f6f..fa95d7781 100644
--- a/Source/Engine/Engine/NativeInterop.Invoker.cs
+++ b/Source/Engine/Engine/NativeInterop.Invoker.cs
@@ -183,11 +183,11 @@ namespace FlaxEngine.Interop
if (returnType == typeof(string))
return ManagedString.ToNative/*Weak*/(Unsafe.As(returnObject));
if (returnType == typeof(IntPtr))
- return (IntPtr)(object)returnObject;
+ return (IntPtr)returnObject;
if (returnType == typeof(ManagedHandle))
- return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
+ return ManagedHandle.ToIntPtr((ManagedHandle)returnObject);
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
- return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As(returnObject))) : IntPtr.Zero;
+ return ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As(returnObject)));
if (returnType.IsArray)
{
var elementType = returnType.GetElementType();
diff --git a/Source/Engine/Engine/NativeInterop.Managed.cs b/Source/Engine/Engine/NativeInterop.Managed.cs
index 32de5dd6b..8fa64a6c1 100644
--- a/Source/Engine/Engine/NativeInterop.Managed.cs
+++ b/Source/Engine/Engine/NativeInterop.Managed.cs
@@ -1,5 +1,5 @@
// Copyright (c) Wojciech Figat. All rights reserved.
-
+#pragma warning disable CS0162
#define USE_CONCURRENT_DICT
#define USE_GCHANDLE
//#define TRACK_HANDLES
@@ -311,20 +311,24 @@ namespace FlaxEngine.Interop
{
internal static ManagedHandle EmptyStringHandle = ManagedHandle.Alloc(string.Empty);
- [System.Diagnostics.DebuggerStepThrough]
+ //[System.Diagnostics.DebuggerStepThrough]
public static unsafe IntPtr ToNative(string str)
{
if (str == null)
return IntPtr.Zero;
- else if (str == string.Empty)
- return ManagedHandle.ToIntPtr(EmptyStringHandle);
- Assert.IsTrue(str.Length > 0);
- return ManagedHandle.ToIntPtr(str);
+ //else if (str == string.Empty)
+ // return ManagedHandle.ToIntPtr(EmptyStringHandle);
+ //return ManagedHandle.ToIntPtr(str);
+
+ NativeString* nativeString = (NativeString*)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf(), 16);
+ *nativeString = new NativeString(str);
+ return (IntPtr)nativeString;
}
- [System.Diagnostics.DebuggerStepThrough]
+ //[System.Diagnostics.DebuggerStepThrough]
public static unsafe IntPtr ToNativeWeak(string str)
{
+ throw new Exception("not used");
if (str == null)
return IntPtr.Zero;
else if (str == string.Empty)
@@ -333,28 +337,39 @@ namespace FlaxEngine.Interop
return ManagedHandle.ToIntPtr(str, GCHandleType.Weak);
}
- [System.Diagnostics.DebuggerStepThrough]
- public static string ToManaged(IntPtr ptr)
+ //[System.Diagnostics.DebuggerStepThrough]
+ public static unsafe string ToManaged(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return null;
- return Unsafe.As(ManagedHandle.FromIntPtr(ptr).Target);
+ //return Unsafe.As(ManagedHandle.FromIntPtr(ptr).Target);
+ NativeString* str = (NativeString*)ptr.ToPointer();
+ return str->ToString();
}
- [System.Diagnostics.DebuggerStepThrough]
- public static void Free(IntPtr ptr)
+ //[System.Diagnostics.DebuggerStepThrough]
+ public static unsafe void Free(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return;
- ManagedHandle handle = ManagedHandle.FromIntPtr(ptr);
- if (handle == EmptyStringHandle)
- return;
- handle.Free();
+ //ManagedHandle handle = ManagedHandle.FromIntPtr(ptr);
+ //if (handle == EmptyStringHandle)
+ // return;
+ //handle.Free();
+ Free((NativeString*)ptr.ToPointer());
+ }
+
+ //[System.Diagnostics.DebuggerStepThrough]
+ public static unsafe void Free(NativeString* str)
+ {
+ if (str->Data != null)
+ NativeMemory.AlignedFree(str->Data);
}
[System.Diagnostics.DebuggerStepThrough]
public static void Free(ManagedHandle handle)
{
+ throw new Exception("not used");
if (handle == EmptyStringHandle)
return;
handle.Free();
@@ -537,7 +552,8 @@ namespace FlaxEngine.Interop
internal static class ManagedHandlePool
{
[ThreadStatic]
- private static List<(bool InUse, ManagedHandle Handle)> _pool;
+ private static List<(bool InUse, ManagedHandle Handle)> __poolField;
+ private static List<(bool InUse, ManagedHandle Handle)> _pool => __poolField ??= [];
internal static void TryCollectWeakHandles(bool force = false)
{
diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs
index d0f69bf82..c0048d322 100644
--- a/Source/Engine/Engine/NativeInterop.Marshallers.cs
+++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs
@@ -3,6 +3,7 @@
#if USE_NETCORE
using FlaxEngine.Assertions;
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
@@ -755,9 +756,8 @@ namespace FlaxEngine.Interop
public static void Free(NativeArray unmanaged)
{
- if (unmanaged.Data == null)
- return;
- Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
+ if (unmanaged.Data != null)
+ unmanaged.Free();
}
public static NativeArray AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
@@ -852,6 +852,44 @@ namespace FlaxEngine.Interop
}
}
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe /*ref*/ struct NativeArrayTypeless
+ {
+ public void* Data;
+ public int Length;
+
+ public NativeArrayTypeless(IntPtr data, int length)
+ {
+ Data = (void*)data;
+ Length = length;
+ }
+
+ public NativeArrayTypeless(void* data, int length)
+ {
+ Data = data;
+ Length = length;
+ }
+
+ public static bool operator ==(NativeArrayTypeless left, NativeArrayTypeless right) => left.Data == right.Data && left.Length == right.Length;
+ public static bool operator !=(NativeArrayTypeless left, NativeArrayTypeless right) => left.Data != right.Data || left.Length != right.Length;
+ public static bool operator ==(NativeArrayTypeless left, IntPtr right) => left.Data == (void*)right;
+ public static bool operator !=(NativeArrayTypeless left, IntPtr right) => left.Data != (void*)right;
+ public static bool operator ==(IntPtr left, NativeArrayTypeless right) => (void*)left == right.Data;
+ public static bool operator !=(IntPtr left, NativeArrayTypeless right) => (void*)left != right.Data;
+
+ public void Free() => NativeMemory.AlignedFree(Data);
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (obj is NativeArrayTypeless arr) return this == arr;
+ if (obj is IntPtr ptr) return this == ptr;
+ return false;
+ }
+
+ public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();
+ }
+
[StructLayout(LayoutKind.Sequential)]
public unsafe /*ref*/ struct NativeArray where T : unmanaged
{
@@ -866,7 +904,7 @@ namespace FlaxEngine.Interop
public NativeArray(Span data)
{
- Data = (T*)Marshal.AllocCoTaskMem(data.Length);
+ Data = (T*)NativeMemory.AlignedAlloc((UIntPtr)(data.Length * Unsafe.SizeOf()), 16);
Length = data.Length;
for (int i = 0; i < data.Length; i++)
@@ -881,8 +919,15 @@ namespace FlaxEngine.Interop
public NativeArray(int length)
{
- Data = (T*)Marshal.AllocCoTaskMem(length);
+ Data = (T*)NativeMemory.AlignedAlloc((UIntPtr)(length * Unsafe.SizeOf()), 16);
Length = length;
+
+ /*var span = new Span(Data, Length);
+ foreach (ref var item in span)
+ item = new IntPtr(12345);
+
+ Free();
+ Data = (T*)NativeMemory.AlignedAlloc((UIntPtr)length, 16);*/
}
public NativeArray()
@@ -891,7 +936,7 @@ namespace FlaxEngine.Interop
Length = 0;
}
- public void Free() => Marshal.FreeCoTaskMem((IntPtr)Data);
+ public void Free() => NativeMemory.AlignedFree(Data);
public Span AsSpan() => new Span(Data, Length);
public ReadOnlySpan AsReadOnlySpan() => new Span(Data, Length);
@@ -914,40 +959,137 @@ namespace FlaxEngine.Interop
public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();
}
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe /*ref*/ struct NativeSpan where T : unmanaged
+ {
+ public T* Data;
+ public int Length;
+
+ public NativeSpan(T* data, int length)
+ {
+ Data = data;
+ Length = length;
+ }
+
+ public NativeSpan(Span data)
+ {
+ Data = (T*)NativeMemory.AlignedAlloc((UIntPtr)(data.Length * Unsafe.SizeOf()), 16);
+ Length = data.Length;
+
+ for (int i = 0; i < data.Length; i++)
+ Unsafe.Copy(&Data[i], ref data[i]);
+ }
+
+ public NativeSpan(IntPtr data, int length)
+ {
+ Data = (T*)data;
+ Length = length;
+ }
+
+ public NativeSpan(int length)
+ {
+ Data = (T*)NativeMemory.AlignedAlloc((UIntPtr)(length * Unsafe.SizeOf()), 16);
+ Length = length;
+
+ /*var span = new Span(Data, Length);
+ foreach (ref var item in span)
+ item = new IntPtr(12345);
+
+ Free();
+ Data = (T*)NativeMemory.AlignedAlloc((UIntPtr)length, 16);*/
+ }
+
+ public NativeSpan()
+ {
+ Data = null;
+ Length = 0;
+ }
+
+ public void Free() => NativeMemory.AlignedFree(Data);
+
+ public Span AsSpan() => new Span(Data, Length);
+ public ReadOnlySpan AsReadOnlySpan() => new Span(Data, Length);
+
+ public static bool operator ==(NativeSpan left, NativeSpan right) => left.Data == right.Data && left.Length == right.Length;
+ public static bool operator !=(NativeSpan left, NativeSpan right) => left.Data != right.Data || left.Length != right.Length;
+ public static bool operator ==(NativeSpan left, IntPtr right) => left.Data == (T*)right;
+ public static bool operator !=(NativeSpan left, IntPtr right) => left.Data != (T*)right;
+ public static bool operator ==(IntPtr left, NativeSpan right) => (T*)left == right.Data;
+ public static bool operator !=(IntPtr left, NativeSpan right) => (T*)left != right.Data;
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (obj is NativeSpan arr) return this == arr;
+ if (obj is IntPtr ptr) return this == ptr;
+ return false;
+ }
+
+ public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();
+ }
+
+ ///
+ /// The flags for custom marshaller passed via .
+ ///
#if FLAX_EDITOR
[HideInEditor]
#endif
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
- [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(NativeArrayMarshaller<,>))]
- [ContiguousCollectionMarshaller]
- public static unsafe class NativeArrayMarshaller where TUnmanagedElement : unmanaged
+ public static class MarshallerFlags
{
+ ///
+ /// The native resources of the elements should be released (caller is responsible for cleanup).
+ ///
+ public const int DisposeElements = 0;
+
+ ///
+ /// The native resources of the elements are not released (callee owns the resources).
+ ///
+ public const int SkipDisposeElements = 1;
+ }
+
+ ///
+ /// Custom marshaller for Span.
+ ///
+ ///
+ /// The marshaller behaviour can be controlled with passed via values.
+ /// The actual element count is read from the span itself, so the element count is assumed to be dynamic in all cases.
+ /// The managed type.
+ /// The unmanaged element type.
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(NativeSpanMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(NativeSpanMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(NativeSpanMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeSpanMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeSpanMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(NativeSpanMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(NativeSpanMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(NativeSpanMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(NativeSpanMarshaller<,>))]
+ [ContiguousCollectionMarshaller]
+ public static unsafe class NativeSpanMarshaller where TUnmanagedElement : unmanaged
+ {
+
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class ManagedToNative
{
- public static NativeArray AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
+ public static NativeSpan AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
- public static Span GetUnmanagedValuesDestination(NativeArray unmanaged, int numElements) => throw new NotImplementedException();
+ public static Span GetUnmanagedValuesDestination(NativeSpan unmanaged, int numElements) => throw new NotImplementedException();
- public static void Free(NativeArray unmanaged) => throw new NotImplementedException();
+ public static void Free(NativeSpan unmanaged) => throw new NotImplementedException();
- public static T[] AllocateContainerForManagedElements(NativeArray unmanaged, int numElements)
+ public static T[] AllocateContainerForManagedElements(NativeSpan unmanaged, int numElements)
{
throw new NotImplementedException();
}
- public static ReadOnlySpan GetUnmanagedValuesSource(NativeArray unmanaged, int numElements)
+ public static ReadOnlySpan GetUnmanagedValuesSource(NativeSpan unmanaged, int numElements)
{
throw new NotImplementedException();
}
@@ -963,7 +1105,183 @@ namespace FlaxEngine.Interop
#endif
public static class NativeToManaged
{
- public static T[] AllocateContainerForManagedElements(NativeArray unmanaged, int numElements)
+ public static T[] AllocateContainerForManagedElements(NativeSpan unmanaged, int marshallerFlags)
+ {
+ if (unmanaged.Data == null)
+ return Array.Empty();
+ return new T[unmanaged.Length];
+ }
+
+ public static ReadOnlySpan GetUnmanagedValuesSource(NativeSpan unmanaged, int marshallerFlags)
+ {
+ if (unmanaged.Data == null)
+ return null;
+ switch (marshallerFlags)
+ {
+ case MarshallerFlags.DisposeElements:
+ return unmanaged.AsReadOnlySpan();
+ case MarshallerFlags.SkipDisposeElements:
+ // Return an empty span to prevent element resources getting released.
+ return ReadOnlySpan.Empty;
+ default:
+ throw new NotSupportedException($"Unsupported value used in marshaller {nameof(MarshalUsingAttribute.ConstantElementCount)}: {marshallerFlags}.");
+ }
+ }
+
+ public static Span GetManagedValuesDestination(T[] managed)
+ {
+ if (managed == null)
+ return null;
+ return managed.AsSpan();
+ }
+
+ public static void Free(NativeSpan unmanaged)
+ {
+ // Span resources should not be freed
+ }
+
+ public static NativeSpan AllocateContainerForUnmanagedElements(T[] managed, out int marshallerFlags) => throw new NotImplementedException();
+
+ public static ReadOnlySpan GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
+
+ public static Span GetUnmanagedValuesDestination(NativeSpan unmanaged, int marshallerFlags) => throw new NotImplementedException();
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public struct Bidirectional
+ {
+ //string managed;
+ //IntPtr unmanaged;
+
+ public void FromManaged(T[] managed)
+ {
+ throw new NotImplementedException();
+ }
+
+ public T[] ToManaged()
+ {
+ throw new NotImplementedException();
+ }
+
+ public ReadOnlySpan GetManagedValuesSource()
+ {
+ throw new NotImplementedException();
+ }
+
+ public Span GetUnmanagedValuesDestination()
+ {
+ throw new NotImplementedException();
+ }
+
+ public ReadOnlySpan GetUnmanagedValuesSource(int marshallerFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Span GetManagedValuesDestination(int marshallerFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public NativeSpan ToUnmanaged()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void FromUnmanaged(NativeSpan unmanaged)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Free()
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static NativeSpan AllocateContainerForUnmanagedElements(T[] managed, out int marshallerFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static T[] AllocateContainerForManagedElements(NativeSpan unmanaged, int marshallerFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static ReadOnlySpan GetManagedValuesSource(T[] managed)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static Span GetUnmanagedValuesDestination(NativeSpan unmanaged, int marshallerFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static ReadOnlySpan GetUnmanagedValuesSource(NativeSpan unmanaged, int marshallerFlags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static Span GetManagedValuesDestination(T[] managed)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(NativeSpanConvertedMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(NativeSpanConvertedMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(NativeSpanConvertedMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeSpanConvertedMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeSpanConvertedMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(NativeSpanConvertedMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(NativeSpanConvertedMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(NativeSpanConvertedMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(NativeSpanConvertedMarshaller<,>))]
+ [ContiguousCollectionMarshaller]
+ public static unsafe class NativeSpanConvertedMarshaller where TUnmanagedElement : unmanaged
+ {
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public static class ManagedToNative
+ {
+ public static NativeSpan AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
+
+ public static ReadOnlySpan GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
+
+ public static Span GetUnmanagedValuesDestination(NativeSpan unmanaged, int numElements) => throw new NotImplementedException();
+
+ public static void Free(NativeSpan unmanaged) => throw new NotImplementedException();
+
+ public static T[] AllocateContainerForManagedElements(NativeSpan unmanaged, int numElements)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static ReadOnlySpan GetUnmanagedValuesSource(NativeSpan unmanaged, int numElements)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static Span GetManagedValuesDestination(T[] managed)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public static class NativeToManaged
+ {
+ public static T[] AllocateContainerForManagedElements(NativeSpan unmanaged, int numElements)
{
if (unmanaged.Data == null)
return Array.Empty();
@@ -971,7 +1289,7 @@ namespace FlaxEngine.Interop
return new T[unmanaged.Length];
}
- public static ReadOnlySpan GetUnmanagedValuesSource(NativeArray unmanaged, int numElements)
+ public static ReadOnlySpan GetUnmanagedValuesSource(NativeSpan unmanaged, int numElements)
{
if (unmanaged.Data == null)
return null;
@@ -985,18 +1303,17 @@ namespace FlaxEngine.Interop
return managed.AsSpan();
}
- public static void Free(NativeArray unmanaged)
+ public static void Free(NativeSpan unmanaged)
{
- if (unmanaged.Data == null)
- return;
- Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
+ if (unmanaged.Data != null)
+ unmanaged.Free();
}
- public static NativeArray AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
+ public static NativeSpan AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
public static ReadOnlySpan GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
- public static Span GetUnmanagedValuesDestination(NativeArray unmanaged, int numElements) => throw new NotImplementedException();
+ public static Span GetUnmanagedValuesDestination(NativeSpan unmanaged, int numElements) => throw new NotImplementedException();
}
#if FLAX_EDITOR
@@ -1037,12 +1354,12 @@ namespace FlaxEngine.Interop
throw new NotImplementedException();
}
- public NativeArray ToUnmanaged()
+ public NativeSpan ToUnmanaged()
{
throw new NotImplementedException();
}
- public void FromUnmanaged(NativeArray unmanaged)
+ public void FromUnmanaged(NativeSpan unmanaged)
{
throw new NotImplementedException();
}
@@ -1053,6 +1370,237 @@ namespace FlaxEngine.Interop
}
}
+ public static NativeSpan AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static T[] AllocateContainerForManagedElements(NativeSpan unmanaged, int numElements)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static ReadOnlySpan GetManagedValuesSource(T[] managed)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static Span GetUnmanagedValuesDestination(NativeSpan unmanaged, int numElements)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static ReadOnlySpan GetUnmanagedValuesSource(NativeSpan unmanaged, int numElements)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static Span GetManagedValuesDestination(T[] managed)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static unsafe class NativeArrayPool
+ {
+#if true
+ private static HashSet _tracked = new();
+
+ public static NativeArray Rent(int size) where T : unmanaged
+ {
+ var array = new NativeArray(size);
+ if (size != 0)
+ {
+ lock (_tracked)
+ _tracked.Add((IntPtr)array.Data);
+ }
+ return array;
+ }
+
+ public static void Return(NativeArray array) where T : unmanaged
+ {
+ if (array.Data != null)
+ {
+ lock (_tracked)
+ {
+ if (!_tracked.Remove((IntPtr)array.Data))
+ throw new Exception("Trying to return non-pooled NativeArray");
+ }
+ array.Free();
+ }
+ }
+#else
+ public static NativeArray Rent(int size) where T : unmanaged
+ {
+ var array = new NativeArray(size);
+ return array;
+ }
+
+ public static void Return(NativeArray array) where T : unmanaged
+ {
+ if (array.Data != null)
+ array.Free();
+ }
+#endif
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(NativeArrayMarshaller<,>.ManagedToNativeElement))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
+ [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(NativeArrayMarshaller<,>))]
+ [ContiguousCollectionMarshaller]
+ public static unsafe class NativeArrayMarshaller where TUnmanagedElement : unmanaged
+ {
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public ref struct ManagedToNative
+ {
+ T[] _managed;
+ NativeArray _array;
+
+ public void FromManaged(T[] managed)
+ {
+ _managed = managed;
+ _array = NativeArrayPool.Rent(managed.Length);
+ }
+
+ public NativeArray ToUnmanaged()
+ {
+ return _array;
+ }
+
+ public ReadOnlySpan GetManagedValuesSource()
+ {
+ return _managed.AsSpan();
+ }
+
+ public Span GetUnmanagedValuesDestination()
+ {
+ return _array.AsSpan();
+ }
+
+ public void Free()
+ {
+ NativeArrayPool.Return(_array);
+ }
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public static class ManagedToNativeElement
+ {
+ public static nint AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
+
+ public static T[] AllocateContainerForManagedElements(nint unmanaged, int numElements) => throw new NotImplementedException();
+
+ public static ReadOnlySpan GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
+
+ public static Span GetUnmanagedValuesDestination(nint unmanaged, int numElements) => throw new NotImplementedException();
+
+ public static ReadOnlySpan GetUnmanagedValuesSource(nint unmanaged, int numElements) => throw new NotImplementedException();
+
+ public static Span GetManagedValuesDestination(T[] managed) => throw new NotImplementedException();
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public static class NativeToManaged
+ {
+ public static T[] AllocateContainerForManagedElements(NativeArray unmanaged, int numElements)
+ {
+ if (unmanaged.Data == null)
+ return Array.Empty();
+ Assert.IsTrue(unmanaged.Length == numElements);
+ return new T[unmanaged.Length];
+ }
+
+ public static ReadOnlySpan GetUnmanagedValuesSource(NativeArray unmanaged, int numElements)
+ {
+ if (unmanaged.Data == null)
+ return null;
+ return unmanaged.AsReadOnlySpan();
+ }
+
+ public static Span GetManagedValuesDestination(T[] managed)
+ {
+ if (managed == null)
+ return null;
+ return managed.AsSpan();
+ }
+
+ public static void Free(NativeArray unmanaged)
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+
+ public static NativeArray AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
+
+ public static ReadOnlySpan GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
+
+ public static Span GetUnmanagedValuesDestination(NativeArray unmanaged, int numElements) => throw new NotImplementedException();
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public struct Bidirectional
+ {
+ T[] managed;
+ NativeArray unmanaged;
+
+ public void FromManaged(T[] managed)
+ {
+ this.managed = managed;
+ if (managed.Length > 0)
+ {
+ this.unmanaged = new NativeArray(managed.Length);
+ }
+ }
+
+ public ReadOnlySpan GetManagedValuesSource() => new ReadOnlySpan(managed);
+
+ public Span GetUnmanagedValuesDestination() => unmanaged.AsSpan();
+
+ public NativeArray ToUnmanaged()
+ {
+ return unmanaged;
+ }
+
+ public void FromUnmanaged(NativeArray unmanaged)
+ {
+ if (unmanaged.Length > 0)
+ {
+ this.managed = new T[unmanaged.Length];
+ }
+ else
+ this.managed = null;
+ }
+
+ public ReadOnlySpan GetUnmanagedValuesSource(int numElements) => unmanaged.AsReadOnlySpan();
+
+ public Span GetManagedValuesDestination(int numElements) => managed.AsSpan();
+
+ public T[] ToManaged() => managed;
+
+ public void Free()
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+ }
+
public static NativeArray AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
{
throw new NotImplementedException();
@@ -1084,78 +1632,417 @@ namespace FlaxEngine.Interop
}
}
+ ///
+ /// Represents the native UTF-16 string type.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct NativeString
+ {
+ public char* Data;
+ public int Length;
+
+ public NativeString(string str)
+ {
+ if (str == null || str.Length == 0)
+ {
+ Data = null;
+ Length = 0;
+ }
+ else
+ {
+ Length = str.Length;
+ Data = (char*)NativeMemory.AlignedAlloc(((UIntPtr)Length + 1) * sizeof(char), 16);
+ str.CopyTo(new Span(Data, Length));
+ Data[Length] = (char)0;
+ }
+ }
+
+ public NativeString()
+ {
+ Data = null;
+ Length = 0;
+ }
+
+ public void Free() => NativeMemory.AlignedFree(Data);
+
+ public Span AsSpan() => new Span(Data, Length);
+ public ReadOnlySpan AsReadOnlySpan() => new ReadOnlySpan(Data, Length);
+ public override string ToString()
+ {
+ //if (Data == null)
+ // return null;
+ if (Length == 0)
+ return string.Empty;
+ return new string(AsSpan());
+ }
+
+ /*public static bool operator ==(NativeArray left, NativeArray right) => left.Data == right.Data && left.Length == right.Length;
+ public static bool operator !=(NativeArray left, NativeArray right) => left.Data != right.Data || left.Length != right.Length;
+ public static bool operator ==(NativeArray left, IntPtr right) => left.Data == (T*)right;
+ public static bool operator !=(NativeArray left, IntPtr right) => left.Data != (T*)right;
+ public static bool operator ==(IntPtr left, NativeArray right) => (T*)left == right.Data;
+ public static bool operator !=(IntPtr left, NativeArray right) => (T*)left != right.Data;
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (obj is NativeArray arr) return this == arr;
+ if (obj is IntPtr ptr) return this == ptr;
+ return false;
+ }
+
+ public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();*/
+ }
+
+ ///
+ /// Represents the native ANSI string type.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct NativeStringAnsi
+ {
+ public byte* Data;
+ public int Length;
+
+ public NativeStringAnsi(string str)
+ {
+ if (str == null || str.Length == 0)
+ {
+ Data = null;
+ Length = 0;
+ }
+ else
+ {
+ Length = System.Text.Encoding.ASCII.GetByteCount(str);
+ Data = (byte*)NativeMemory.AlignedAlloc(((UIntPtr)Length + 1) * sizeof(byte), 16);
+ var span = new Span(Data, Length);
+ int ret = System.Text.Encoding.ASCII.GetBytes(str.AsSpan(), span);
+ //str.CopyTo(new Span(Data, Length));
+ Data[Length] = (byte)0;
+ }
+ }
+
+ public NativeStringAnsi()
+ {
+ Data = null;
+ Length = 0;
+ }
+
+ public void Free() => NativeMemory.AlignedFree(Data);
+
+ public Span AsSpan() => new Span(Data, Length);
+ public ReadOnlySpan AsReadOnlySpan() => new ReadOnlySpan(Data, Length);
+ public override string ToString()
+ {
+ //if (Data == null)
+ // return null;
+ if (Length == 0)
+ return string.Empty;
+ return System.Text.Encoding.ASCII.GetString(AsReadOnlySpan());
+ }
+
+ /*public static bool operator ==(NativeArray left, NativeArray right) => left.Data == right.Data && left.Length == right.Length;
+ public static bool operator !=(NativeArray left, NativeArray right) => left.Data != right.Data || left.Length != right.Length;
+ public static bool operator ==(NativeArray left, IntPtr right) => left.Data == (T*)right;
+ public static bool operator !=(NativeArray left, IntPtr right) => left.Data != (T*)right;
+ public static bool operator ==(IntPtr left, NativeArray right) => (T*)left == right.Data;
+ public static bool operator !=(IntPtr left, NativeArray right) => (T*)left != right.Data;
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (obj is NativeArray arr) return this == arr;
+ if (obj is IntPtr ptr) return this == ptr;
+ return false;
+ }
+
+ public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();*/
+ }
+
+ ///
+ /// A custom marshaller for native strings.
+ ///
#if FLAX_EDITOR
[HideInEditor]
#endif
- [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(StringMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(StringMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringMarshaller.ManagedToNative))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(StringMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(StringMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringMarshaller))]
[CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(StringMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedIn, typeof(StringMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(string), MarshalMode.ElementOut, typeof(StringMarshaller.NativeToManaged))]
[CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedRef, typeof(StringMarshaller.Bidirectional))]
[CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedRef, typeof(StringMarshaller.Bidirectional))]
[CustomMarshaller(typeof(string), MarshalMode.ElementRef, typeof(StringMarshaller))]
- public static class StringMarshaller
+ public static unsafe class StringMarshaller
{
#if FLAX_EDITOR
[HideInEditor]
#endif
public static class NativeToManaged
{
- public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
- public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed/*, GCHandleType.Weak*/);
- public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
- }
-
-#if FLAX_EDITOR
- [HideInEditor]
-#endif
- public static class ManagedToNative
- {
- public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
- public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed/*, GCHandleType.Weak*/);
-
- public static void Free(IntPtr unmanaged)
+ public static string ConvertToManaged(NativeString unmanaged) => unmanaged.ToString();
+ public static NativeString ConvertToUnmanaged(string managed) => new NativeString(managed);
+ public static void Free(NativeString unmanaged)
{
- ManagedString.Free(unmanaged); // No need to free weak handles
+ // Skip native owned strings (passed as value)
+ if (unmanaged.Data != null)
+ unmanaged.Free();
}
}
-#if FLAX_EDITOR
- [HideInEditor]
-#endif
public struct Bidirectional
{
string managed;
- IntPtr unmanaged;
+ NativeString unmanaged;
public void FromManaged(string managed) => this.managed = managed;
- public IntPtr ToUnmanaged()
+ public NativeString ToUnmanaged()
{
- unmanaged = ManagedString.ToNative(managed);
- return unmanaged;
+ return unmanaged = new NativeString(managed);
}
- public void FromUnmanaged(IntPtr unmanaged) => this.unmanaged = unmanaged;
+ public void FromUnmanaged(NativeString unmanaged) => this.unmanaged = unmanaged;
public string ToManaged()
{
- managed = ManagedString.ToManaged(unmanaged);
- unmanaged = IntPtr.Zero;
- return managed;
+ return managed = unmanaged.ToString();
}
- public void Free() => ManagedString.Free(unmanaged);
+ public void Free()
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
}
- public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
- public static IntPtr ConvertToUnmanaged(string managed) => ManagedString.ToNative(managed);
- public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
+ public static string ConvertToManaged(NativeString unmanaged) => unmanaged.ToString();
+ public static NativeString ConvertToUnmanaged(string managed) => new NativeString(managed);
+ public static void Free(NativeString unmanaged)
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
- public static string ToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
- public static IntPtr ToNative(string managed) => ManagedString.ToNative(managed);
+ public static string ToManaged(NativeString unmanaged) => ConvertToManaged(unmanaged);
+ public static NativeString ToNative(string managed) => ConvertToUnmanaged(managed);
+ }
+
+ ///
+ /// A custom marshaller for native strings owned by native side.
+ ///
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(StringViewMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(StringViewMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringViewMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(StringViewMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedIn, typeof(StringViewMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementOut, typeof(StringViewMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedRef, typeof(StringViewMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedRef, typeof(StringViewMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementRef, typeof(StringViewMarshaller))]
+ public static unsafe class StringViewMarshaller
+ {
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public static class NativeToManaged
+ {
+ public static string ConvertToManaged(NativeString unmanaged) => unmanaged.ToString();
+ public static NativeString ConvertToUnmanaged(string managed) => new NativeString(managed);
+ public static void Free(NativeString unmanaged)
+ {
+ // Skip native owned strings
+ }
+ }
+
+ public struct Bidirectional
+ {
+ string managed;
+ NativeString unmanaged;
+
+ public void FromManaged(string managed) => this.managed = managed;
+
+ public NativeString ToUnmanaged()
+ {
+ return unmanaged = new NativeString(managed);
+ }
+
+ public void FromUnmanaged(NativeString unmanaged) => this.unmanaged = unmanaged;
+
+ public string ToManaged()
+ {
+ return managed = unmanaged.ToString();
+ }
+
+ public void Free()
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+ }
+
+ public static string ConvertToManaged(NativeString unmanaged) => unmanaged.ToString();
+ public static NativeString ConvertToUnmanaged(string managed) => new NativeString(managed);
+ public static void Free(NativeString unmanaged)
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+
+ public static string ToManaged(NativeString unmanaged) => ConvertToManaged(unmanaged);
+ public static NativeString ToNative(string managed) => ConvertToUnmanaged(managed);
+ }
+
+ ///
+ /// A custom marshaller for native strings.
+ ///
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(StringAnsiMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(StringAnsiMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringAnsiMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(StringAnsiMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedIn, typeof(StringAnsiMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementOut, typeof(StringAnsiMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedRef, typeof(StringAnsiMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedRef, typeof(StringAnsiMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementRef, typeof(StringAnsiMarshaller))]
+ public static unsafe class StringAnsiMarshaller
+ {
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public static class NativeToManaged
+ {
+ public static string ConvertToManaged(NativeStringAnsi unmanaged) => unmanaged.ToString();
+ public static NativeStringAnsi ConvertToUnmanaged(string managed) => new NativeStringAnsi(managed);
+ public static void Free(NativeStringAnsi unmanaged)
+ {
+ // Skip native owned strings (passed as value)
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+ }
+
+ public struct Bidirectional
+ {
+ string managed;
+ NativeStringAnsi unmanaged;
+
+ public void FromManaged(string managed) => this.managed = managed;
+
+ public NativeStringAnsi ToUnmanaged()
+ {
+ return unmanaged = new NativeStringAnsi(managed);
+ }
+
+ public void FromUnmanaged(NativeStringAnsi unmanaged) => this.unmanaged = unmanaged;
+
+ public string ToManaged()
+ {
+ return managed = unmanaged.ToString();
+ }
+
+ public void Free()
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+ }
+
+ public static string ConvertToManaged(NativeStringAnsi unmanaged) => unmanaged.ToString();
+ public static NativeStringAnsi ConvertToUnmanaged(string managed) => new NativeStringAnsi(managed);
+ public static void Free(NativeStringAnsi unmanaged)
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+
+ public static string ToManaged(NativeStringAnsi unmanaged) => ConvertToManaged(unmanaged);
+ public static NativeStringAnsi ToNative(string managed) => ConvertToUnmanaged(managed);
+ }
+
+ ///
+ /// A custom marshaller for native strings owned by native side.
+ ///
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedIn, typeof(StringAnsiViewMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedOut, typeof(StringAnsiViewMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementIn, typeof(StringAnsiViewMarshaller))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(StringAnsiViewMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedIn, typeof(StringAnsiViewMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementOut, typeof(StringAnsiViewMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedRef, typeof(StringAnsiViewMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.UnmanagedToManagedRef, typeof(StringAnsiViewMarshaller.Bidirectional))]
+ [CustomMarshaller(typeof(string), MarshalMode.ElementRef, typeof(StringAnsiViewMarshaller))]
+ public static unsafe class StringAnsiViewMarshaller
+ {
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ public static class NativeToManaged
+ {
+ public static string ConvertToManaged(NativeStringAnsi unmanaged) => unmanaged.ToString();
+ public static NativeStringAnsi ConvertToUnmanaged(string managed) => new NativeStringAnsi(managed);
+ public static void Free(NativeStringAnsi unmanaged)
+ {
+ // Skip native owned strings
+ }
+ }
+
+ public struct Bidirectional
+ {
+ string managed;
+ NativeStringAnsi unmanaged;
+
+ public void FromManaged(string managed) => this.managed = managed;
+
+ public NativeStringAnsi ToUnmanaged()
+ {
+ return unmanaged = new NativeStringAnsi(managed);
+ }
+
+ public void FromUnmanaged(NativeStringAnsi unmanaged) => this.unmanaged = unmanaged;
+
+ public string ToManaged()
+ {
+ return managed = unmanaged.ToString();
+ }
+
+ public void Free()
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+ }
+
+ public static string ConvertToManaged(NativeStringAnsi unmanaged) => unmanaged.ToString();
+ public static NativeStringAnsi ConvertToUnmanaged(string managed) => new NativeStringAnsi(managed);
+ public static void Free(NativeStringAnsi unmanaged)
+ {
+ if (unmanaged.Data != null)
+ unmanaged.Free();
+ }
+
+ public static string ToManaged(NativeStringAnsi unmanaged) => ConvertToManaged(unmanaged);
+ public static NativeStringAnsi ToNative(string managed) => ConvertToUnmanaged(managed);
+ }
+
+#if FLAX_EDITOR
+ [HideInEditor]
+#endif
+ [CustomMarshaller(typeof(bool), MarshalMode.Default, typeof(BooleanMarshaller))]
+ public static class BooleanMarshaller
+ {
+ public static bool ConvertToManaged(byte unmanaged) => unmanaged != 0;
+ public static byte ConvertToUnmanaged(bool managed) => (byte)(managed ? 1 : 0);
+ public static void Free(byte unmanaged) {}
}
}
diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs
index e33a29cf7..c2b28f90a 100644
--- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs
+++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs
@@ -527,34 +527,49 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
- internal static ManagedHandle NewArray(ManagedHandle typeHandle, long size)
+ internal static IntPtr NewArray(ManagedHandle typeHandle, long size)
{
Type elementType = Unsafe.As(typeHandle.Target);
Type marshalledType = ArrayFactory.GetMarshalledType(elementType);
Type arrayType = ArrayFactory.GetArrayType(elementType);
if (marshalledType.IsValueType)
{
- ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, arrayType, marshalledType);
- return ManagedHandle.Alloc(managedArray);
+ IntPtr arrayPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf(), 16);
+ IntPtr dataPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)(RuntimeHelpers.SizeOf(marshalledType.TypeHandle) * size), 16);
+ Unsafe.Write(arrayPtr.ToPointer(), dataPtr);
+ Unsafe.Write(IntPtr.Add(arrayPtr, Unsafe.SizeOf()).ToPointer(), size);
+
+ return arrayPtr;
+ //ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, arrayType, marshalledType);
+ //return ManagedHandle.Alloc(managedArray);
}
else
{
- Array arr = ArrayFactory.CreateArray(elementType, size);
+ /*Array arr = ArrayFactory.CreateArray(elementType, size);
ManagedArray managedArray = ManagedArray.WrapNewArray(arr, arrayType);
- return ManagedHandle.Alloc(managedArray);
+ return ManagedHandle.Alloc(managedArray);*/
+ IntPtr arrayPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf(), 16);
+ IntPtr dataPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)(Unsafe.SizeOf() * size), 16);
+ Unsafe.Write(arrayPtr.ToPointer(), dataPtr);
+ Unsafe.Write(IntPtr.Add(arrayPtr, Unsafe.SizeOf()).ToPointer(), size);
+
+ return arrayPtr;
}
}
[UnmanagedCallersOnly]
- internal static void FreeArray(ManagedHandle handle)
+ internal static void FreeArray(void* ptr)
{
- if (!handle.IsAllocated)
+ if (ptr == null)
return;
- ManagedArray managedArray = Unsafe.As(handle.Target);
+
+ NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
+ array->Free();
+ /*ManagedArray managedArray = Unsafe.As(handle.Target);
if (managedArray.ElementType.IsValueType)
managedArray.Free();
else
- managedArray.FreePooled();
+ managedArray.FreePooled();*/
}
[UnmanagedCallersOnly]
@@ -575,14 +590,15 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
- internal static IntPtr GetArrayPointer(ManagedHandle arrayHandle)
+ internal static IntPtr GetArrayPointer(void* ptr)
{
- if (!arrayHandle.IsAllocated)
+ if (ptr == null)
return IntPtr.Zero;
- ManagedArray managedArray = Unsafe.As(arrayHandle.Target);
- if (managedArray.Length == 0)
+ NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
+ if (array->Length == 0)
return IntPtr.Zero;
- return managedArray.Pointer;
+
+ return (IntPtr)array->Data;
}
[UnmanagedCallersOnly]
@@ -599,12 +615,16 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
- internal static int GetArrayLength(ManagedHandle arrayHandle)
+ internal static int GetArrayLength(void* ptr)
{
- if (!arrayHandle.IsAllocated)
- return 0;
- ManagedArray managedArray = Unsafe.As(arrayHandle.Target);
- return managedArray.Length;
+ //if (ptr == null)
+ // return 0;
+ NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
+ return array->Length;
+ /* if (!arrayHandle.IsAllocated)
+ return 0;
+ ManagedArray managedArray = Unsafe.As(arrayHandle.Target);
+ return managedArray.Length;*/
}
[UnmanagedCallersOnly]
@@ -626,9 +646,9 @@ namespace FlaxEngine.Interop
}
[UnmanagedCallersOnly]
- internal static void FreeString(ManagedHandle handle)
+ internal static void FreeString(NativeString* str)
{
- ManagedString.Free(handle);
+ ManagedString.Free(str);
}
[UnmanagedCallersOnly]
diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs
index 011b915b2..c4dfff571 100644
--- a/Source/Engine/Engine/NativeInterop.cs
+++ b/Source/Engine/Engine/NativeInterop.cs
@@ -198,8 +198,8 @@ namespace FlaxEngine.Interop
public static T[] GCHandleArrayToManagedArray(NativeArray ptrArray, T[] buffer = null) where T : class
{
ReadOnlySpan span = ptrArray.AsReadOnlySpan();
- if (buffer != null)
- buffer = buffer;
+ //if (buffer != null)
+ // buffer = buffer;
if (buffer == null || buffer.Length < ptrArray.Length)
buffer = new T[ptrArray.Length];
for (int i = 0; i < ptrArray.Length; i++)
@@ -426,7 +426,7 @@ namespace FlaxEngine.Interop
if (!toManagedMarshallers.TryGetValue(type, out var deleg))
deleg = toManagedMarshallers.GetOrAdd(type, Factory);
- return deleg(nativePtr, type.IsByRef);
+ return deleg(nativePtr, type.IsByRef && false);
}
internal static void MarshalToNative(object managedObject, IntPtr nativePtr, Type type)
@@ -552,6 +552,7 @@ namespace FlaxEngine.Interop
internal static int[] marshallableFieldOffsets;
internal static MarshalFieldTypedDelegate[] toManagedFieldMarshallers;
internal static MarshalFieldTypedDelegate[] toNativeFieldMarshallers;
+ private static int marshalledSize;
private static MarshalToNativeTypedDelegate toNativeTypedMarshaller;
private static MarshalToManagedTypedDelegate toManagedTypedMarshaller;
@@ -582,7 +583,36 @@ namespace FlaxEngine.Interop
MethodInfo toManagedFieldMethod;
MethodInfo toNativeFieldMethod;
- if (fieldType.IsPointer)
+ if (fieldType == typeof(string))
+ fieldType = fieldType;
+
+ if (fieldType == typeof(SoftTypeReference))
+ {
+ if (type.IsValueType)
+ {
+ toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToManagedFieldSoftTypeReferenceValueType), bindingFlags);
+ toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToNativeFieldSoftTypeReferenceValueType), bindingFlags);
+ }
+ else
+ {
+ toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToManagedFieldSoftTypeReferenceReferenceType), bindingFlags);
+ toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToNativeFieldSoftTypeReferenceReferenceType), bindingFlags);
+ }
+ }
+ else if (fieldType == typeof(string))
+ {
+ if (type.IsValueType)
+ {
+ toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToManagedFieldStringValueType), bindingFlags);
+ toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToNativeFieldStringValueType), bindingFlags);
+ }
+ else
+ {
+ toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToManagedFieldStringReferenceType), bindingFlags);
+ toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper.ToNativeFieldStringReferenceType), bindingFlags);
+ }
+ }
+ else if (fieldType.IsPointer)
{
if (type.IsValueType)
{
@@ -666,6 +696,15 @@ namespace FlaxEngine.Interop
}
}
+ /*if (marshallableFieldOffsets != null)
+ {
+ for (int i = 1; i < marshallableFieldOffsets.Length; i++)
+ {
+ if (marshallableFieldOffsets[i - 1] > marshallableFieldOffsets[i])
+ throw new NativeInteropException("marshal field offsets");
+ }
+ }*/
+
// Setup marshallers for managed and native directions
MethodInfo toManagedMethod;
if (type.IsValueType)
@@ -682,18 +721,31 @@ namespace FlaxEngine.Interop
//toManagedDelegate = toManagedMethod.CreateDelegate();//.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(type, toManagedMethod.GetParameters()[0].ParameterType));
string methodName = nameof(MarshalInternalHelper.ToManagedMarshaller);
toManagedMethod = typeof(MarshalInternalHelper<,>).MakeGenericType(types).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
+ marshalledSize = RuntimeHelpers.SizeOf(internalType.TypeHandle);
}
else
{
string methodName;
if (type == typeof(IntPtr))
+ {
methodName = nameof(MarshalHelperValueType.ToManagedPointer);
+ marshalledSize = Unsafe.SizeOf();
+ }
else if (type == typeof(ManagedHandle))
+ {
methodName = nameof(MarshalHelperValueType.ToManagedHandle);
+ marshalledSize = Unsafe.SizeOf();
+ }
else if (marshallableFields != null)
+ {
methodName = nameof(MarshalHelperValueType.ToManagedWithMarshallableFields);
+ marshalledSize = RuntimeHelpers.SizeOf(type.TypeHandle);
+ }
else
+ {
methodName = nameof(MarshalHelperValueType.ToManaged);
+ marshalledSize = RuntimeHelpers.SizeOf(type.TypeHandle);
+ }
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
}
}
@@ -707,10 +759,14 @@ namespace FlaxEngine.Interop
methodName = nameof(MarshalHelperValueType.ToManagedArray);
else
methodName = nameof(MarshalHelperValueType.ToManagedArrayMarshalled);
- toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type.GetElementType()).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
+ toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(elementType).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
+ marshalledSize = RuntimeHelpers.SizeOf(elementType.TypeHandle);
}
else
- toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(type.GetElementType()).GetMethod(nameof(MarshalHelperReferenceType.ToManagedArray), BindingFlags.Static | BindingFlags.NonPublic);
+ {
+ toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(elementType).GetMethod(nameof(MarshalHelperReferenceType.ToManagedArray), BindingFlags.Static | BindingFlags.NonPublic);
+ marshalledSize = Unsafe.SizeOf();
+ }
}
else
{
@@ -726,7 +782,10 @@ namespace FlaxEngine.Interop
else
throw new NativeInteropException($"Unsupported type '{type.FullName}'");
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
+ marshalledSize = Unsafe.SizeOf();
}
+ if (marshalledSize <= 0)
+ throw new NativeInteropException($"Missing marshalled size for type '{type.FullName}'");
toManagedTypedMarshaller = toManagedMethod.CreateDelegate();
MethodInfo toNativeMethod;
@@ -802,6 +861,18 @@ namespace FlaxEngine.Interop
return arr;
}
+ internal static Array ToManagedArray2(NativeArrayTypeless nativeArray)
+ {
+ T[] arr = new T[nativeArray.Length];
+ IntPtr nativePtr = (IntPtr)nativeArray.Data;
+ for (int i = 0; i < arr.Length; i++)
+ {
+ toManagedTypedMarshaller(ref arr[i], nativePtr, false);
+ nativePtr += marshalledSize;
+ }
+ return arr;
+ }
+
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
{
toNativeTypedMarshaller(ref managedValue, nativePtr);
@@ -871,6 +942,106 @@ namespace FlaxEngine.Interop
fieldSize = IntPtr.Size;
}
+ private static void ToManagedFieldStringValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
+ {
+ fieldSize = Unsafe.SizeOf();
+ NativeString nativeValue = Unsafe.Read(nativeFieldPtr.ToPointer());
+ string value = nativeValue.ToString();
+#if USE_AOT || DOTNET_HOST_MONO
+ FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
+#else
+ ref string fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner);
+ fieldValueRef = value;
+#endif
+ }
+
+ private static void ToManagedFieldStringReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
+ {
+ fieldSize = Unsafe.SizeOf();
+ NativeString nativeValue = Unsafe.Read(nativeFieldPtr.ToPointer());
+ string value = nativeValue.ToString();
+#if USE_AOT || DOTNET_HOST_MONO
+ FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
+#else
+ ref string fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner);
+ fieldValueRef = value;
+#endif
+ }
+
+ private static void ToNativeFieldStringValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
+ {
+ fieldSize = Unsafe.SizeOf();
+#if USE_AOT || DOTNET_HOST_MONO
+ string fieldValue = field.GetValue(fieldOwner);
+#else
+ string fieldValue = FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner);
+#endif
+ NativeString value = new NativeString(fieldValue);
+ Unsafe.Write(nativeFieldPtr.ToPointer(), value);
+ }
+
+ private static void ToNativeFieldStringReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
+ {
+ fieldSize = Unsafe.SizeOf();
+#if USE_AOT || DOTNET_HOST_MONO
+ string fieldValue = field.GetValue(fieldOwner);
+#else
+ string fieldValue = FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner);
+#endif
+ NativeString value = new NativeString(fieldValue);
+ Unsafe.Write(nativeFieldPtr.ToPointer(), value);
+ }
+
+ private static void ToManagedFieldSoftTypeReferenceValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
+ {
+ fieldSize = Unsafe.SizeOf();
+ NativeString nativeValue = Unsafe.Read(nativeFieldPtr.ToPointer());
+ SoftTypeReference value = new SoftTypeReference(nativeValue.ToString());
+#if USE_AOT || DOTNET_HOST_MONO
+ FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
+#else
+ ref SoftTypeReference fieldValueRef = ref FieldHelper.GetValueTypeFieldReference(fieldOffset, ref fieldOwner);
+ fieldValueRef = value;
+#endif
+ }
+
+ private static void ToManagedFieldSoftTypeReferenceReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
+ {
+ fieldSize = Unsafe.SizeOf();
+ NativeString nativeValue = Unsafe.Read(nativeFieldPtr.ToPointer());
+ SoftTypeReference value = new SoftTypeReference(nativeValue.ToString());
+#if USE_AOT || DOTNET_HOST_MONO
+ FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
+#else
+ ref SoftTypeReference fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference(fieldOffset, ref fieldOwner);
+ fieldValueRef = value;
+#endif
+ }
+
+ private static void ToNativeFieldSoftTypeReferenceValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
+ {
+ fieldSize = Unsafe.SizeOf