Skip to content

Commit

Permalink
x2 speed for set/get properties in C# API
Browse files Browse the repository at this point in the history
removed unnecessary includes
  • Loading branch information
DmitriySalnikov committed Sep 14, 2023
1 parent 5254896 commit c1cbc2f
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 119 deletions.
2 changes: 1 addition & 1 deletion examples_dd3d/DebugDrawDemoScene.gd
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func _process(delta: float) -> void:
$LagTest.visible = true

# Testing the rendering layers by showing the image from the second camera inside the 2D panel
#DebugDraw3D.config.geometry_render_layers = 1 if !Input.is_key_pressed(KEY_SHIFT) else 0b10010
DebugDraw3D.config.geometry_render_layers = 1 if !Input.is_key_pressed(KEY_SHIFT) else 0b10010
$Panel.visible = Input.is_key_pressed(KEY_SHIFT)
DebugDraw2D.custom_canvas = $CustomCanvas if Input.is_key_pressed(KEY_SHIFT) else null

Expand Down
2 changes: 1 addition & 1 deletion examples_dd3d/DebugDrawDemoSceneCS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public override void _Process(double delta)
dLagTest.Visible = true;

// Testing the rendering layers by showing the image from the second camera inside the 2D panel
// DebugDraw3D.Config.geometry_render_layers = 1 if !Input.IsKeyPressed(KEY_SHIFT) else 0b10010
DebugDraw3D.Config.GeometryRenderLayers = !Input.IsKeyPressed(Key.Shift) ? 1 : 0b10010;
dPanel.Visible = Input.IsKeyPressed(Key.Shift);
DebugDraw2D.CustomCanvas = Input.IsKeyPressed(Key.Shift) ? dCustomCanvas : null;

Expand Down
11 changes: 0 additions & 11 deletions src/2d/debug_draw_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,7 @@
#include "utils/utils.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/config_file.hpp>
#include <godot_cpp/classes/dir_access.hpp>
#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/classes/label.hpp>
#include <godot_cpp/classes/main_loop.hpp>
#include <godot_cpp/classes/node2d.hpp>
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/project_settings.hpp>
#include <godot_cpp/classes/scene_tree.hpp>
#include <godot_cpp/classes/standard_material3d.hpp>
#include <godot_cpp/classes/window.hpp>
GODOT_WARNING_RESTORE()

#include <limits.h>
Expand Down
3 changes: 1 addition & 2 deletions src/2d/debug_draw_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
#include "utils/compiler.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/camera3d.hpp> // TODO: need to be removed with vararg functions in release build.
#include <godot_cpp/classes/control.hpp>
#include <godot_cpp/classes/canvas_item.hpp>
#include <godot_cpp/classes/canvas_layer.hpp>
#include <godot_cpp/classes/font.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/classes/sub_viewport.hpp>
GODOT_WARNING_RESTORE()

#include <memory>
Expand Down
12 changes: 1 addition & 11 deletions src/3d/debug_draw_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,8 @@
#include "utils/utils.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/config_file.hpp>
#include <godot_cpp/classes/dir_access.hpp>
#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/classes/label.hpp>
#include <godot_cpp/classes/main_loop.hpp>
#include <godot_cpp/classes/node2d.hpp>
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/project_settings.hpp>
#include <godot_cpp/classes/scene_tree.hpp>
#include <godot_cpp/classes/camera3d.hpp>
#include <godot_cpp/classes/standard_material3d.hpp>
#include <godot_cpp/classes/window.hpp>
GODOT_WARNING_RESTORE()

#include <limits.h>
Expand Down
4 changes: 1 addition & 3 deletions src/3d/debug_draw_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#include "common/colors.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/camera3d.hpp> // TODO: need to be removed with vararg functions in release build.
#include <godot_cpp/classes/canvas_item.hpp>
#include <godot_cpp/classes/font.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/classes/sub_viewport.hpp>
Expand Down Expand Up @@ -332,7 +330,7 @@ class DebugDraw3D : public Object {
/// camera: Camera node
/// color: Color
/// duration: Duration of existence in seconds
void draw_camera_frustum(const class Camera3D *camera, const Color &color = Colors::empty_color, const real_t &duration = 0) FAKE_FUNC_IMPL;
void draw_camera_frustum(const class godot::Camera3D *camera, const Color &color = Colors::empty_color, const real_t &duration = 0) FAKE_FUNC_IMPL;

/// Draw camera frustum area
/// cameraFrustum: Array of frustum planes
Expand Down
3 changes: 0 additions & 3 deletions src/3d/debug_geometry_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
#include "stats_3d.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/main_loop.hpp>
#include <godot_cpp/classes/scene_tree.hpp>
#include <godot_cpp/classes/sub_viewport.hpp>
#include <godot_cpp/classes/world3d.hpp>
GODOT_WARNING_RESTORE()

Expand Down
11 changes: 1 addition & 10 deletions src/debug_draw_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,9 @@
#endif

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/config_file.hpp>
#include <godot_cpp/classes/dir_access.hpp>
#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/classes/label.hpp>
#include <godot_cpp/classes/main_loop.hpp>
#include <godot_cpp/classes/node2d.hpp>
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/project_settings.hpp>
#include <godot_cpp/classes/scene_tree.hpp>
#include <godot_cpp/classes/control.hpp>
#include <godot_cpp/classes/standard_material3d.hpp>
#include <godot_cpp/classes/window.hpp>
GODOT_WARNING_RESTORE()

DebugDrawManager *DebugDrawManager::singleton = nullptr;
Expand Down
5 changes: 0 additions & 5 deletions src/debug_draw_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
#include "utils/compiler.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/camera3d.hpp> // TODO: need to be removed with vararg functions in release build.
#include <godot_cpp/classes/canvas_item.hpp>
#include <godot_cpp/classes/canvas_layer.hpp>
#include <godot_cpp/classes/font.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/classes/sub_viewport.hpp>
GODOT_WARNING_RESTORE()

#include <memory>
Expand Down
3 changes: 0 additions & 3 deletions src/editor/asset_library_update_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
#include "version.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/json.hpp>
#include <godot_cpp/classes/project_settings.hpp>
#include <godot_cpp/classes/scene_tree.hpp>
#include <godot_cpp/classes/scene_tree_timer.hpp>
#include <godot_cpp/classes/window.hpp>
GODOT_WARNING_RESTORE()

using namespace godot;
Expand Down
126 changes: 71 additions & 55 deletions src/editor/generate_csharp_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/dir_access.hpp>
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/input.hpp>
GODOT_WARNING_RESTORE()

Expand Down Expand Up @@ -143,7 +142,7 @@ void GenerateCSharpBindingsPlugin::generate_class(const StringName &cls, remap_d
TypedArray<Dictionary> methods = ClassDB::class_get_method_list(cls, true);
TypedArray<Dictionary> signals = ClassDB::class_get_signal_list(cls, true);
TypedArray<Dictionary> properties = ClassDB::class_get_property_list(cls, true);
std::map<String, PropertyMethods> properties_map;
std::map<String, ArgumentData> properties_map;

bool is_preserved_inheritance = generate_for_classes.has(parent_name);
bool is_singleton = singletons.has(cls);
Expand Down Expand Up @@ -184,48 +183,54 @@ void GenerateCSharpBindingsPlugin::generate_class(const StringName &cls, remap_d
{
log("Methods...", 2);

int added = 0;
for (int i = 0; i < methods.size(); i++) {
String name = ((Dictionary)methods[i])["name"];
if (!name.begins_with("_")) {
added++;
line(FMT_STR("private static readonly StringName __{0} = \"{1}\";", name, name));
}
}

if (added)
line();
TypedArray<String> is_property;

for (int i = 0; i < methods.size(); i++) {
bool is_property = false;
String name = ((Dictionary)methods[i])["name"];

for (int j = 0; j < properties.size(); j++) {
String prop_name = ((Dictionary)properties[j])["name"];
auto split = name.split("_", true, 1);
if (split.size() == 2 && split[1] == prop_name) {
is_property = true;
is_property.append(name);

std::map<String, PropertyMethods>::iterator it = properties_map.find(prop_name);
std::map<String, ArgumentData>::iterator it = properties_map.find(prop_name);
if (it == properties_map.end()) {
properties_map[prop_name] = {};
properties_map[prop_name] = ArgumentData();
it = properties_map.find(prop_name);
}

if (name.begins_with("set")) {
(*it).second.set = name;
} else {
(*it).second.get = name;
(*it).second.type_name = argument_parse(((Dictionary)methods[i])["return"]).type_name;
ArgumentData data = argument_parse(((Dictionary)methods[i])["return"]);
data.name = prop_name;
(*it).second = data;
}
}
}
}

int added = 0;
for (int i = 0; i < methods.size(); i++) {
String name = ((Dictionary)methods[i])["name"];
if (!name.begins_with("_") && !is_property.has(name)) {
added++;
line(FMT_STR("private static readonly StringName __{0} = \"{1}\";", name, name));
}
}

if (added)
line();

for (int i = 0; i < methods.size(); i++) {
String name = ((Dictionary)methods[i])["name"];

if (name.begins_with("_")) {
continue;
}

generate_method(cls, methods[i], is_singleton, is_property, remapped_data);
if (!is_property.has(name))
generate_method(cls, methods[i], is_singleton, remapped_data);
}
}

Expand Down Expand Up @@ -395,7 +400,7 @@ void GenerateCSharpBindingsPlugin::generate_enum(const StringName &cls, const St
}
}

void GenerateCSharpBindingsPlugin::generate_method(const StringName &cls, const Dictionary &method, bool is_static, bool is_property, remap_data &remapped_data) {
void GenerateCSharpBindingsPlugin::generate_method(const StringName &cls, const Dictionary &method, bool is_static, remap_data &remapped_data) {
String name = (String)method["name"];

log(name, 3);
Expand All @@ -405,12 +410,10 @@ void GenerateCSharpBindingsPlugin::generate_method(const StringName &cls, const
bool is_need_wrapper = generate_for_classes.has(return_data.type_name);

String static_modifier_str = is_static ? "static " : "";
String access_str = is_property ? "private" : "public";
String prop_prefix = is_property ? "prop_" : "";

std::vector<DefaultData> default_args = arguments_parse_values(method["args"], method["default_args"], remapped_data);

line(FMT_STR("{0} {1}{2} {3}{4}({5})", access_str, static_modifier_str, return_data.type_name, prop_prefix, ((String)method["name"]).to_pascal_case(), arguments_string_decl(method["args"], true, default_args)));
line(FMT_STR("public {0}{1} {2}({3})", static_modifier_str, return_data.type_name, ((String)method["name"]).to_pascal_case(), arguments_string_decl(method["args"], true, default_args)));
{
TAB();

Expand All @@ -420,32 +423,25 @@ void GenerateCSharpBindingsPlugin::generate_method(const StringName &cls, const
}

{
auto method_body = [&]() {
if (!return_data.is_void) {
String int_convert = return_data.is_enum ? "(long)" : "";

if (is_need_wrapper) {
line(FMT_STR("return ({0})_DebugDrawUtils_.CreateWrapperFromObject((GodotObject)Instance?.Call(__{1}{2}));", return_data.type_name, name, call_args));
} else {
line(FMT_STR("return ({0})({1}Instance?.Call(__{2}{3}));", return_data.type_name, int_convert, name, call_args));
}
} else {
line(FMT_STR("Instance?.Call(__{0}{1});", name, call_args));
}
};
IFDEF_DD3D_ENABLED();

if (is_property) {
method_body();
} else {
IFDEF_DD3D_ENABLED();
if (!return_data.is_void) {
String int_convert = return_data.is_enum ? "(long)" : "";

method_body();
if (!return_data.is_void) {
IFELSE();
line("return default;");
if (is_need_wrapper) {
line(FMT_STR("return ({0})_DebugDrawUtils_.CreateWrapperFromObject((GodotObject)Instance?.Call(__{1}{2}));", return_data.type_name, name, call_args));
} else {
// Nothing to do
line(FMT_STR("return ({0})({1}Instance?.Call(__{2}{3}));", return_data.type_name, int_convert, name, call_args));
}
} else {
line(FMT_STR("Instance?.Call(__{0}{1});", name, call_args));
}

if (!return_data.is_void) {
IFELSE();
line("return default;");
} else {
// Nothing to do
}
}
}
Expand All @@ -466,20 +462,40 @@ void GenerateCSharpBindingsPlugin::generate_default_arguments_remap(const remap_
line();
}

void GenerateCSharpBindingsPlugin::generate_properties(const StringName &cls, const TypedArray<Dictionary> &props, std::map<String, PropertyMethods> setget_map, bool is_static) {
void GenerateCSharpBindingsPlugin::generate_properties(const StringName &cls, const TypedArray<Dictionary> &props, std::map<String, ArgumentData> setget_map, bool is_static) {
// ClassDB SetGet is faster than calling set/get methods
// Iterations: 100000
// Methods Get: 50,967 ms
// Methods Set: 60,477 ms
// ClassDB_SetGet Get: 28,660 ms
// ClassDB_SetGet Set: 26,918 ms

for (int i = 0; i < props.size(); i++) {
String name = ((Dictionary)props[i])["name"];
line(FMT_STR("private static readonly StringName __prop_{0} = \"{1}\";", name, name));
}
line();

for (int i = 0; i < props.size(); i++) {
Dictionary prop = props[i];
ArgumentData prop_info = argument_parse(prop);
PropertyMethods setget = setget_map[prop_info.name];
ArgumentData setget = setget_map[((Dictionary)props[i])["name"]];
bool is_need_wrapper = generate_for_classes.has(setget.type_name);
String static_modifier_str = is_static ? "static " : "";

log(prop_info.name, 3);
log(setget.name, 3);

line(FMT_STR("public {0}{1} {2}", static_modifier_str, setget.type_name, prop_info.name.to_pascal_case()));
line(FMT_STR("public {0}{1} {2}", static_modifier_str, setget.type_name, setget.name.to_pascal_case()));
{
TAB();
line(FMT_STR("get => prop_{0}();", setget.get.to_pascal_case()));
line(FMT_STR("set => prop_{0}(value);", setget.set.to_pascal_case()));
if (is_need_wrapper) {
line(FMT_STR("get => new {0}((GodotObject)ClassDB.ClassGetProperty(Instance, __prop_{1}));", setget.type_name, setget.name));
line(FMT_STR("set => ClassDB.ClassSetProperty(Instance, __prop_{0}, value.Instance);", setget.name));
} else if (setget.is_enum) {
line(FMT_STR("get => ({0})(long)ClassDB.ClassGetProperty(Instance, __prop_{1});", setget.type_name, setget.name));
line(FMT_STR("set => ClassDB.ClassSetProperty(Instance, __prop_{0}, (long)value);", setget.name));
} else {
line(FMT_STR("get => ({0})ClassDB.ClassGetProperty(Instance, __prop_{1});", setget.type_name, setget.name));
line(FMT_STR("set => ClassDB.ClassSetProperty(Instance, __prop_{0}, value);", setget.name));
}
}
line();
}
Expand Down
17 changes: 9 additions & 8 deletions src/editor/generate_csharp_bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,20 @@ class GenerateCSharpBindingsPlugin {
~IfDefGuard();
};

struct PropertyMethods {
String type_name;
String set;
String get;
};

struct ArgumentData {
String name;
String type_name;
Variant::Type type;
bool is_void;
bool is_enum;

ArgumentData() :
name("[NOT INITIALIZED]"),
type_name("[NOT INITIALIZED]"),
type(Variant::NIL),
is_void(false),
is_enum(false) {}

ArgumentData(const String &_name, Variant::Type _type, const String &_type_name, bool _enum = false) :
name(_name),
type_name(_type_name),
Expand Down Expand Up @@ -158,9 +159,9 @@ class GenerateCSharpBindingsPlugin {
void generate_wrapper(const StringName &cls, bool is_static, bool inheritance = false);
void generate_constants(const StringName &cls);
void generate_enum(const StringName &cls, const StringName &enm);
void generate_method(const StringName &cls, const Dictionary &method, bool is_static, bool is_property, remap_data &remapped_data);
void generate_method(const StringName &cls, const Dictionary &method, bool is_static, remap_data &remapped_data);
void generate_default_arguments_remap(const remap_data &remapped_data);
void generate_properties(const StringName &cls, const TypedArray<Dictionary> &props, std::map<String, PropertyMethods> setget_map, bool is_static);
void generate_properties(const StringName &cls, const TypedArray<Dictionary> &props, std::map<String, ArgumentData> setget_map, bool is_static);
ArgumentData argument_parse(const Dictionary &arg, bool is_return = false);
ArgumentData argument_parse(const StringName &class_name, const String &name, const Variant::Type type);
std::vector<DefaultData> arguments_parse_values(const TypedArray<Dictionary> &args, const Array &def_args, remap_data &remapped_data);
Expand Down
Loading

0 comments on commit c1cbc2f

Please sign in to comment.