summaryrefslogtreecommitdiff
path: root/modules/mono/editor
diff options
context:
space:
mode:
authorIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2022-11-06 01:27:55 +0100
committerIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2022-11-25 03:14:10 +0100
commit3f645f980c5d7894f98075c29d1c65319be62be7 (patch)
treeefb9a10e4ad94b2e46c422633c299ae4b9f40e27 /modules/mono/editor
parentcdfef0c852d10cd14a275fffb8b3ad572b96074b (diff)
C#: Optimize Variant conversion callbacks
These callbacks are used for marshaling by callables and generic Godot collections. C# generics don't support specialization the way C++ templates do. I knew NativeAOT could optimize away many type checks when the types are known at compile time, but I didn't trust the JIT would do as good a job, so I initially went with cached function pointers. Well, it turns out the JIT is also very good at optimizing in this scenario, so I'm changing the methods to do the conversion directly, rather than returning a function pointer for the conversion. The methods were moved to `VariantUtils`, and were renamed from `GetFromVariantCallback/GetToVariantCallback` to `ConvertTo/CreateFrom`. The new implementation looks like it goes through many `if` checks at runtime to find the right branch for the type, but in practice it works pretty much like template specialization. The JIT only generates code for the relevant branch. Together with inlining, the result is very close or the same as doing the conversion manually: ```cs godot_variant variant; int foo = variant.Int; int bar = VariantUtils.ConvertTo<int>(variant); ``` If the type is a generic Godot collection, the conversion still goes through a function pointer call. The new code happens to be much shorter as well, with the file going from 1057 lines to 407. Side note: `Variant.cs` was mistakenly created in the wrong folder, so I moved it to the `Core` folder.
Diffstat (limited to 'modules/mono/editor')
-rw-r--r--modules/mono/editor/bindings_generator.cpp7
1 files changed, 3 insertions, 4 deletions
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index b90321b586..82b5f478e1 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -2274,7 +2274,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(");\n");
// Generate Callable trampoline for the delegate
- p_output << MEMBER_BEGIN "private static unsafe void " << p_isignal.proxy_name << "Trampoline"
+ p_output << MEMBER_BEGIN "private static void " << p_isignal.proxy_name << "Trampoline"
<< "(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)\n"
<< INDENT1 "{\n"
<< INDENT2 "Callable.ThrowIfArgCountMismatch(args, " << itos(p_isignal.arguments.size()) << ");\n"
@@ -2289,9 +2289,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output << ",";
}
- // TODO: We don't need to use VariantConversionCallbacks. We have the type information so we can use [cs_variant_to_managed] and [cs_managed_to_variant].
- p_output << "\n" INDENT3 "VariantConversionCallbacks.GetToManagedCallback<"
- << arg_type->cs_type << ">()(args[" << itos(idx) << "])";
+ p_output << sformat(arg_type->cs_variant_to_managed,
+ "args[" + itos(idx) + "]", arg_type->cs_type, arg_type->name);
idx++;
}