Bladeren bron

[Debugger] New extensible EngineProfiler class.

Uses GDExtension, replaces old Callable system for profilers, and is
also used internally.
Fabio Alessandrelli 3 jaren geleden
bovenliggende
commit
789e648f4d

+ 10 - 55
core/core_bind.cpp

@@ -2376,21 +2376,18 @@ 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::register_profiler(const StringName &p_name, Ref<EngineProfiler> p_profiler) {
+	ERR_FAIL_COND(p_profiler.is_null());
+	ERR_FAIL_COND_MSG(p_profiler->is_bound(), "Profiler already registered.");
+	ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), "Profiler name already in use: " + p_name);
+	Error err = p_profiler->bind(p_name);
+	ERR_FAIL_COND_MSG(err != OK, "Profiler failed to register with error: " + itos(err));
+	profilers.insert(p_name, p_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[p_name]->unbind();
 	profilers.erase(p_name);
 }
 
@@ -2435,45 +2432,6 @@ void EngineDebugger::send_message(const String &p_msg, const Array &p_data) {
 	::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, double p_frame_time, double p_idle_time, double p_physics_time, double 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()) {
@@ -2495,10 +2453,6 @@ EngineDebugger::~EngineDebugger() {
 		::EngineDebugger::unregister_message_capture(E.key);
 	}
 	captures.clear();
-	for (const KeyValue<StringName, ProfilerCallable> &E : profilers) {
-		::EngineDebugger::unregister_profiler(E.key);
-	}
-	profilers.clear();
 }
 
 EngineDebugger *EngineDebugger::singleton = nullptr;
@@ -2506,8 +2460,9 @@ EngineDebugger *EngineDebugger::singleton = nullptr;
 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("register_profiler", "name", "profiler"), &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);
 

+ 3 - 22
core/core_bind.h

@@ -31,6 +31,7 @@
 #ifndef CORE_BIND_H
 #define CORE_BIND_H
 
+#include "core/debugger/engine_profiler.h"
 #include "core/io/compression.h"
 #include "core/io/dir_access.h"
 #include "core/io/file_access.h"
@@ -673,25 +674,8 @@ public:
 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;
+	Map<StringName, Ref<EngineProfiler>> profilers;
 
 protected:
 	static void _bind_methods();
@@ -702,7 +686,7 @@ public:
 
 	bool is_active();
 
-	void register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick);
+	void register_profiler(const StringName &p_name, Ref<EngineProfiler> p_profiler);
 	void unregister_profiler(const StringName &p_name);
 	bool is_profiling(const StringName &p_name);
 	bool has_profiler(const StringName &p_name);
@@ -715,9 +699,6 @@ public:
 
 	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, double p_frame_time, double p_idle_time, double p_physics_time, double 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; }

+ 82 - 0
core/debugger/engine_profiler.cpp

@@ -0,0 +1,82 @@
+/*************************************************************************/
+/*  engine_profiler.cpp                                                  */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "engine_profiler.h"
+
+#include "core/debugger/engine_debugger.h"
+
+void EngineProfiler::_bind_methods() {
+	GDVIRTUAL_BIND(_toggle, "enable", "options");
+	GDVIRTUAL_BIND(_add_frame, "data");
+	GDVIRTUAL_BIND(_tick, "frame_time", "idle_time", "physics_time", "physics_frame_time");
+}
+
+void EngineProfiler::toggle(bool p_enable, const Array &p_array) {
+	GDVIRTUAL_CALL(_toggle, p_enable, p_array);
+}
+
+void EngineProfiler::add(const Array &p_data) {
+	GDVIRTUAL_CALL(_add_frame, p_data);
+}
+
+void EngineProfiler::tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
+	GDVIRTUAL_CALL(_tick, p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time);
+}
+
+Error EngineProfiler::bind(const String &p_name) {
+	ERR_FAIL_COND_V(is_bound(), ERR_ALREADY_IN_USE);
+	EngineDebugger::Profiler prof(
+			this,
+			[](void *p_user, bool p_enable, const Array &p_opts) {
+				((EngineProfiler *)p_user)->toggle(p_enable, p_opts);
+			},
+			[](void *p_user, const Array &p_data) {
+				((EngineProfiler *)p_user)->add(p_data);
+			},
+			[](void *p_user, double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) {
+				((EngineProfiler *)p_user)->tick(p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time);
+			});
+	registration = p_name;
+	EngineDebugger::register_profiler(p_name, prof);
+	return OK;
+}
+
+Error EngineProfiler::unbind() {
+	ERR_FAIL_COND_V(!is_bound(), ERR_UNCONFIGURED);
+	EngineDebugger::unregister_profiler(registration);
+	registration.clear();
+	return OK;
+}
+
+EngineProfiler::~EngineProfiler() {
+	if (is_bound()) {
+		unbind();
+	}
+}

+ 65 - 0
core/debugger/engine_profiler.h

@@ -0,0 +1,65 @@
+/*************************************************************************/
+/*  engine_profiler.h                                                    */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef ENGINE_PROFILER_H
+#define ENGINE_PROFILER_H
+
+#include "core/object/ref_counted.h"
+
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
+
+class EngineProfiler : public RefCounted {
+	GDCLASS(EngineProfiler, RefCounted);
+
+private:
+	String registration;
+
+protected:
+	static void _bind_methods();
+
+public:
+	virtual void toggle(bool p_enable, const Array &p_opts);
+	virtual void add(const Array &p_data);
+	virtual void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time);
+
+	Error bind(const String &p_name);
+	Error unbind();
+	bool is_bound() const { return registration.length() > 0; }
+
+	GDVIRTUAL2(_toggle, bool, Array);
+	GDVIRTUAL1(_add_frame, Array);
+	GDVIRTUAL4(_tick, double, double, double, double);
+
+	EngineProfiler() {}
+	virtual ~EngineProfiler();
+};
+
+#endif // ENGINE_PROFILER_H

+ 3 - 0
core/register_core_types.cpp

@@ -37,6 +37,7 @@
 #include "core/crypto/aes_context.h"
 #include "core/crypto/crypto.h"
 #include "core/crypto/hashing_context.h"
+#include "core/debugger/engine_profiler.h"
 #include "core/extension/native_extension.h"
 #include "core/extension/native_extension_manager.h"
 #include "core/input/input.h"
@@ -237,6 +238,8 @@ void register_core_types() {
 
 	GDREGISTER_VIRTUAL_CLASS(ResourceUID);
 
+	GDREGISTER_CLASS(EngineProfiler);
+
 	resource_uid = memnew(ResourceUID);
 
 	native_extension_manager = memnew(NativeExtensionManager);

+ 2 - 7
doc/classes/EngineDebugger.xml

@@ -65,14 +65,9 @@
 		<method name="register_profiler">
 			<return type="void" />
 			<argument index="0" name="name" type="StringName" />
-			<argument index="1" name="toggle" type="Callable" />
-			<argument index="2" name="add" type="Callable" />
-			<argument index="3" name="tick" type="Callable" />
+			<argument index="1" name="profiler" type="EngineProfiler" />
 			<description>
-				Registers a profiler with the given [code]name[/code].
-				[code]toggle[/code] callable is called when the profiler is enabled/disabled. It must take an argument array as an argument.
-				[code]add[/code] callable is called when data is added to profiler using [method EngineDebugger.profiler_add_frame_data]. It must take a data array as argument.
-				[code]tick[/code] callable is called at every active profiler iteration. It must take frame time, idle time, physics time, and physics idle time as arguments.
+				Registers a profiler with the given [code]name[/code]. See [EngineProfiler] for more informations.
 			</description>
 		</method>
 		<method name="send_message">

+ 39 - 0
doc/classes/EngineProfiler.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EngineProfiler" inherits="RefCounted" version="4.0">
+	<brief_description>
+		Base class for creating custom profilers.
+	</brief_description>
+	<description>
+		This class can be used to implement custom profilers that are able to interact with the engine and editor debugger.
+		See [EngineDebugger] and [EditorDebuggerPlugin] for more informations.
+	</description>
+	<tutorials>
+	</tutorials>
+	<methods>
+		<method name="_add_frame" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="data" type="Array" />
+			<description>
+				Called when data is added to profiler using [method EngineDebugger.profiler_add_frame_data].
+			</description>
+		</method>
+		<method name="_tick" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="frame_time" type="float" />
+			<argument index="1" name="idle_time" type="float" />
+			<argument index="2" name="physics_time" type="float" />
+			<argument index="3" name="physics_frame_time" type="float" />
+			<description>
+				Called once every engine iteration when the profiler is active with informations about the current frame.
+			</description>
+		</method>
+		<method name="_toggle" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="enable" type="bool" />
+			<argument index="1" name="options" type="Array" />
+			<description>
+				Called when the profiler is enabled/disabled, along with a set of [code]options[/code].
+			</description>
+		</method>
+	</methods>
+</class>