└── addons
└── debug_menu
├── LICENSE.md
├── debug_menu.gd
├── debug_menu.tscn
├── plugin.cfg
└── plugin.gd
/addons/debug_menu/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright © 2023-present Hugo Locurcio and contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/addons/debug_menu/debug_menu.gd:
--------------------------------------------------------------------------------
1 | extends CanvasLayer
2 |
3 | @export var fps: Label
4 | @export var frame_time: Label
5 | @export var frame_number: Label
6 | @export var frame_history_total_avg: Label
7 | @export var frame_history_total_min: Label
8 | @export var frame_history_total_max: Label
9 | @export var frame_history_total_last: Label
10 | @export var frame_history_cpu_avg: Label
11 | @export var frame_history_cpu_min: Label
12 | @export var frame_history_cpu_max: Label
13 | @export var frame_history_cpu_last: Label
14 | @export var frame_history_gpu_avg: Label
15 | @export var frame_history_gpu_min: Label
16 | @export var frame_history_gpu_max: Label
17 | @export var frame_history_gpu_last: Label
18 | @export var fps_graph: Panel
19 | @export var total_graph: Panel
20 | @export var cpu_graph: Panel
21 | @export var gpu_graph: Panel
22 | @export var information: Label
23 | @export var settings: Label
24 |
25 | ## The number of frames to keep in history for graph drawing and best/worst calculations.
26 | ## Currently, this also affects how FPS is measured.
27 | const HISTORY_NUM_FRAMES = 150
28 |
29 | const GRAPH_SIZE = Vector2(150, 25)
30 | const GRAPH_MIN_FPS = 10
31 | const GRAPH_MAX_FPS = 160
32 | const GRAPH_MIN_FRAMETIME = 1.0 / GRAPH_MIN_FPS
33 | const GRAPH_MAX_FRAMETIME = 1.0 / GRAPH_MAX_FPS
34 |
35 | ## Debug menu display style.
36 | enum Style {
37 | HIDDEN, ## Debug menu is hidden.
38 | VISIBLE_COMPACT, ## Debug menu is visible, with only the FPS, FPS cap (if any) and time taken to render the last frame.
39 | VISIBLE_DETAILED, ## Debug menu is visible with full information, including graphs.
40 | MAX, ## Represents the size of the Style enum.
41 | }
42 |
43 | ## The style to use when drawing the debug menu.
44 | var style := Style.HIDDEN:
45 | set(value):
46 | style = value
47 | match style:
48 | Style.HIDDEN:
49 | visible = false
50 | Style.VISIBLE_COMPACT, Style.VISIBLE_DETAILED:
51 | visible = true
52 | frame_number.visible = style == Style.VISIBLE_DETAILED
53 | $DebugMenu/VBoxContainer/FrameTimeHistory.visible = style == Style.VISIBLE_DETAILED
54 | $DebugMenu/VBoxContainer/FPSGraph.visible = style == Style.VISIBLE_DETAILED
55 | $DebugMenu/VBoxContainer/TotalGraph.visible = style == Style.VISIBLE_DETAILED
56 | $DebugMenu/VBoxContainer/CPUGraph.visible = style == Style.VISIBLE_DETAILED
57 | $DebugMenu/VBoxContainer/GPUGraph.visible = style == Style.VISIBLE_DETAILED
58 | information.visible = style == Style.VISIBLE_DETAILED
59 | settings.visible = style == Style.VISIBLE_DETAILED
60 |
61 | # Value of `Time.get_ticks_usec()` on the previous frame.
62 | var last_tick := 0
63 |
64 | var thread := Thread.new()
65 |
66 | ## Returns the sum of all values of an array (use as a parameter to `Array.reduce()`).
67 | var sum_func := func avg(accum: float, number: float) -> float: return accum + number
68 |
69 | # History of the last `HISTORY_NUM_FRAMES` rendered frames.
70 | var frame_history_total: Array[float] = []
71 | var frame_history_cpu: Array[float] = []
72 | var frame_history_gpu: Array[float] = []
73 | var fps_history: Array[float] = [] # Only used for graphs.
74 |
75 | var frametime_avg := GRAPH_MIN_FRAMETIME
76 | var frametime_cpu_avg := GRAPH_MAX_FRAMETIME
77 | var frametime_gpu_avg := GRAPH_MIN_FRAMETIME
78 | var frames_per_second := float(GRAPH_MIN_FPS)
79 | var frame_time_gradient := Gradient.new()
80 |
81 | func _init() -> void:
82 | # This must be done here instead of `_ready()` to avoid having `visibility_changed` be emitted immediately.
83 | visible = false
84 |
85 | if not InputMap.has_action("cycle_debug_menu"):
86 | # Create default input action if no user-defined override exists.
87 | # We can't do it in the editor plugin's activation code as it doesn't seem to work there.
88 | InputMap.add_action("cycle_debug_menu")
89 | var event := InputEventKey.new()
90 | event.keycode = KEY_F3
91 | InputMap.action_add_event("cycle_debug_menu", event)
92 |
93 |
94 | func _ready() -> void:
95 | fps_graph.draw.connect(_fps_graph_draw)
96 | total_graph.draw.connect(_total_graph_draw)
97 | cpu_graph.draw.connect(_cpu_graph_draw)
98 | gpu_graph.draw.connect(_gpu_graph_draw)
99 |
100 | fps_history.resize(HISTORY_NUM_FRAMES)
101 | frame_history_total.resize(HISTORY_NUM_FRAMES)
102 | frame_history_cpu.resize(HISTORY_NUM_FRAMES)
103 | frame_history_gpu.resize(HISTORY_NUM_FRAMES)
104 |
105 | # NOTE: Both FPS and frametimes are colored following FPS logic
106 | # (red = 10 FPS, yellow = 60 FPS, green = 110 FPS, cyan = 160 FPS).
107 | # This makes the color gradient non-linear.
108 | # Colors are taken from .
109 | frame_time_gradient.set_color(0, Color8(239, 68, 68)) # red-500
110 | frame_time_gradient.set_color(1, Color8(56, 189, 248)) # light-blue-400
111 | frame_time_gradient.add_point(0.3333, Color8(250, 204, 21)) # yellow-400
112 | frame_time_gradient.add_point(0.6667, Color8(128, 226, 95)) # 50-50 mix of lime-400 and green-400
113 |
114 | get_viewport().size_changed.connect(update_settings_label)
115 |
116 | # Display loading text while information is being queried,
117 | # in case the user toggles the full debug menu just after starting the project.
118 | information.text = "Loading hardware information...\n\n "
119 | settings.text = "Loading project information..."
120 | thread.start(
121 | func():
122 | # Disable thread safety checks as they interfere with this add-on.
123 | # This only affects this particular thread, not other thread instances in the project.
124 | # See for details.
125 | # Use a Callable so that this can be ignored on Godot 4.0 without causing a script error
126 | # (thread safety checks were added in Godot 4.1).
127 | if Engine.get_version_info()["hex"] >= 0x040100:
128 | Callable(Thread, "set_thread_safety_checks_enabled").call(false)
129 |
130 | # Enable required time measurements to display CPU/GPU frame time information.
131 | # These lines are time-consuming operations, so run them in a separate thread.
132 | RenderingServer.viewport_set_measure_render_time(get_viewport().get_viewport_rid(), true)
133 | update_information_label()
134 | update_settings_label()
135 | )
136 |
137 |
138 | func _input(event: InputEvent) -> void:
139 | if event.is_action_pressed("cycle_debug_menu"):
140 | style = wrapi(style + 1, 0, Style.MAX) as Style
141 |
142 |
143 | func _exit_tree() -> void:
144 | thread.wait_to_finish()
145 |
146 |
147 | ## Update hardware information label (this can change at runtime based on window
148 | ## size and graphics settings). This is only called when the window is resized.
149 | ## To update when graphics settings are changed, the function must be called manually
150 | ## using `DebugMenu.update_settings_label()`.
151 | func update_settings_label() -> void:
152 | settings.text = ""
153 | if ProjectSettings.has_setting("application/config/version"):
154 | settings.text += "Project Version: %s\n" % ProjectSettings.get_setting("application/config/version")
155 |
156 | var rendering_method := str(ProjectSettings.get_setting_with_override("rendering/renderer/rendering_method"))
157 | var rendering_method_string := rendering_method
158 | match rendering_method:
159 | "forward_plus":
160 | rendering_method_string = "Forward+"
161 | "mobile":
162 | rendering_method_string = "Forward Mobile"
163 | "gl_compatibility":
164 | rendering_method_string = "Compatibility"
165 | settings.text += "Rendering Method: %s\n" % rendering_method_string
166 |
167 | var viewport := get_viewport()
168 |
169 | # The size of the viewport rendering, which determines which resolution 3D is rendered at.
170 | var viewport_render_size := Vector2i()
171 |
172 | if viewport.content_scale_mode == Window.CONTENT_SCALE_MODE_VIEWPORT:
173 | viewport_render_size = viewport.get_visible_rect().size
174 | settings.text += "Viewport: %d×%d, Window: %d×%d\n" % [viewport.get_visible_rect().size.x, viewport.get_visible_rect().size.y, viewport.size.x, viewport.size.y]
175 | else:
176 | # Window size matches viewport size.
177 | viewport_render_size = viewport.size
178 | settings.text += "Viewport: %d×%d\n" % [viewport.size.x, viewport.size.y]
179 |
180 | # Display 3D settings only if relevant.
181 | if viewport.get_camera_3d():
182 | var scaling_3d_mode_string := "(unknown)"
183 | match viewport.scaling_3d_mode:
184 | Viewport.SCALING_3D_MODE_BILINEAR:
185 | scaling_3d_mode_string = "Bilinear"
186 | Viewport.SCALING_3D_MODE_FSR:
187 | scaling_3d_mode_string = "FSR 1.0"
188 | Viewport.SCALING_3D_MODE_FSR2:
189 | scaling_3d_mode_string = "FSR 2.2"
190 |
191 | var antialiasing_3d_string := ""
192 | if viewport.scaling_3d_mode == Viewport.SCALING_3D_MODE_FSR2:
193 | # The FSR2 scaling mode includes its own temporal antialiasing implementation.
194 | antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "FSR 2.2"
195 | if viewport.scaling_3d_mode != Viewport.SCALING_3D_MODE_FSR2 and viewport.use_taa:
196 | # Godot's own TAA is ignored when using FSR2 scaling mode, as FSR2 provides its own TAA implementation.
197 | antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "TAA"
198 | if viewport.msaa_3d >= Viewport.MSAA_2X:
199 | antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "%d× MSAA" % pow(2, viewport.msaa_3d)
200 | if viewport.screen_space_aa == Viewport.SCREEN_SPACE_AA_FXAA:
201 | antialiasing_3d_string += (" + " if not antialiasing_3d_string.is_empty() else "") + "FXAA"
202 |
203 | settings.text += "3D scale (%s): %d%% = %d×%d" % [
204 | scaling_3d_mode_string,
205 | viewport.scaling_3d_scale * 100,
206 | viewport_render_size.x * viewport.scaling_3d_scale,
207 | viewport_render_size.y * viewport.scaling_3d_scale,
208 | ]
209 |
210 | if not antialiasing_3d_string.is_empty():
211 | settings.text += "\n3D Antialiasing: %s" % antialiasing_3d_string
212 |
213 | var environment := viewport.get_camera_3d().get_world_3d().environment
214 | if environment:
215 | if environment.ssr_enabled:
216 | settings.text += "\nSSR: %d Steps" % environment.ssr_max_steps
217 |
218 | if environment.ssao_enabled:
219 | settings.text += "\nSSAO: On"
220 | if environment.ssil_enabled:
221 | settings.text += "\nSSIL: On"
222 |
223 | if environment.sdfgi_enabled:
224 | settings.text += "\nSDFGI: %d Cascades" % environment.sdfgi_cascades
225 |
226 | if environment.glow_enabled:
227 | settings.text += "\nGlow: On"
228 |
229 | if environment.volumetric_fog_enabled:
230 | settings.text += "\nVolumetric Fog: On"
231 | var antialiasing_2d_string := ""
232 | if viewport.msaa_2d >= Viewport.MSAA_2X:
233 | antialiasing_2d_string = "%d× MSAA" % pow(2, viewport.msaa_2d)
234 |
235 | if not antialiasing_2d_string.is_empty():
236 | settings.text += "\n2D Antialiasing: %s" % antialiasing_2d_string
237 |
238 |
239 | ## Update hardware/software information label (this never changes at runtime).
240 | func update_information_label() -> void:
241 | var adapter_string := ""
242 | # Make "NVIDIA Corporation" and "NVIDIA" be considered identical (required when using OpenGL to avoid redundancy).
243 | if RenderingServer.get_video_adapter_vendor().trim_suffix(" Corporation") in RenderingServer.get_video_adapter_name():
244 | # Avoid repeating vendor name before adapter name.
245 | # Trim redundant suffix sometimes reported by NVIDIA graphics cards when using OpenGL.
246 | adapter_string = RenderingServer.get_video_adapter_name().trim_suffix("/PCIe/SSE2")
247 | else:
248 | adapter_string = RenderingServer.get_video_adapter_vendor() + " - " + RenderingServer.get_video_adapter_name().trim_suffix("/PCIe/SSE2")
249 |
250 | # Graphics driver version information isn't always availble.
251 | var driver_info := OS.get_video_adapter_driver_info()
252 | var driver_info_string := ""
253 | if driver_info.size() >= 2:
254 | driver_info_string = driver_info[1]
255 | else:
256 | driver_info_string = "(unknown)"
257 |
258 | var release_string := ""
259 | if OS.has_feature("editor"):
260 | # Editor build (implies `debug`).
261 | release_string = "editor"
262 | elif OS.has_feature("debug"):
263 | # Debug export template build.
264 | release_string = "debug"
265 | else:
266 | # Release export template build.
267 | release_string = "release"
268 |
269 | var rendering_method := str(ProjectSettings.get_setting_with_override("rendering/renderer/rendering_method"))
270 | var rendering_driver := str(ProjectSettings.get_setting_with_override("rendering/rendering_device/driver"))
271 | var graphics_api_string := rendering_driver
272 | if rendering_method != "gl_compatibility":
273 | if rendering_driver == "d3d12":
274 | graphics_api_string = "Direct3D 12"
275 | elif rendering_driver == "metal":
276 | graphics_api_string = "Metal"
277 | elif rendering_driver == "vulkan":
278 | if OS.has_feature("macos") or OS.has_feature("ios"):
279 | graphics_api_string = "Vulkan via MoltenVK"
280 | else:
281 | graphics_api_string = "Vulkan"
282 | else:
283 | if rendering_driver == "opengl3_angle":
284 | graphics_api_string = "OpenGL via ANGLE"
285 | elif OS.has_feature("mobile") or rendering_driver == "opengl3_es":
286 | graphics_api_string = "OpenGL ES"
287 | elif OS.has_feature("web"):
288 | graphics_api_string = "WebGL"
289 | elif rendering_driver == "opengl3":
290 | graphics_api_string = "OpenGL"
291 |
292 | information.text = (
293 | "%s, %d threads\n" % [OS.get_processor_name().replace("(R)", "").replace("(TM)", ""), OS.get_processor_count()]
294 | + "%s %s (%s %s), %s %s\n" % [OS.get_name(), "64-bit" if OS.has_feature("64") else "32-bit", release_string, "double" if OS.has_feature("double") else "single", graphics_api_string, RenderingServer.get_video_adapter_api_version()]
295 | + "%s, %s" % [adapter_string, driver_info_string]
296 | )
297 |
298 |
299 | func _fps_graph_draw() -> void:
300 | var fps_polyline := PackedVector2Array()
301 | fps_polyline.resize(HISTORY_NUM_FRAMES)
302 | for fps_index in fps_history.size():
303 | fps_polyline[fps_index] = Vector2(
304 | remap(fps_index, 0, fps_history.size(), 0, GRAPH_SIZE.x),
305 | remap(clampf(fps_history[fps_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
306 | )
307 | # Don't use antialiasing to speed up line drawing, but use a width that scales with
308 | # viewport scale to keep the line easily readable on hiDPI displays.
309 | fps_graph.draw_polyline(fps_polyline, frame_time_gradient.sample(remap(frames_per_second, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
310 |
311 |
312 | func _total_graph_draw() -> void:
313 | var total_polyline := PackedVector2Array()
314 | total_polyline.resize(HISTORY_NUM_FRAMES)
315 | for total_index in frame_history_total.size():
316 | total_polyline[total_index] = Vector2(
317 | remap(total_index, 0, frame_history_total.size(), 0, GRAPH_SIZE.x),
318 | remap(clampf(frame_history_total[total_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
319 | )
320 | # Don't use antialiasing to speed up line drawing, but use a width that scales with
321 | # viewport scale to keep the line easily readable on hiDPI displays.
322 | total_graph.draw_polyline(total_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
323 |
324 |
325 | func _cpu_graph_draw() -> void:
326 | var cpu_polyline := PackedVector2Array()
327 | cpu_polyline.resize(HISTORY_NUM_FRAMES)
328 | for cpu_index in frame_history_cpu.size():
329 | cpu_polyline[cpu_index] = Vector2(
330 | remap(cpu_index, 0, frame_history_cpu.size(), 0, GRAPH_SIZE.x),
331 | remap(clampf(frame_history_cpu[cpu_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
332 | )
333 | # Don't use antialiasing to speed up line drawing, but use a width that scales with
334 | # viewport scale to keep the line easily readable on hiDPI displays.
335 | cpu_graph.draw_polyline(cpu_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_cpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
336 |
337 |
338 | func _gpu_graph_draw() -> void:
339 | var gpu_polyline := PackedVector2Array()
340 | gpu_polyline.resize(HISTORY_NUM_FRAMES)
341 | for gpu_index in frame_history_gpu.size():
342 | gpu_polyline[gpu_index] = Vector2(
343 | remap(gpu_index, 0, frame_history_gpu.size(), 0, GRAPH_SIZE.x),
344 | remap(clampf(frame_history_gpu[gpu_index], GRAPH_MIN_FPS, GRAPH_MAX_FPS), GRAPH_MIN_FPS, GRAPH_MAX_FPS, GRAPH_SIZE.y, 0.0)
345 | )
346 | # Don't use antialiasing to speed up line drawing, but use a width that scales with
347 | # viewport scale to keep the line easily readable on hiDPI displays.
348 | gpu_graph.draw_polyline(gpu_polyline, frame_time_gradient.sample(remap(1000.0 / frametime_gpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0)), 1.0)
349 |
350 |
351 | func _process(_delta: float) -> void:
352 | if visible:
353 | fps_graph.queue_redraw()
354 | total_graph.queue_redraw()
355 | cpu_graph.queue_redraw()
356 | gpu_graph.queue_redraw()
357 |
358 | # Difference between the last two rendered frames in milliseconds.
359 | var frametime := (Time.get_ticks_usec() - last_tick) * 0.001
360 |
361 | frame_history_total.push_back(frametime)
362 | if frame_history_total.size() > HISTORY_NUM_FRAMES:
363 | frame_history_total.pop_front()
364 |
365 | # Frametimes are colored following FPS logic (red = 10 FPS, yellow = 60 FPS, green = 110 FPS, cyan = 160 FPS).
366 | # This makes the color gradient non-linear.
367 | frametime_avg = frame_history_total.reduce(sum_func) / frame_history_total.size()
368 | frame_history_total_avg.text = str(frametime_avg).pad_decimals(2)
369 | frame_history_total_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
370 |
371 | var frametime_min: float = frame_history_total.min()
372 | frame_history_total_min.text = str(frametime_min).pad_decimals(2)
373 | frame_history_total_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
374 |
375 | var frametime_max: float = frame_history_total.max()
376 | frame_history_total_max.text = str(frametime_max).pad_decimals(2)
377 | frame_history_total_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
378 |
379 | frame_history_total_last.text = str(frametime).pad_decimals(2)
380 | frame_history_total_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
381 |
382 | var viewport_rid := get_viewport().get_viewport_rid()
383 | var frametime_cpu := RenderingServer.viewport_get_measured_render_time_cpu(viewport_rid) + RenderingServer.get_frame_setup_time_cpu()
384 | frame_history_cpu.push_back(frametime_cpu)
385 | if frame_history_cpu.size() > HISTORY_NUM_FRAMES:
386 | frame_history_cpu.pop_front()
387 |
388 | frametime_cpu_avg = frame_history_cpu.reduce(sum_func) / frame_history_cpu.size()
389 | frame_history_cpu_avg.text = str(frametime_cpu_avg).pad_decimals(2)
390 | frame_history_cpu_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
391 |
392 | var frametime_cpu_min: float = frame_history_cpu.min()
393 | frame_history_cpu_min.text = str(frametime_cpu_min).pad_decimals(2)
394 | frame_history_cpu_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
395 |
396 | var frametime_cpu_max: float = frame_history_cpu.max()
397 | frame_history_cpu_max.text = str(frametime_cpu_max).pad_decimals(2)
398 | frame_history_cpu_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
399 |
400 | frame_history_cpu_last.text = str(frametime_cpu).pad_decimals(2)
401 | frame_history_cpu_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_cpu, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
402 |
403 | var frametime_gpu := RenderingServer.viewport_get_measured_render_time_gpu(viewport_rid)
404 | frame_history_gpu.push_back(frametime_gpu)
405 | if frame_history_gpu.size() > HISTORY_NUM_FRAMES:
406 | frame_history_gpu.pop_front()
407 |
408 | frametime_gpu_avg = frame_history_gpu.reduce(sum_func) / frame_history_gpu.size()
409 | frame_history_gpu_avg.text = str(frametime_gpu_avg).pad_decimals(2)
410 | frame_history_gpu_avg.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_avg, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
411 |
412 | var frametime_gpu_min: float = frame_history_gpu.min()
413 | frame_history_gpu_min.text = str(frametime_gpu_min).pad_decimals(2)
414 | frame_history_gpu_min.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_min, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
415 |
416 | var frametime_gpu_max: float = frame_history_gpu.max()
417 | frame_history_gpu_max.text = str(frametime_gpu_max).pad_decimals(2)
418 | frame_history_gpu_max.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu_max, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
419 |
420 | frame_history_gpu_last.text = str(frametime_gpu).pad_decimals(2)
421 | frame_history_gpu_last.modulate = frame_time_gradient.sample(remap(1000.0 / frametime_gpu, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
422 |
423 | frames_per_second = 1000.0 / frametime_avg
424 | fps_history.push_back(frames_per_second)
425 | if fps_history.size() > HISTORY_NUM_FRAMES:
426 | fps_history.pop_front()
427 |
428 | fps.text = str(floor(frames_per_second)) + " FPS"
429 | var frame_time_color := frame_time_gradient.sample(remap(frames_per_second, GRAPH_MIN_FPS, GRAPH_MAX_FPS, 0.0, 1.0))
430 | fps.modulate = frame_time_color
431 |
432 | frame_time.text = str(frametime).pad_decimals(2) + " mspf"
433 | frame_time.modulate = frame_time_color
434 |
435 | var vsync_string := ""
436 | match DisplayServer.window_get_vsync_mode():
437 | DisplayServer.VSYNC_ENABLED:
438 | vsync_string = "V-Sync"
439 | DisplayServer.VSYNC_ADAPTIVE:
440 | vsync_string = "Adaptive V-Sync"
441 | DisplayServer.VSYNC_MAILBOX:
442 | vsync_string = "Mailbox V-Sync"
443 |
444 | if Engine.max_fps > 0 or OS.low_processor_usage_mode:
445 | # Display FPS cap determined by `Engine.max_fps` or low-processor usage mode sleep duration
446 | # (the lowest FPS cap is used).
447 | var low_processor_max_fps := roundi(1000000.0 / OS.low_processor_usage_mode_sleep_usec)
448 | var fps_cap := low_processor_max_fps
449 | if Engine.max_fps > 0:
450 | fps_cap = mini(Engine.max_fps, low_processor_max_fps)
451 | frame_time.text += " (cap: " + str(fps_cap) + " FPS"
452 |
453 | if not vsync_string.is_empty():
454 | frame_time.text += " + " + vsync_string
455 |
456 | frame_time.text += ")"
457 | else:
458 | if not vsync_string.is_empty():
459 | frame_time.text += " (" + vsync_string + ")"
460 |
461 | frame_number.text = "Frame: " + str(Engine.get_frames_drawn())
462 |
463 | last_tick = Time.get_ticks_usec()
464 |
465 |
466 | func _on_visibility_changed() -> void:
467 | if visible:
468 | # Reset graphs to prevent them from looking strange before `HISTORY_NUM_FRAMES` frames
469 | # have been drawn.
470 | var frametime_last := (Time.get_ticks_usec() - last_tick) * 0.001
471 | fps_history.resize(HISTORY_NUM_FRAMES)
472 | fps_history.fill(1000.0 / frametime_last)
473 | frame_history_total.resize(HISTORY_NUM_FRAMES)
474 | frame_history_total.fill(frametime_last)
475 | frame_history_cpu.resize(HISTORY_NUM_FRAMES)
476 | var viewport_rid := get_viewport().get_viewport_rid()
477 | frame_history_cpu.fill(RenderingServer.viewport_get_measured_render_time_cpu(viewport_rid) + RenderingServer.get_frame_setup_time_cpu())
478 | frame_history_gpu.resize(HISTORY_NUM_FRAMES)
479 | frame_history_gpu.fill(RenderingServer.viewport_get_measured_render_time_gpu(viewport_rid))
480 |
--------------------------------------------------------------------------------
/addons/debug_menu/debug_menu.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://cggqb75a8w8r"]
2 |
3 | [ext_resource type="Script" path="res://addons/debug_menu/debug_menu.gd" id="1_p440y"]
4 |
5 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ki0n8"]
6 | bg_color = Color(0, 0, 0, 0.25098)
7 |
8 | [node name="CanvasLayer" type="CanvasLayer" node_paths=PackedStringArray("fps", "frame_time", "frame_number", "frame_history_total_avg", "frame_history_total_min", "frame_history_total_max", "frame_history_total_last", "frame_history_cpu_avg", "frame_history_cpu_min", "frame_history_cpu_max", "frame_history_cpu_last", "frame_history_gpu_avg", "frame_history_gpu_min", "frame_history_gpu_max", "frame_history_gpu_last", "fps_graph", "total_graph", "cpu_graph", "gpu_graph", "information", "settings")]
9 | process_mode = 3
10 | layer = 128
11 | script = ExtResource("1_p440y")
12 | fps = NodePath("DebugMenu/VBoxContainer/FPS")
13 | frame_time = NodePath("DebugMenu/VBoxContainer/FrameTime")
14 | frame_number = NodePath("DebugMenu/VBoxContainer/FrameNumber")
15 | frame_history_total_avg = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/TotalAvg")
16 | frame_history_total_min = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/TotalMin")
17 | frame_history_total_max = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/TotalMax")
18 | frame_history_total_last = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/TotalLast")
19 | frame_history_cpu_avg = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/CPUAvg")
20 | frame_history_cpu_min = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/CPUMin")
21 | frame_history_cpu_max = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/CPUMax")
22 | frame_history_cpu_last = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/CPULast")
23 | frame_history_gpu_avg = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/GPUAvg")
24 | frame_history_gpu_min = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/GPUMin")
25 | frame_history_gpu_max = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/GPUMax")
26 | frame_history_gpu_last = NodePath("DebugMenu/VBoxContainer/FrameTimeHistory/GPULast")
27 | fps_graph = NodePath("DebugMenu/VBoxContainer/FPSGraph/Graph")
28 | total_graph = NodePath("DebugMenu/VBoxContainer/TotalGraph/Graph")
29 | cpu_graph = NodePath("DebugMenu/VBoxContainer/CPUGraph/Graph")
30 | gpu_graph = NodePath("DebugMenu/VBoxContainer/GPUGraph/Graph")
31 | information = NodePath("DebugMenu/VBoxContainer/Information")
32 | settings = NodePath("DebugMenu/VBoxContainer/Settings")
33 |
34 | [node name="DebugMenu" type="Control" parent="."]
35 | custom_minimum_size = Vector2(400, 400)
36 | layout_mode = 3
37 | anchors_preset = 1
38 | anchor_left = 1.0
39 | anchor_right = 1.0
40 | offset_left = -416.0
41 | offset_top = 8.0
42 | offset_right = -16.0
43 | offset_bottom = 408.0
44 | grow_horizontal = 0
45 | size_flags_horizontal = 8
46 | size_flags_vertical = 4
47 | mouse_filter = 2
48 |
49 | [node name="VBoxContainer" type="VBoxContainer" parent="DebugMenu"]
50 | layout_mode = 1
51 | anchors_preset = 1
52 | anchor_left = 1.0
53 | anchor_right = 1.0
54 | offset_left = -300.0
55 | offset_bottom = 374.0
56 | grow_horizontal = 0
57 | mouse_filter = 2
58 | theme_override_constants/separation = 0
59 |
60 | [node name="FPS" type="Label" parent="DebugMenu/VBoxContainer"]
61 | modulate = Color(0, 1, 0, 1)
62 | layout_mode = 2
63 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
64 | theme_override_constants/outline_size = 5
65 | theme_override_constants/line_spacing = 0
66 | theme_override_font_sizes/font_size = 18
67 | text = "60 FPS"
68 | horizontal_alignment = 2
69 |
70 | [node name="FrameTime" type="Label" parent="DebugMenu/VBoxContainer"]
71 | modulate = Color(0, 1, 0, 1)
72 | layout_mode = 2
73 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
74 | theme_override_constants/outline_size = 3
75 | theme_override_font_sizes/font_size = 12
76 | text = "16.67 mspf (cap: 123 FPS + Adaptive V-Sync)"
77 | horizontal_alignment = 2
78 |
79 | [node name="FrameNumber" type="Label" parent="DebugMenu/VBoxContainer"]
80 | layout_mode = 2
81 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
82 | theme_override_constants/outline_size = 3
83 | theme_override_font_sizes/font_size = 12
84 | text = "Frame: 1234"
85 | horizontal_alignment = 2
86 |
87 | [node name="FrameTimeHistory" type="GridContainer" parent="DebugMenu/VBoxContainer"]
88 | layout_mode = 2
89 | size_flags_horizontal = 8
90 | mouse_filter = 2
91 | theme_override_constants/h_separation = 0
92 | theme_override_constants/v_separation = 0
93 | columns = 5
94 |
95 | [node name="Spacer" type="Control" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
96 | custom_minimum_size = Vector2(60, 0)
97 | layout_mode = 2
98 | mouse_filter = 2
99 |
100 | [node name="AvgHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
101 | custom_minimum_size = Vector2(50, 0)
102 | layout_mode = 2
103 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
104 | theme_override_constants/outline_size = 3
105 | theme_override_font_sizes/font_size = 12
106 | text = "Average"
107 | horizontal_alignment = 2
108 |
109 | [node name="MinHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
110 | custom_minimum_size = Vector2(50, 0)
111 | layout_mode = 2
112 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
113 | theme_override_constants/outline_size = 3
114 | theme_override_font_sizes/font_size = 12
115 | text = "Best"
116 | horizontal_alignment = 2
117 |
118 | [node name="MaxHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
119 | custom_minimum_size = Vector2(50, 0)
120 | layout_mode = 2
121 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
122 | theme_override_constants/outline_size = 3
123 | theme_override_font_sizes/font_size = 12
124 | text = "Worst"
125 | horizontal_alignment = 2
126 |
127 | [node name="LastHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
128 | custom_minimum_size = Vector2(50, 0)
129 | layout_mode = 2
130 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
131 | theme_override_constants/outline_size = 3
132 | theme_override_font_sizes/font_size = 12
133 | text = "Last"
134 | horizontal_alignment = 2
135 |
136 | [node name="TotalHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
137 | custom_minimum_size = Vector2(50, 0)
138 | layout_mode = 2
139 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
140 | theme_override_constants/outline_size = 3
141 | theme_override_font_sizes/font_size = 12
142 | text = "Total:"
143 | horizontal_alignment = 2
144 |
145 | [node name="TotalAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
146 | modulate = Color(0, 1, 0, 1)
147 | custom_minimum_size = Vector2(50, 0)
148 | layout_mode = 2
149 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
150 | theme_override_constants/outline_size = 3
151 | theme_override_font_sizes/font_size = 12
152 | text = "123.45"
153 | horizontal_alignment = 2
154 |
155 | [node name="TotalMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
156 | modulate = Color(0, 1, 0, 1)
157 | custom_minimum_size = Vector2(50, 0)
158 | layout_mode = 2
159 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
160 | theme_override_constants/outline_size = 3
161 | theme_override_font_sizes/font_size = 12
162 | text = "123.45"
163 | horizontal_alignment = 2
164 |
165 | [node name="TotalMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
166 | modulate = Color(0, 1, 0, 1)
167 | custom_minimum_size = Vector2(50, 0)
168 | layout_mode = 2
169 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
170 | theme_override_constants/outline_size = 3
171 | theme_override_font_sizes/font_size = 12
172 | text = "123.45"
173 | horizontal_alignment = 2
174 |
175 | [node name="TotalLast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
176 | modulate = Color(0, 1, 0, 1)
177 | custom_minimum_size = Vector2(50, 0)
178 | layout_mode = 2
179 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
180 | theme_override_constants/outline_size = 3
181 | theme_override_font_sizes/font_size = 12
182 | text = "123.45"
183 | horizontal_alignment = 2
184 |
185 | [node name="CPUHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
186 | custom_minimum_size = Vector2(50, 0)
187 | layout_mode = 2
188 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
189 | theme_override_constants/outline_size = 3
190 | theme_override_font_sizes/font_size = 12
191 | text = "CPU:"
192 | horizontal_alignment = 2
193 |
194 | [node name="CPUAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
195 | modulate = Color(0, 1, 0, 1)
196 | custom_minimum_size = Vector2(50, 0)
197 | layout_mode = 2
198 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
199 | theme_override_constants/outline_size = 3
200 | theme_override_font_sizes/font_size = 12
201 | text = "123.45"
202 | horizontal_alignment = 2
203 |
204 | [node name="CPUMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
205 | modulate = Color(0, 1, 0, 1)
206 | custom_minimum_size = Vector2(50, 0)
207 | layout_mode = 2
208 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
209 | theme_override_constants/outline_size = 3
210 | theme_override_font_sizes/font_size = 12
211 | text = "12.34"
212 | horizontal_alignment = 2
213 |
214 | [node name="CPUMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
215 | modulate = Color(0, 1, 0, 1)
216 | custom_minimum_size = Vector2(50, 0)
217 | layout_mode = 2
218 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
219 | theme_override_constants/outline_size = 3
220 | theme_override_font_sizes/font_size = 12
221 | text = "123.45"
222 | horizontal_alignment = 2
223 |
224 | [node name="CPULast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
225 | modulate = Color(0, 1, 0, 1)
226 | custom_minimum_size = Vector2(50, 0)
227 | layout_mode = 2
228 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
229 | theme_override_constants/outline_size = 3
230 | theme_override_font_sizes/font_size = 12
231 | text = "123.45"
232 | horizontal_alignment = 2
233 |
234 | [node name="GPUHeader" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
235 | custom_minimum_size = Vector2(50, 0)
236 | layout_mode = 2
237 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
238 | theme_override_constants/outline_size = 3
239 | theme_override_font_sizes/font_size = 12
240 | text = "GPU:"
241 | horizontal_alignment = 2
242 |
243 | [node name="GPUAvg" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
244 | modulate = Color(0, 1, 0, 1)
245 | custom_minimum_size = Vector2(50, 0)
246 | layout_mode = 2
247 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
248 | theme_override_constants/outline_size = 3
249 | theme_override_font_sizes/font_size = 12
250 | text = "123.45"
251 | horizontal_alignment = 2
252 |
253 | [node name="GPUMin" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
254 | modulate = Color(0, 1, 0, 1)
255 | custom_minimum_size = Vector2(50, 0)
256 | layout_mode = 2
257 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
258 | theme_override_constants/outline_size = 3
259 | theme_override_font_sizes/font_size = 12
260 | text = "1.23"
261 | horizontal_alignment = 2
262 |
263 | [node name="GPUMax" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
264 | modulate = Color(0, 1, 0, 1)
265 | custom_minimum_size = Vector2(50, 0)
266 | layout_mode = 2
267 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
268 | theme_override_constants/outline_size = 3
269 | theme_override_font_sizes/font_size = 12
270 | text = "123.45"
271 | horizontal_alignment = 2
272 |
273 | [node name="GPULast" type="Label" parent="DebugMenu/VBoxContainer/FrameTimeHistory"]
274 | modulate = Color(0, 1, 0, 1)
275 | custom_minimum_size = Vector2(50, 0)
276 | layout_mode = 2
277 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
278 | theme_override_constants/outline_size = 3
279 | theme_override_font_sizes/font_size = 12
280 | text = "123.45"
281 | horizontal_alignment = 2
282 |
283 | [node name="FPSGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
284 | layout_mode = 2
285 | mouse_filter = 2
286 | alignment = 2
287 |
288 | [node name="Title" type="Label" parent="DebugMenu/VBoxContainer/FPSGraph"]
289 | custom_minimum_size = Vector2(0, 27)
290 | layout_mode = 2
291 | size_flags_horizontal = 8
292 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
293 | theme_override_constants/outline_size = 3
294 | theme_override_font_sizes/font_size = 12
295 | text = "FPS: ↑"
296 | vertical_alignment = 1
297 |
298 | [node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/FPSGraph"]
299 | custom_minimum_size = Vector2(150, 25)
300 | layout_mode = 2
301 | size_flags_vertical = 0
302 | mouse_filter = 2
303 | theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
304 |
305 | [node name="TotalGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
306 | layout_mode = 2
307 | mouse_filter = 2
308 | alignment = 2
309 |
310 | [node name="Title" type="Label" parent="DebugMenu/VBoxContainer/TotalGraph"]
311 | custom_minimum_size = Vector2(0, 27)
312 | layout_mode = 2
313 | size_flags_horizontal = 8
314 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
315 | theme_override_constants/outline_size = 3
316 | theme_override_font_sizes/font_size = 12
317 | text = "Total: ↓"
318 | vertical_alignment = 1
319 |
320 | [node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/TotalGraph"]
321 | custom_minimum_size = Vector2(150, 25)
322 | layout_mode = 2
323 | size_flags_vertical = 0
324 | mouse_filter = 2
325 | theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
326 |
327 | [node name="CPUGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
328 | layout_mode = 2
329 | mouse_filter = 2
330 | alignment = 2
331 |
332 | [node name="Title" type="Label" parent="DebugMenu/VBoxContainer/CPUGraph"]
333 | custom_minimum_size = Vector2(0, 27)
334 | layout_mode = 2
335 | size_flags_horizontal = 8
336 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
337 | theme_override_constants/outline_size = 3
338 | theme_override_font_sizes/font_size = 12
339 | text = "CPU: ↓"
340 | vertical_alignment = 1
341 |
342 | [node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/CPUGraph"]
343 | custom_minimum_size = Vector2(150, 25)
344 | layout_mode = 2
345 | size_flags_vertical = 0
346 | mouse_filter = 2
347 | theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
348 |
349 | [node name="GPUGraph" type="HBoxContainer" parent="DebugMenu/VBoxContainer"]
350 | layout_mode = 2
351 | mouse_filter = 2
352 | alignment = 2
353 |
354 | [node name="Title" type="Label" parent="DebugMenu/VBoxContainer/GPUGraph"]
355 | custom_minimum_size = Vector2(0, 27)
356 | layout_mode = 2
357 | size_flags_horizontal = 8
358 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
359 | theme_override_constants/outline_size = 3
360 | theme_override_font_sizes/font_size = 12
361 | text = "GPU: ↓"
362 | vertical_alignment = 1
363 |
364 | [node name="Graph" type="Panel" parent="DebugMenu/VBoxContainer/GPUGraph"]
365 | custom_minimum_size = Vector2(150, 25)
366 | layout_mode = 2
367 | size_flags_vertical = 0
368 | mouse_filter = 2
369 | theme_override_styles/panel = SubResource("StyleBoxFlat_ki0n8")
370 |
371 | [node name="Information" type="Label" parent="DebugMenu/VBoxContainer"]
372 | modulate = Color(1, 1, 1, 0.752941)
373 | layout_mode = 2
374 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
375 | theme_override_constants/outline_size = 3
376 | theme_override_font_sizes/font_size = 12
377 | text = "12th Gen Intel(R) Core(TM) i0-1234K
378 | Windows 12 64-bit (double precision), Vulkan 1.2.34
379 | NVIDIA GeForce RTX 1234, 123.45.67"
380 | horizontal_alignment = 2
381 |
382 | [node name="Settings" type="Label" parent="DebugMenu/VBoxContainer"]
383 | modulate = Color(0.8, 0.84, 1, 0.752941)
384 | layout_mode = 2
385 | theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
386 | theme_override_constants/outline_size = 3
387 | theme_override_font_sizes/font_size = 12
388 | text = "Project Version: 1.2.3
389 | Rendering Method: Forward+
390 | Window: 1234×567, Viewport: 1234×567
391 | 3D Scale (FSR 1.0): 100% = 1234×567
392 | 3D Antialiasing: TAA + 2× MSAA + FXAA
393 | SSR: 123 Steps
394 | SSAO: On
395 | SSIL: On
396 | SDFGI: 1 Cascades
397 | Glow: On
398 | Volumetric Fog: On
399 | 2D Antialiasing: 2× MSAA"
400 | horizontal_alignment = 2
401 |
402 | [connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
403 |
--------------------------------------------------------------------------------
/addons/debug_menu/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="Debug Menu"
4 | description="In-game debug menu displaying performance metrics and hardware information"
5 | author="Calinou"
6 | version="1.2.0"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/debug_menu/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 |
4 | func _enter_tree() -> void:
5 | if not ProjectSettings.has_setting("autoload/DebugMenu"):
6 | add_autoload_singleton("DebugMenu", "res://addons/debug_menu/debug_menu.tscn")
7 |
8 | if not ProjectSettings.has_setting("application/config/version") or ProjectSettings.get_setting("application/config/version") == "":
9 | ProjectSettings.set_setting("application/config/version", "1.0.0")
10 | print('Debug Menu: Setting "application/config/version" was missing or empty and has been set to "1.0.0".')
11 |
12 | ProjectSettings.add_property_info({
13 | name = "application/config/version",
14 | type = TYPE_STRING,
15 | })
16 |
17 | ProjectSettings.save()
18 |
19 |
20 | func _exit_tree() -> void:
21 | remove_autoload_singleton("DebugMenu")
22 | # Don't remove the project setting's value and input map action,
23 | # as the plugin may be re-enabled in the future.
24 |
--------------------------------------------------------------------------------