| 1 | /**************************************************************************/ | 
|---|
| 2 | /*  servers_debugger.cpp                                                  */ | 
|---|
| 3 | /**************************************************************************/ | 
|---|
| 4 | /*                         This file is part of:                          */ | 
|---|
| 5 | /*                             GODOT ENGINE                               */ | 
|---|
| 6 | /*                        https://godotengine.org                         */ | 
|---|
| 7 | /**************************************************************************/ | 
|---|
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
|---|
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
|---|
| 10 | /*                                                                        */ | 
|---|
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining  */ | 
|---|
| 12 | /* a copy of this software and associated documentation files (the        */ | 
|---|
| 13 | /* "Software"), to deal in the Software without restriction, including    */ | 
|---|
| 14 | /* without limitation the rights to use, copy, modify, merge, publish,    */ | 
|---|
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to     */ | 
|---|
| 16 | /* permit persons to whom the Software is furnished to do so, subject to  */ | 
|---|
| 17 | /* the following conditions:                                              */ | 
|---|
| 18 | /*                                                                        */ | 
|---|
| 19 | /* The above copyright notice and this permission notice shall be         */ | 
|---|
| 20 | /* included in all copies or substantial portions of the Software.        */ | 
|---|
| 21 | /*                                                                        */ | 
|---|
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | 
|---|
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | 
|---|
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | 
|---|
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | 
|---|
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | 
|---|
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | 
|---|
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | 
|---|
| 29 | /**************************************************************************/ | 
|---|
| 30 |  | 
|---|
| 31 | #include "servers_debugger.h" | 
|---|
| 32 |  | 
|---|
| 33 | #include "core/config/project_settings.h" | 
|---|
| 34 | #include "core/debugger/engine_debugger.h" | 
|---|
| 35 | #include "core/debugger/engine_profiler.h" | 
|---|
| 36 | #include "core/io/marshalls.h" | 
|---|
| 37 | #include "servers/display_server.h" | 
|---|
| 38 |  | 
|---|
| 39 | #define CHECK_SIZE(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() < (uint32_t)(expected), false, String("Malformed ") + what + " message from script debugger, message too short. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size())) | 
|---|
| 40 | #define CHECK_END(arr, expected, what) ERR_FAIL_COND_V_MSG((uint32_t)arr.size() > (uint32_t)expected, false, String("Malformed ") + what + " message from script debugger, message too long. Expected size: " + itos(expected) + ", actual size: " + itos(arr.size())) | 
|---|
| 41 |  | 
|---|
| 42 | Array ServersDebugger::ResourceUsage::serialize() { | 
|---|
| 43 | infos.sort(); | 
|---|
| 44 |  | 
|---|
| 45 | Array arr; | 
|---|
| 46 | arr.push_back(infos.size() * 4); | 
|---|
| 47 | for (const ResourceInfo &E : infos) { | 
|---|
| 48 | arr.push_back(E.path); | 
|---|
| 49 | arr.push_back(E.format); | 
|---|
| 50 | arr.push_back(E.type); | 
|---|
| 51 | arr.push_back(E.vram); | 
|---|
| 52 | } | 
|---|
| 53 | return arr; | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | bool ServersDebugger::ResourceUsage::deserialize(const Array &p_arr) { | 
|---|
| 57 | CHECK_SIZE(p_arr, 1, "ResourceUsage"); | 
|---|
| 58 | uint32_t size = p_arr[0]; | 
|---|
| 59 | ERR_FAIL_COND_V(size % 4, false); | 
|---|
| 60 | CHECK_SIZE(p_arr, 1 + size, "ResourceUsage"); | 
|---|
| 61 | uint32_t idx = 1; | 
|---|
| 62 | while (idx < 1 + size) { | 
|---|
| 63 | ResourceInfo info; | 
|---|
| 64 | info.path = p_arr[idx]; | 
|---|
| 65 | info.format = p_arr[idx + 1]; | 
|---|
| 66 | info.type = p_arr[idx + 2]; | 
|---|
| 67 | info.vram = p_arr[idx + 3]; | 
|---|
| 68 | infos.push_back(info); | 
|---|
| 69 | idx += 4; | 
|---|
| 70 | } | 
|---|
| 71 | CHECK_END(p_arr, idx, "ResourceUsage"); | 
|---|
| 72 | return true; | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | Array ServersDebugger::ScriptFunctionSignature::serialize() { | 
|---|
| 76 | Array arr; | 
|---|
| 77 | arr.push_back(name); | 
|---|
| 78 | arr.push_back(id); | 
|---|
| 79 | return arr; | 
|---|
| 80 | } | 
|---|
| 81 |  | 
|---|
| 82 | bool ServersDebugger::ScriptFunctionSignature::deserialize(const Array &p_arr) { | 
|---|
| 83 | CHECK_SIZE(p_arr, 2, "ScriptFunctionSignature"); | 
|---|
| 84 | name = p_arr[0]; | 
|---|
| 85 | id = p_arr[1]; | 
|---|
| 86 | CHECK_END(p_arr, 2, "ScriptFunctionSignature"); | 
|---|
| 87 | return true; | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | Array ServersDebugger::ServersProfilerFrame::serialize() { | 
|---|
| 91 | Array arr; | 
|---|
| 92 | arr.push_back(frame_number); | 
|---|
| 93 | arr.push_back(frame_time); | 
|---|
| 94 | arr.push_back(process_time); | 
|---|
| 95 | arr.push_back(physics_time); | 
|---|
| 96 | arr.push_back(physics_frame_time); | 
|---|
| 97 | arr.push_back(script_time); | 
|---|
| 98 |  | 
|---|
| 99 | arr.push_back(servers.size()); | 
|---|
| 100 | for (int i = 0; i < servers.size(); i++) { | 
|---|
| 101 | ServerInfo &s = servers[i]; | 
|---|
| 102 | arr.push_back(s.name); | 
|---|
| 103 | arr.push_back(s.functions.size() * 2); | 
|---|
| 104 | for (int j = 0; j < s.functions.size(); j++) { | 
|---|
| 105 | ServerFunctionInfo &f = s.functions[j]; | 
|---|
| 106 | arr.push_back(f.name); | 
|---|
| 107 | arr.push_back(f.time); | 
|---|
| 108 | } | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | arr.push_back(script_functions.size() * 4); | 
|---|
| 112 | for (int i = 0; i < script_functions.size(); i++) { | 
|---|
| 113 | arr.push_back(script_functions[i].sig_id); | 
|---|
| 114 | arr.push_back(script_functions[i].call_count); | 
|---|
| 115 | arr.push_back(script_functions[i].self_time); | 
|---|
| 116 | arr.push_back(script_functions[i].total_time); | 
|---|
| 117 | } | 
|---|
| 118 | return arr; | 
|---|
| 119 | } | 
|---|
| 120 |  | 
|---|
| 121 | bool ServersDebugger::ServersProfilerFrame::deserialize(const Array &p_arr) { | 
|---|
| 122 | CHECK_SIZE(p_arr, 7, "ServersProfilerFrame"); | 
|---|
| 123 | frame_number = p_arr[0]; | 
|---|
| 124 | frame_time = p_arr[1]; | 
|---|
| 125 | process_time = p_arr[2]; | 
|---|
| 126 | physics_time = p_arr[3]; | 
|---|
| 127 | physics_frame_time = p_arr[4]; | 
|---|
| 128 | script_time = p_arr[5]; | 
|---|
| 129 | int servers_size = p_arr[6]; | 
|---|
| 130 | int idx = 7; | 
|---|
| 131 | while (servers_size) { | 
|---|
| 132 | CHECK_SIZE(p_arr, idx + 2, "ServersProfilerFrame"); | 
|---|
| 133 | servers_size--; | 
|---|
| 134 | ServerInfo si; | 
|---|
| 135 | si.name = p_arr[idx]; | 
|---|
| 136 | int sub_data_size = p_arr[idx + 1]; | 
|---|
| 137 | idx += 2; | 
|---|
| 138 | CHECK_SIZE(p_arr, idx + sub_data_size, "ServersProfilerFrame"); | 
|---|
| 139 | for (int j = 0; j < sub_data_size / 2; j++) { | 
|---|
| 140 | ServerFunctionInfo sf; | 
|---|
| 141 | sf.name = p_arr[idx]; | 
|---|
| 142 | sf.time = p_arr[idx + 1]; | 
|---|
| 143 | idx += 2; | 
|---|
| 144 | si.functions.push_back(sf); | 
|---|
| 145 | } | 
|---|
| 146 | servers.push_back(si); | 
|---|
| 147 | } | 
|---|
| 148 | CHECK_SIZE(p_arr, idx + 1, "ServersProfilerFrame"); | 
|---|
| 149 | int func_size = p_arr[idx]; | 
|---|
| 150 | idx += 1; | 
|---|
| 151 | CHECK_SIZE(p_arr, idx + func_size, "ServersProfilerFrame"); | 
|---|
| 152 | for (int i = 0; i < func_size / 4; i++) { | 
|---|
| 153 | ScriptFunctionInfo fi; | 
|---|
| 154 | fi.sig_id = p_arr[idx]; | 
|---|
| 155 | fi.call_count = p_arr[idx + 1]; | 
|---|
| 156 | fi.self_time = p_arr[idx + 2]; | 
|---|
| 157 | fi.total_time = p_arr[idx + 3]; | 
|---|
| 158 | script_functions.push_back(fi); | 
|---|
| 159 | idx += 4; | 
|---|
| 160 | } | 
|---|
| 161 | CHECK_END(p_arr, idx, "ServersProfilerFrame"); | 
|---|
| 162 | return true; | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | Array ServersDebugger::VisualProfilerFrame::serialize() { | 
|---|
| 166 | Array arr; | 
|---|
| 167 | arr.push_back(frame_number); | 
|---|
| 168 | arr.push_back(areas.size() * 3); | 
|---|
| 169 | for (int i = 0; i < areas.size(); i++) { | 
|---|
| 170 | arr.push_back(areas[i].name); | 
|---|
| 171 | arr.push_back(areas[i].cpu_msec); | 
|---|
| 172 | arr.push_back(areas[i].gpu_msec); | 
|---|
| 173 | } | 
|---|
| 174 | return arr; | 
|---|
| 175 | } | 
|---|
| 176 |  | 
|---|
| 177 | bool ServersDebugger::VisualProfilerFrame::deserialize(const Array &p_arr) { | 
|---|
| 178 | CHECK_SIZE(p_arr, 2, "VisualProfilerFrame"); | 
|---|
| 179 | frame_number = p_arr[0]; | 
|---|
| 180 | int size = p_arr[1]; | 
|---|
| 181 | CHECK_SIZE(p_arr, size, "VisualProfilerFrame"); | 
|---|
| 182 | int idx = 2; | 
|---|
| 183 | areas.resize(size / 3); | 
|---|
| 184 | RS::FrameProfileArea *w = areas.ptrw(); | 
|---|
| 185 | for (int i = 0; i < size / 3; i++) { | 
|---|
| 186 | w[i].name = p_arr[idx]; | 
|---|
| 187 | w[i].cpu_msec = p_arr[idx + 1]; | 
|---|
| 188 | w[i].gpu_msec = p_arr[idx + 2]; | 
|---|
| 189 | idx += 3; | 
|---|
| 190 | } | 
|---|
| 191 | CHECK_END(p_arr, idx, "VisualProfilerFrame"); | 
|---|
| 192 | return true; | 
|---|
| 193 | } | 
|---|
| 194 | class ServersDebugger::ScriptsProfiler : public EngineProfiler { | 
|---|
| 195 | typedef ServersDebugger::ScriptFunctionSignature FunctionSignature; | 
|---|
| 196 | typedef ServersDebugger::ScriptFunctionInfo FunctionInfo; | 
|---|
| 197 | struct ProfileInfoSort { | 
|---|
| 198 | bool operator()(ScriptLanguage::ProfilingInfo *A, ScriptLanguage::ProfilingInfo *B) const { | 
|---|
| 199 | return A->total_time < B->total_time; | 
|---|
| 200 | } | 
|---|
| 201 | }; | 
|---|
| 202 | Vector<ScriptLanguage::ProfilingInfo> info; | 
|---|
| 203 | Vector<ScriptLanguage::ProfilingInfo *> ptrs; | 
|---|
| 204 | HashMap<StringName, int> sig_map; | 
|---|
| 205 | int max_frame_functions = 16; | 
|---|
| 206 |  | 
|---|
| 207 | public: | 
|---|
| 208 | void toggle(bool p_enable, const Array &p_opts) { | 
|---|
| 209 | if (p_enable) { | 
|---|
| 210 | sig_map.clear(); | 
|---|
| 211 | for (int i = 0; i < ScriptServer::get_language_count(); i++) { | 
|---|
| 212 | ScriptServer::get_language(i)->profiling_start(); | 
|---|
| 213 | } | 
|---|
| 214 | if (p_opts.size() == 1 && p_opts[0].get_type() == Variant::INT) { | 
|---|
| 215 | max_frame_functions = MAX(0, int(p_opts[0])); | 
|---|
| 216 | } | 
|---|
| 217 | } else { | 
|---|
| 218 | for (int i = 0; i < ScriptServer::get_language_count(); i++) { | 
|---|
| 219 | ScriptServer::get_language(i)->profiling_stop(); | 
|---|
| 220 | } | 
|---|
| 221 | } | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 | void write_frame_data(Vector<FunctionInfo> &r_funcs, uint64_t &r_total, bool p_accumulated) { | 
|---|
| 225 | int ofs = 0; | 
|---|
| 226 | for (int i = 0; i < ScriptServer::get_language_count(); i++) { | 
|---|
| 227 | if (p_accumulated) { | 
|---|
| 228 | ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&info.write[ofs], info.size() - ofs); | 
|---|
| 229 | } else { | 
|---|
| 230 | ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&info.write[ofs], info.size() - ofs); | 
|---|
| 231 | } | 
|---|
| 232 | } | 
|---|
| 233 |  | 
|---|
| 234 | for (int i = 0; i < ofs; i++) { | 
|---|
| 235 | ptrs.write[i] = &info.write[i]; | 
|---|
| 236 | } | 
|---|
| 237 |  | 
|---|
| 238 | SortArray<ScriptLanguage::ProfilingInfo *, ProfileInfoSort> sa; | 
|---|
| 239 | sa.sort(ptrs.ptrw(), ofs); | 
|---|
| 240 |  | 
|---|
| 241 | int to_send = MIN(ofs, max_frame_functions); | 
|---|
| 242 |  | 
|---|
| 243 | // Check signatures first, and compute total time. | 
|---|
| 244 | r_total = 0; | 
|---|
| 245 | for (int i = 0; i < to_send; i++) { | 
|---|
| 246 | if (!sig_map.has(ptrs[i]->signature)) { | 
|---|
| 247 | int idx = sig_map.size(); | 
|---|
| 248 | FunctionSignature sig; | 
|---|
| 249 | sig.name = ptrs[i]->signature; | 
|---|
| 250 | sig.id = idx; | 
|---|
| 251 | EngineDebugger::get_singleton()->send_message( "servers:function_signature", sig.serialize()); | 
|---|
| 252 | sig_map[ptrs[i]->signature] = idx; | 
|---|
| 253 | } | 
|---|
| 254 | r_total += ptrs[i]->self_time; | 
|---|
| 255 | } | 
|---|
| 256 |  | 
|---|
| 257 | // Send frame, script time, functions information then | 
|---|
| 258 | r_funcs.resize(to_send); | 
|---|
| 259 |  | 
|---|
| 260 | FunctionInfo *w = r_funcs.ptrw(); | 
|---|
| 261 | for (int i = 0; i < to_send; i++) { | 
|---|
| 262 | if (sig_map.has(ptrs[i]->signature)) { | 
|---|
| 263 | w[i].sig_id = sig_map[ptrs[i]->signature]; | 
|---|
| 264 | } | 
|---|
| 265 | w[i].call_count = ptrs[i]->call_count; | 
|---|
| 266 | w[i].total_time = ptrs[i]->total_time / 1000000.0; | 
|---|
| 267 | w[i].self_time = ptrs[i]->self_time / 1000000.0; | 
|---|
| 268 | } | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 | ScriptsProfiler() { | 
|---|
| 272 | info.resize(GLOBAL_GET( "debug/settings/profiler/max_functions")); | 
|---|
| 273 | ptrs.resize(info.size()); | 
|---|
| 274 | } | 
|---|
| 275 | }; | 
|---|
| 276 |  | 
|---|
| 277 | class ServersDebugger::ServersProfiler : public EngineProfiler { | 
|---|
| 278 | bool skip_profile_frame = false; | 
|---|
| 279 | typedef ServersDebugger::ServerInfo ServerInfo; | 
|---|
| 280 | typedef ServersDebugger::ServerFunctionInfo ServerFunctionInfo; | 
|---|
| 281 |  | 
|---|
| 282 | HashMap<StringName, ServerInfo> server_data; | 
|---|
| 283 | ScriptsProfiler scripts_profiler; | 
|---|
| 284 |  | 
|---|
| 285 | double frame_time = 0; | 
|---|
| 286 | double process_time = 0; | 
|---|
| 287 | double physics_time = 0; | 
|---|
| 288 | double physics_frame_time = 0; | 
|---|
| 289 |  | 
|---|
| 290 | void _send_frame_data(bool p_final) { | 
|---|
| 291 | ServersDebugger::ServersProfilerFrame frame; | 
|---|
| 292 | frame.frame_number = Engine::get_singleton()->get_process_frames(); | 
|---|
| 293 | frame.frame_time = frame_time; | 
|---|
| 294 | frame.process_time = process_time; | 
|---|
| 295 | frame.physics_time = physics_time; | 
|---|
| 296 | frame.physics_frame_time = physics_frame_time; | 
|---|
| 297 | HashMap<StringName, ServerInfo>::Iterator E = server_data.begin(); | 
|---|
| 298 | while (E) { | 
|---|
| 299 | if (!p_final) { | 
|---|
| 300 | frame.servers.push_back(E->value); | 
|---|
| 301 | } | 
|---|
| 302 | E->value.functions.clear(); | 
|---|
| 303 | ++E; | 
|---|
| 304 | } | 
|---|
| 305 | uint64_t time = 0; | 
|---|
| 306 | scripts_profiler.write_frame_data(frame.script_functions, time, p_final); | 
|---|
| 307 | frame.script_time = USEC_TO_SEC(time); | 
|---|
| 308 | if (skip_profile_frame) { | 
|---|
| 309 | skip_profile_frame = false; | 
|---|
| 310 | return; | 
|---|
| 311 | } | 
|---|
| 312 | if (p_final) { | 
|---|
| 313 | EngineDebugger::get_singleton()->send_message( "servers:profile_total", frame.serialize()); | 
|---|
| 314 | } else { | 
|---|
| 315 | EngineDebugger::get_singleton()->send_message( "servers:profile_frame", frame.serialize()); | 
|---|
| 316 | } | 
|---|
| 317 | } | 
|---|
| 318 |  | 
|---|
| 319 | public: | 
|---|
| 320 | void toggle(bool p_enable, const Array &p_opts) { | 
|---|
| 321 | skip_profile_frame = false; | 
|---|
| 322 | if (p_enable) { | 
|---|
| 323 | server_data.clear(); // Clear old profiling data. | 
|---|
| 324 | } else { | 
|---|
| 325 | _send_frame_data(true); // Send final frame. | 
|---|
| 326 | } | 
|---|
| 327 | scripts_profiler.toggle(p_enable, p_opts); | 
|---|
| 328 | } | 
|---|
| 329 |  | 
|---|
| 330 | void add(const Array &p_data) { | 
|---|
| 331 | String name = p_data[0]; | 
|---|
| 332 | if (!server_data.has(name)) { | 
|---|
| 333 | ServerInfo info; | 
|---|
| 334 | info.name = name; | 
|---|
| 335 | server_data[name] = info; | 
|---|
| 336 | } | 
|---|
| 337 | ServerInfo &srv = server_data[name]; | 
|---|
| 338 |  | 
|---|
| 339 | ServerFunctionInfo fi; | 
|---|
| 340 | fi.name = p_data[1]; | 
|---|
| 341 | fi.time = p_data[2]; | 
|---|
| 342 | srv.functions.push_back(fi); | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) { | 
|---|
| 346 | frame_time = p_frame_time; | 
|---|
| 347 | process_time = p_process_time; | 
|---|
| 348 | physics_time = p_physics_time; | 
|---|
| 349 | physics_frame_time = p_physics_frame_time; | 
|---|
| 350 | _send_frame_data(false); | 
|---|
| 351 | } | 
|---|
| 352 |  | 
|---|
| 353 | void skip_frame() { | 
|---|
| 354 | skip_profile_frame = true; | 
|---|
| 355 | } | 
|---|
| 356 | }; | 
|---|
| 357 |  | 
|---|
| 358 | class ServersDebugger::VisualProfiler : public EngineProfiler { | 
|---|
| 359 | typedef ServersDebugger::ServerInfo ServerInfo; | 
|---|
| 360 | typedef ServersDebugger::ServerFunctionInfo ServerFunctionInfo; | 
|---|
| 361 |  | 
|---|
| 362 | HashMap<StringName, ServerInfo> server_data; | 
|---|
| 363 |  | 
|---|
| 364 | public: | 
|---|
| 365 | void toggle(bool p_enable, const Array &p_opts) { | 
|---|
| 366 | RS::get_singleton()->set_frame_profiling_enabled(p_enable); | 
|---|
| 367 | } | 
|---|
| 368 |  | 
|---|
| 369 | void add(const Array &p_data) {} | 
|---|
| 370 |  | 
|---|
| 371 | void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) { | 
|---|
| 372 | Vector<RS::FrameProfileArea> profile_areas = RS::get_singleton()->get_frame_profile(); | 
|---|
| 373 | ServersDebugger::VisualProfilerFrame frame; | 
|---|
| 374 | if (!profile_areas.size()) { | 
|---|
| 375 | return; | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | frame.frame_number = RS::get_singleton()->get_frame_profile_frame(); | 
|---|
| 379 | frame.areas.append_array(profile_areas); | 
|---|
| 380 | EngineDebugger::get_singleton()->send_message( "visual:profile_frame", frame.serialize()); | 
|---|
| 381 | } | 
|---|
| 382 | }; | 
|---|
| 383 |  | 
|---|
| 384 | ServersDebugger *ServersDebugger::singleton = nullptr; | 
|---|
| 385 |  | 
|---|
| 386 | void ServersDebugger::initialize() { | 
|---|
| 387 | if (EngineDebugger::is_active()) { | 
|---|
| 388 | memnew(ServersDebugger); | 
|---|
| 389 | } | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | void ServersDebugger::deinitialize() { | 
|---|
| 393 | if (singleton) { | 
|---|
| 394 | memdelete(singleton); | 
|---|
| 395 | } | 
|---|
| 396 | } | 
|---|
| 397 |  | 
|---|
| 398 | Error ServersDebugger::_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) { | 
|---|
| 399 | ERR_FAIL_COND_V(!singleton, ERR_BUG); | 
|---|
| 400 | r_captured = true; | 
|---|
| 401 | if (p_cmd == "memory") { | 
|---|
| 402 | singleton->_send_resource_usage(); | 
|---|
| 403 | } else if (p_cmd == "draw") { // Forced redraw. | 
|---|
| 404 | // For camera override to stay live when the game is paused from the editor. | 
|---|
| 405 | double delta = 0.0; | 
|---|
| 406 | if (singleton->last_draw_time) { | 
|---|
| 407 | delta = (OS::get_singleton()->get_ticks_usec() - singleton->last_draw_time) / 1000000.0; | 
|---|
| 408 | } | 
|---|
| 409 | singleton->last_draw_time = OS::get_singleton()->get_ticks_usec(); | 
|---|
| 410 | RenderingServer::get_singleton()->sync(); | 
|---|
| 411 | if (RenderingServer::get_singleton()->has_changed()) { | 
|---|
| 412 | RenderingServer::get_singleton()->draw(true, delta); | 
|---|
| 413 | } | 
|---|
| 414 | EngineDebugger::get_singleton()->send_message( "servers:drawn", Array()); | 
|---|
| 415 | } else if (p_cmd == "foreground") { | 
|---|
| 416 | singleton->last_draw_time = 0.0; | 
|---|
| 417 | DisplayServer::get_singleton()->window_move_to_foreground(); | 
|---|
| 418 | singleton->servers_profiler->skip_frame(); | 
|---|
| 419 | } else { | 
|---|
| 420 | r_captured = false; | 
|---|
| 421 | } | 
|---|
| 422 | return OK; | 
|---|
| 423 | } | 
|---|
| 424 |  | 
|---|
| 425 | void ServersDebugger::_send_resource_usage() { | 
|---|
| 426 | ServersDebugger::ResourceUsage usage; | 
|---|
| 427 |  | 
|---|
| 428 | List<RS::TextureInfo> tinfo; | 
|---|
| 429 | RS::get_singleton()->texture_debug_usage(&tinfo); | 
|---|
| 430 |  | 
|---|
| 431 | for (const RS::TextureInfo &E : tinfo) { | 
|---|
| 432 | ServersDebugger::ResourceInfo info; | 
|---|
| 433 | info.path = E.path; | 
|---|
| 434 | info.vram = E.bytes; | 
|---|
| 435 | info.id = E.texture; | 
|---|
| 436 | info.type = "Texture"; | 
|---|
| 437 | if (E.depth == 0) { | 
|---|
| 438 | info.format = itos(E.width) + "x"+ itos(E.height) + " "+ Image::get_format_name(E.format); | 
|---|
| 439 | } else { | 
|---|
| 440 | info.format = itos(E.width) + "x"+ itos(E.height) + "x"+ itos(E.depth) + " "+ Image::get_format_name(E.format); | 
|---|
| 441 | } | 
|---|
| 442 | usage.infos.push_back(info); | 
|---|
| 443 | } | 
|---|
| 444 |  | 
|---|
| 445 | EngineDebugger::get_singleton()->send_message( "servers:memory_usage", usage.serialize()); | 
|---|
| 446 | } | 
|---|
| 447 |  | 
|---|
| 448 | ServersDebugger::ServersDebugger() { | 
|---|
| 449 | singleton = this; | 
|---|
| 450 |  | 
|---|
| 451 | // Generic servers profiler (audio/physics/...) | 
|---|
| 452 | servers_profiler.instantiate(); | 
|---|
| 453 | servers_profiler->bind( "servers"); | 
|---|
| 454 |  | 
|---|
| 455 | // Visual Profiler (cpu/gpu times) | 
|---|
| 456 | visual_profiler.instantiate(); | 
|---|
| 457 | visual_profiler->bind( "visual"); | 
|---|
| 458 |  | 
|---|
| 459 | EngineDebugger::Capture servers_cap(nullptr, &_capture); | 
|---|
| 460 | EngineDebugger::register_message_capture( "servers", servers_cap); | 
|---|
| 461 | } | 
|---|
| 462 |  | 
|---|
| 463 | ServersDebugger::~ServersDebugger() { | 
|---|
| 464 | EngineDebugger::unregister_message_capture( "servers"); | 
|---|
| 465 | singleton = nullptr; | 
|---|
| 466 | } | 
|---|
| 467 |  | 
|---|