From 2c180f62d985194060f1a8d2070c130081177c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etcheverry?= Date: Fri, 5 Aug 2022 03:32:59 +0200 Subject: C#: Replace P/Invoke with delegate pointers - Moves interop functions to UnmanagedCallbacks struct that contains the function pointers and is passed to C#. - Implements UnmanagedCallbacksGenerator, a C# source generator that generates the UnmanagedCallbacks struct in C# and the body for the NativeFuncs methods (their implementation just calls the function pointer in the UnmanagedCallbacks). The generated methods are needed because .NET pins byref parameters of native calls, even if they are 'ref struct's, which don't need pinning. The generated methods use `Unsafe.AsPointer` so that we can benefit from byref parameters without suffering overhead of pinning. Co-authored-by: Raul Santos --- modules/mono/editor/GodotTools/GodotTools.sln | 6 ++ .../GodotTools/GodotTools/GodotSharpEditor.cs | 3 +- .../editor/GodotTools/GodotTools/GodotTools.csproj | 1 + .../GodotTools/GodotTools/Internals/Internal.cs | 119 +++++++++++---------- 4 files changed, 69 insertions(+), 60 deletions(-) (limited to 'modules/mono/editor/GodotTools') diff --git a/modules/mono/editor/GodotTools/GodotTools.sln b/modules/mono/editor/GodotTools/GodotTools.sln index f3d2f90f39..564775635d 100644 --- a/modules/mono/editor/GodotTools/GodotTools.sln +++ b/modules/mono/editor/GodotTools/GodotTools.sln @@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.Shared", "GodotT EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators", "..\Godot.NET.Sdk\Godot.SourceGenerators\Godot.SourceGenerators.csproj", "{D8C421B2-8911-41EB-B983-F675C7141EB7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators.Internal", "..\..\glue\GodotSharp\Godot.SourceGenerators.Internal\Godot.SourceGenerators.Internal.csproj", "{55666071-BEC1-4A52-8A98-9A4A7A947DBF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -55,5 +57,9 @@ Global {D8C421B2-8911-41EB-B983-F675C7141EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU {D8C421B2-8911-41EB-B983-F675C7141EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU {D8C421B2-8911-41EB-B983-F675C7141EB7}.Release|Any CPU.Build.0 = Release|Any CPU + {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 45a29d89de..0aca60dad4 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -547,8 +547,9 @@ namespace GodotTools public static GodotSharpEditor Instance { get; private set; } [UsedImplicitly] - private static IntPtr InternalCreateInstance() + private static IntPtr InternalCreateInstance(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) { + Internal.Initialize(unmanagedCallbacks, unmanagedCallbacksSize); return new GodotSharpEditor().NativeInstance; } } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index f5734e6e69..30525ba04a 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -43,6 +43,7 @@ + diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs index f0d2bed246..e3fe1622d0 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs @@ -1,12 +1,16 @@ using System; -using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Godot; using Godot.NativeInterop; +using Godot.SourceGenerators.Internal; using GodotTools.IdeMessaging.Requests; namespace GodotTools.Internals { - internal static class Internal + [SuppressMessage("ReSharper", "InconsistentNaming")] + [GenerateUnmanagedCallbacks(typeof(InternalUnmanagedCallbacks))] + internal static partial class Internal { public const string CSharpLanguageType = "CSharpScript"; public const string CSharpLanguageExtension = ".cs"; @@ -64,97 +68,94 @@ namespace GodotTools.Internals #region Internal - private const string GodotDllName = "__Internal"; + private static bool initialized = false; - [DllImport(GodotDllName)] - public static extern void godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string r_dest); + // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global + internal static unsafe void Initialize(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) + { + if (initialized) + throw new InvalidOperationException("Already initialized"); + initialized = true; + + if (unmanagedCallbacksSize != sizeof(InternalUnmanagedCallbacks)) + throw new ArgumentException("Unmanaged callbacks size mismatch"); + + _unmanagedCallbacks = Unsafe.AsRef((void*)unmanagedCallbacks); + } + + private partial struct InternalUnmanagedCallbacks + { + } + + /* + * IMPORTANT: + * The order of the methods defined in NativeFuncs must match the order + * in the array defined at the bottom of 'editor/editor_internal_calls.cpp'. + */ + + public static partial void godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string r_dest); - [DllImport(GodotDllName)] - public static extern void godot_icall_GodotSharpDirs_MonoUserDir(out godot_string r_dest); + public static partial void godot_icall_GodotSharpDirs_MonoUserDir(out godot_string r_dest); - [DllImport(GodotDllName)] - public static extern void godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string r_dest); + public static partial void godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string r_dest); - [DllImport(GodotDllName)] - public static extern void godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string r_dest); + public static partial void godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string r_dest); - [DllImport(GodotDllName)] - public static extern void godot_icall_EditorProgress_Create(in godot_string task, in godot_string label, + public static partial void godot_icall_EditorProgress_Create(in godot_string task, in godot_string label, int amount, bool canCancel); - [DllImport(GodotDllName)] - public static extern void godot_icall_EditorProgress_Dispose(in godot_string task); + public static partial void godot_icall_EditorProgress_Dispose(in godot_string task); - [DllImport(GodotDllName)] - public static extern bool godot_icall_EditorProgress_Step(in godot_string task, in godot_string state, int step, + public static partial bool godot_icall_EditorProgress_Step(in godot_string task, in godot_string state, + int step, bool forceRefresh); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_FullExportTemplatesDir(out godot_string dest); + private static partial void godot_icall_Internal_FullExportTemplatesDir(out godot_string dest); - [DllImport(GodotDllName)] - private static extern bool godot_icall_Internal_IsMacOSAppBundleInstalled(in godot_string bundleId); + private static partial bool godot_icall_Internal_IsMacOSAppBundleInstalled(in godot_string bundleId); - [DllImport(GodotDllName)] - private static extern bool godot_icall_Internal_GodotIs32Bits(); + private static partial bool godot_icall_Internal_GodotIs32Bits(); - [DllImport(GodotDllName)] - private static extern bool godot_icall_Internal_GodotIsRealTDouble(); + private static partial bool godot_icall_Internal_GodotIsRealTDouble(); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_GodotMainIteration(); + private static partial void godot_icall_Internal_GodotMainIteration(); - [DllImport(GodotDllName)] - private static extern bool godot_icall_Internal_IsAssembliesReloadingNeeded(); + private static partial bool godot_icall_Internal_IsAssembliesReloadingNeeded(); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_ReloadAssemblies(bool softReload); + private static partial void godot_icall_Internal_ReloadAssemblies(bool softReload); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_EditorDebuggerNodeReloadScripts(); + private static partial void godot_icall_Internal_EditorDebuggerNodeReloadScripts(); - [DllImport(GodotDllName)] - private static extern bool godot_icall_Internal_ScriptEditorEdit(IntPtr resource, int line, int col, + private static partial bool godot_icall_Internal_ScriptEditorEdit(IntPtr resource, int line, int col, bool grabFocus); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_EditorNodeShowScriptScreen(); + private static partial void godot_icall_Internal_EditorNodeShowScriptScreen(); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_EditorRunPlay(); + private static partial void godot_icall_Internal_EditorRunPlay(); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_EditorRunStop(); + private static partial void godot_icall_Internal_EditorRunStop(); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts(); + private static partial void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts(); - [DllImport(GodotDllName)] - private static extern void godot_icall_Internal_CodeCompletionRequest(int kind, in godot_string scriptFile, + private static partial void godot_icall_Internal_CodeCompletionRequest(int kind, in godot_string scriptFile, out godot_packed_string_array res); - [DllImport(GodotDllName)] - public static extern float godot_icall_Globals_EditorScale(); + public static partial float godot_icall_Globals_EditorScale(); - [DllImport(GodotDllName)] - public static extern void godot_icall_Globals_GlobalDef(in godot_string setting, in godot_variant defaultValue, + public static partial void godot_icall_Globals_GlobalDef(in godot_string setting, in godot_variant defaultValue, bool restartIfChanged, out godot_variant result); - [DllImport(GodotDllName)] - public static extern void godot_icall_Globals_EditorDef(in godot_string setting, in godot_variant defaultValue, + public static partial void godot_icall_Globals_EditorDef(in godot_string setting, in godot_variant defaultValue, bool restartIfChanged, out godot_variant result); - [DllImport(GodotDllName)] - public static extern void godot_icall_Globals_EditorShortcut(in godot_string setting, out godot_variant result); + public static partial void + godot_icall_Globals_EditorShortcut(in godot_string setting, out godot_variant result); - [DllImport(GodotDllName)] - public static extern void godot_icall_Globals_TTR(in godot_string text, out godot_string dest); + public static partial void godot_icall_Globals_TTR(in godot_string text, out godot_string dest); - [DllImport(GodotDllName)] - public static extern void godot_icall_Utils_OS_GetPlatformName(out godot_string dest); + public static partial void godot_icall_Utils_OS_GetPlatformName(out godot_string dest); - [DllImport(GodotDllName)] - public static extern bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(in godot_string filePath); + public static partial bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(in godot_string filePath); #endregion } -- cgit v1.2.3