summaryrefslogtreecommitdiff
path: root/core/bind
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <rverschelde@gmail.com>2020-08-27 11:35:39 +0200
committerGitHub <noreply@github.com>2020-08-27 11:35:39 +0200
commitd30c3d06dd465320abd799cd962501e16d93fbef (patch)
treed043355ca4d2e66ff16ddcbcabefffb78af9303e /core/bind
parent6875c9d684120025f765421de3d608fa9736b95f (diff)
parentea2eaf8c276e5d694aee075f8701467c3db76735 (diff)
Merge pull request #39440 from simpuid/custom-profilers
Debugger Plugins in Godot
Diffstat (limited to 'core/bind')
-rw-r--r--core/bind/core_bind.cpp152
-rw-r--r--core/bind/core_bind.h54
2 files changed, 206 insertions, 0 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 045d7d5872..489ff762c9 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -31,6 +31,7 @@
#include "core_bind.h"
#include "core/crypto/crypto_core.h"
+#include "core/debugger/engine_debugger.h"
#include "core/io/file_access_compressed.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/json.h"
@@ -2467,3 +2468,154 @@ Ref<JSONParseResult> _JSON::parse(const String &p_json) {
}
_JSON *_JSON::singleton = nullptr;
+
+////// _EngineDebugger //////
+
+void _EngineDebugger::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("is_active"), &_EngineDebugger::is_active);
+
+ ClassDB::bind_method(D_METHOD("register_profiler", "name", "toggle", "add", "tick"), &_EngineDebugger::register_profiler);
+ ClassDB::bind_method(D_METHOD("unregister_profiler", "name"), &_EngineDebugger::unregister_profiler);
+ ClassDB::bind_method(D_METHOD("is_profiling", "name"), &_EngineDebugger::is_profiling);
+ ClassDB::bind_method(D_METHOD("has_profiler", "name"), &_EngineDebugger::has_profiler);
+
+ ClassDB::bind_method(D_METHOD("profiler_add_frame_data", "name", "data"), &_EngineDebugger::profiler_add_frame_data);
+ ClassDB::bind_method(D_METHOD("profiler_enable", "name", "enable", "arguments"), &_EngineDebugger::profiler_enable, DEFVAL(Array()));
+
+ ClassDB::bind_method(D_METHOD("register_message_capture", "name", "callable"), &_EngineDebugger::register_message_capture);
+ ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &_EngineDebugger::unregister_message_capture);
+ ClassDB::bind_method(D_METHOD("has_capture", "name"), &_EngineDebugger::has_capture);
+
+ ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &_EngineDebugger::send_message);
+}
+
+bool _EngineDebugger::is_active() {
+ return EngineDebugger::is_active();
+}
+
+void _EngineDebugger::register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) {
+ ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), "Profiler already registered: " + p_name);
+ profilers.insert(p_name, ProfilerCallable(p_toggle, p_add, p_tick));
+ ProfilerCallable &p = profilers[p_name];
+ EngineDebugger::Profiler profiler(
+ &p,
+ &_EngineDebugger::call_toggle,
+ &_EngineDebugger::call_add,
+ &_EngineDebugger::call_tick);
+ EngineDebugger::register_profiler(p_name, profiler);
+}
+
+void _EngineDebugger::unregister_profiler(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name);
+ EngineDebugger::unregister_profiler(p_name);
+ profilers.erase(p_name);
+}
+
+bool _EngineDebugger::_EngineDebugger::is_profiling(const StringName &p_name) {
+ return EngineDebugger::is_profiling(p_name);
+}
+
+bool _EngineDebugger::has_profiler(const StringName &p_name) {
+ return EngineDebugger::has_profiler(p_name);
+}
+
+void _EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
+ EngineDebugger::profiler_add_frame_data(p_name, p_data);
+}
+
+void _EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
+ if (EngineDebugger::get_singleton()) {
+ EngineDebugger::get_singleton()->profiler_enable(p_name, p_enabled, p_opts);
+ }
+}
+
+void _EngineDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) {
+ ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), "Capture already registered: " + p_name);
+ captures.insert(p_name, p_callable);
+ Callable &c = captures[p_name];
+ EngineDebugger::Capture capture(&c, &_EngineDebugger::call_capture);
+ EngineDebugger::register_message_capture(p_name, capture);
+}
+
+void _EngineDebugger::unregister_message_capture(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name);
+ EngineDebugger::unregister_message_capture(p_name);
+ captures.erase(p_name);
+}
+
+bool _EngineDebugger::has_capture(const StringName &p_name) {
+ return EngineDebugger::has_capture(p_name);
+}
+
+void _EngineDebugger::send_message(const String &p_msg, const Array &p_data) {
+ ERR_FAIL_COND_MSG(!EngineDebugger::is_active(), "Can't send message. No active debugger");
+ EngineDebugger::get_singleton()->send_message(p_msg, p_data);
+}
+
+void _EngineDebugger::call_toggle(void *p_user, bool p_enable, const Array &p_opts) {
+ Callable &toggle = ((ProfilerCallable *)p_user)->callable_toggle;
+ if (toggle.is_null()) {
+ return;
+ }
+ Variant enable = p_enable, opts = p_opts;
+ const Variant *args[2] = { &enable, &opts };
+ Variant retval;
+ Callable::CallError err;
+ toggle.call(args, 2, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'toggle' to callable: " + Variant::get_callable_error_text(toggle, args, 2, err));
+}
+
+void _EngineDebugger::call_add(void *p_user, const Array &p_data) {
+ Callable &add = ((ProfilerCallable *)p_user)->callable_add;
+ if (add.is_null()) {
+ return;
+ }
+ Variant data = p_data;
+ const Variant *args[1] = { &data };
+ Variant retval;
+ Callable::CallError err;
+ add.call(args, 1, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'add' to callable: " + Variant::get_callable_error_text(add, args, 1, err));
+}
+
+void _EngineDebugger::call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) {
+ Callable &tick = ((ProfilerCallable *)p_user)->callable_tick;
+ if (tick.is_null()) {
+ return;
+ }
+ Variant frame_time = p_frame_time, idle_time = p_idle_time, physics_time = p_physics_time, physics_frame_time = p_physics_frame_time;
+ const Variant *args[4] = { &frame_time, &idle_time, &physics_time, &physics_frame_time };
+ Variant retval;
+ Callable::CallError err;
+ tick.call(args, 4, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'tick' to callable: " + Variant::get_callable_error_text(tick, args, 4, err));
+}
+
+Error _EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
+ Callable &capture = *(Callable *)p_user;
+ if (capture.is_null()) {
+ return FAILED;
+ }
+ Variant cmd = p_cmd, data = p_data;
+ const Variant *args[2] = { &cmd, &data };
+ Variant retval;
+ Callable::CallError err;
+ capture.call(args, 2, retval, err);
+ ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(capture, args, 2, err));
+ ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, "Error calling 'capture' to callable: " + String(capture) + ". Return type is not bool.");
+ r_captured = retval;
+ return OK;
+}
+
+_EngineDebugger::~_EngineDebugger() {
+ for (Map<StringName, Callable>::Element *E = captures.front(); E; E = E->next()) {
+ EngineDebugger::unregister_message_capture(E->key());
+ }
+ captures.clear();
+ for (Map<StringName, ProfilerCallable>::Element *E = profilers.front(); E; E = E->next()) {
+ EngineDebugger::unregister_profiler(E->key());
+ }
+ profilers.clear();
+}
+
+_EngineDebugger *_EngineDebugger::singleton = nullptr;
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index a1fedf1bb8..a59fcda60c 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -715,4 +715,58 @@ public:
_JSON() { singleton = this; }
};
+class _EngineDebugger : public Object {
+ GDCLASS(_EngineDebugger, Object);
+
+ class ProfilerCallable {
+ friend class _EngineDebugger;
+
+ Callable callable_toggle;
+ Callable callable_add;
+ Callable callable_tick;
+
+ public:
+ ProfilerCallable() {}
+
+ ProfilerCallable(const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) {
+ callable_toggle = p_toggle;
+ callable_add = p_add;
+ callable_tick = p_tick;
+ }
+ };
+
+ Map<StringName, Callable> captures;
+ Map<StringName, ProfilerCallable> profilers;
+
+protected:
+ static void _bind_methods();
+ static _EngineDebugger *singleton;
+
+public:
+ static _EngineDebugger *get_singleton() { return singleton; }
+
+ bool is_active();
+
+ void register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick);
+ void unregister_profiler(const StringName &p_name);
+ bool is_profiling(const StringName &p_name);
+ bool has_profiler(const StringName &p_name);
+ void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
+ void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
+
+ void register_message_capture(const StringName &p_name, const Callable &p_callable);
+ void unregister_message_capture(const StringName &p_name);
+ bool has_capture(const StringName &p_name);
+
+ void send_message(const String &p_msg, const Array &p_data);
+
+ static void call_toggle(void *p_user, bool p_enable, const Array &p_opts);
+ static void call_add(void *p_user, const Array &p_data);
+ static void call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time);
+ static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
+
+ _EngineDebugger() { singleton = this; }
+ ~_EngineDebugger();
+};
+
#endif // CORE_BIND_H