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 <raulsntos@gmail.com>
This commit is contained in:
Ignacio Roldán Etcheverry
2022-08-05 03:32:59 +02:00
parent 186d7f6239
commit 2c180f62d9
21 changed files with 1314 additions and 740 deletions

View File

@ -38,6 +38,7 @@
#include "core/os/thread.h"
#include "../csharp_script.h"
#include "../glue/runtime_interop.h"
#include "../godotsharp_dirs.h"
#include "../utils/path_utils.h"
#include "gd_mono_cache.h"
@ -294,9 +295,9 @@ load_assembly_and_get_function_pointer_fn initialize_hostfxr_self_contained(
#endif
#ifdef TOOLS_ENABLED
using godot_plugins_initialize_fn = bool (*)(void *, bool, gdmono::PluginCallbacks *, GDMonoCache::ManagedCallbacks *);
using godot_plugins_initialize_fn = bool (*)(void *, bool, gdmono::PluginCallbacks *, GDMonoCache::ManagedCallbacks *, const void **, int32_t);
#else
using godot_plugins_initialize_fn = bool (*)(void *, GDMonoCache::ManagedCallbacks *);
using godot_plugins_initialize_fn = bool (*)(void *, GDMonoCache::ManagedCallbacks *, const void **, int32_t);
#endif
#ifdef TOOLS_ENABLED
@ -443,7 +444,10 @@ void GDMono::initialize() {
ERR_FAIL_NULL(godot_plugins_initialize);
}
GDMonoCache::ManagedCallbacks managed_callbacks;
int32_t interop_funcs_size = 0;
const void **interop_funcs = godotsharp::get_runtime_interop_funcs(interop_funcs_size);
GDMonoCache::ManagedCallbacks managed_callbacks{};
void *godot_dll_handle = nullptr;
@ -456,12 +460,14 @@ void GDMono::initialize() {
gdmono::PluginCallbacks plugin_callbacks_res;
bool init_ok = godot_plugins_initialize(godot_dll_handle,
Engine::get_singleton()->is_editor_hint(),
&plugin_callbacks_res, &managed_callbacks);
&plugin_callbacks_res, &managed_callbacks,
interop_funcs, interop_funcs_size);
ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
plugin_callbacks = plugin_callbacks_res;
#else
bool init_ok = godot_plugins_initialize(godot_dll_handle, &managed_callbacks);
bool init_ok = godot_plugins_initialize(godot_dll_handle, &managed_callbacks,
interop_funcs, interop_funcs_size);
ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
#endif