Skip to content

Commit

Permalink
Debug CanvasItem redraw
Browse files Browse the repository at this point in the history
I wanted to add this tool for years and always forget. This command line option:

```
$ godot.exe -e --debug-canvas-item-redraw
```

Allows to see when a canvas item is redrawn. This helps find out if something
in the UI is refreshing in a way it should not. Examples as such:

* Signals causing more of the UI to redraw.
* Container resizing causes more UI elements to redraw.
* Something using a timer is redrawing all time time, which can go unnoticed.

To my surprise, the editor UI is redrawing very efficiently. There is some
weird stuff with the scene tabs, redrawing when the inspector changes but most
things for the most part are fine.
  • Loading branch information
reduz authored and akien-mga committed Aug 28, 2023
1 parent 713bfaf commit 407b16a
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 0 deletions.
6 changes: 6 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,12 @@
<member name="compression/formats/zstd/window_log_size" type="int" setter="" getter="" default="27">
Largest size limit (in power of 2) allowed when compressing using long-distance matching with Zstandard. Higher values can result in better compression, but will require more memory when compressing and decompressing.
</member>
<member name="debug/canvas_items/debug_redraw_color" type="Color" setter="" getter="" default="Color(1, 0.2, 0.2, 0.5)">
If canvas item redraw debugging is active, this color will be flashed on canvas items when they redraw.
</member>
<member name="debug/canvas_items/debug_redraw_time" type="float" setter="" getter="" default="1.0">
If canvas item redraw debugging is active, this will be the time the flash will last each time they redraw.
</member>
<member name="debug/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false">
If [code]true[/code], logs all output to files.
</member>
Expand Down
6 changes: 6 additions & 0 deletions drivers/gles3/rasterizer_canvas_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,12 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {

void set_time(double p_time);

virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override {
if (p_enabled) {
WARN_PRINT_ONCE("Debug CanvasItem Redraw is not available yet when using the GL Compatibility backend.");
}
}

static RasterizerCanvasGLES3 *get_singleton();
RasterizerCanvasGLES3();
~RasterizerCanvasGLES3();
Expand Down
6 changes: 6 additions & 0 deletions editor/editor_run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
bool debug_paths = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_paths", false);
bool debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
bool debug_avoidance = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_avoidance", false);
bool debug_canvas_redraw = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_canvas_redraw", false);

if (debug_collisions) {
args.push_back("--debug-collisions");
}
Expand All @@ -126,6 +128,10 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
args.push_back("--debug-avoidance");
}

if (debug_canvas_redraw) {
args.push_back("--debug-canvas-item-redraw");
}

if (p_write_movie != "") {
args.push_back("--write-movie");
args.push_back(p_write_movie);
Expand Down
14 changes: 14 additions & 0 deletions editor/plugins/debugger_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) {
debug_menu->set_item_tooltip(-1,
TTR("When this option is enabled, avoidance objects shapes, radius and velocities will be visible in the running project."));
debug_menu->add_separator();
debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_canvas_redraw", TTR("Debug CanvasItem Redraws")), RUN_DEBUG_CANVAS_REDRAW);
debug_menu->set_item_tooltip(-1,
TTR("When this option is enabled, redraw requests of 2D objects will become visible (as a short flash) in the running project.\nThis is useful to troubleshoot low processor mode."));
debug_menu->add_separator();
debug_menu->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
debug_menu->set_item_tooltip(-1,
TTR("When this option is enabled, any changes made to the scene in the editor will be replicated in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
Expand Down Expand Up @@ -174,6 +178,12 @@ void DebuggerEditorPlugin::_menu_option(int p_option) {
debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_AVOIDANCE), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_avoidance", !ischecked);

} break;
case RUN_DEBUG_CANVAS_REDRAW: {
bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_CANVAS_REDRAW));
debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_CANVAS_REDRAW), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_canvas_redraw", !ischecked);

} break;
case RUN_RELOAD_SCRIPTS: {
bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_RELOAD_SCRIPTS));
Expand Down Expand Up @@ -213,6 +223,7 @@ void DebuggerEditorPlugin::_update_debug_options() {
bool check_debug_paths = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_paths", false);
bool check_debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
bool check_debug_avoidance = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_avoidance", false);
bool check_debug_canvas_redraw = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_canvas_redraw", false);
bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", true);
bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", true);
bool check_server_keep_open = EditorSettings::get_singleton()->get_project_metadata("debug_options", "server_keep_open", false);
Expand All @@ -236,6 +247,9 @@ void DebuggerEditorPlugin::_update_debug_options() {
if (check_debug_avoidance) {
_menu_option(RUN_DEBUG_AVOIDANCE);
}
if (check_debug_canvas_redraw) {
_menu_option(RUN_DEBUG_CANVAS_REDRAW);
}
if (check_live_debug) {
_menu_option(RUN_LIVE_DEBUG);
}
Expand Down
1 change: 1 addition & 0 deletions editor/plugins/debugger_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class DebuggerEditorPlugin : public EditorPlugin {
RUN_DEBUG_PATHS,
RUN_DEBUG_NAVIGATION,
RUN_DEBUG_AVOIDANCE,
RUN_DEBUG_CANVAS_REDRAW,
RUN_DEPLOY_REMOTE_DEBUG,
RUN_RELOAD_SCRIPTS,
SERVER_KEEP_OPEN,
Expand Down
7 changes: 7 additions & 0 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ static bool debug_collisions = false;
static bool debug_paths = false;
static bool debug_navigation = false;
static bool debug_avoidance = false;
static bool debug_canvas_item_redraw = false;
#endif
static int max_fps = -1;
static int frame_delay = 0;
Expand Down Expand Up @@ -471,6 +472,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n");
OS::get_singleton()->print(" --debug-avoidance Show navigation avoidance debug visuals when running the scene.\n");
OS::get_singleton()->print(" --debug-stringnames Print all StringName allocations to stdout when the engine quits.\n");
OS::get_singleton()->print(" --debug-canvas-item-redraw Display a rectangle each time a canvas item requests a redraw (useful to troubleshoot low processor mode).\n");
#endif
OS::get_singleton()->print(" --max-fps <fps> Set a maximum number of frames per second rendered (can be used to limit power usage). A value of 0 results in unlimited framerate.\n");
OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds). Do not use as a FPS limiter; use --max-fps instead.\n");
Expand Down Expand Up @@ -1414,6 +1416,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
debug_navigation = true;
} else if (I->get() == "--debug-avoidance") {
debug_avoidance = true;
} else if (I->get() == "--debug-canvas-item-redraw") {
debug_canvas_item_redraw = true;
} else if (I->get() == "--debug-stringnames") {
StringName::set_debug_stringnames(true);
#endif
Expand Down Expand Up @@ -3050,6 +3054,9 @@ bool Main::start() {
NavigationServer3D::get_singleton()->set_active(true);
NavigationServer3D::get_singleton()->set_debug_enabled(true);
}
if (debug_canvas_item_redraw) {
RenderingServer::get_singleton()->canvas_item_set_debug_redraw(true);
}
#endif

if (single_threaded_scene) {
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/dummy/rasterizer_canvas_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class RasterizerCanvasDummy : public RendererCanvasRender {
bool free(RID p_rid) override { return true; }
void update() override {}

virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override {}

RasterizerCanvasDummy() {}
~RasterizerCanvasDummy() {}
};
Expand Down
14 changes: 14 additions & 0 deletions servers/rendering/renderer_canvas_cull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include "renderer_canvas_cull.h"

#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
#include "renderer_viewport.h"
#include "rendering_server_default.h"
Expand Down Expand Up @@ -1557,6 +1558,11 @@ void RendererCanvasCull::canvas_item_clear(RID p_item) {
ERR_FAIL_COND(!canvas_item);

canvas_item->clear();
#ifdef DEBUG_ENABLED
if (debug_redraw) {
canvas_item->debug_redraw_time = debug_redraw_time;
}
#endif
}

void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) {
Expand Down Expand Up @@ -1612,6 +1618,11 @@ void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_
}
}

void RendererCanvasCull::canvas_item_set_debug_redraw(bool p_enabled) {
debug_redraw = p_enabled;
RSG::canvas_render->set_debug_redraw(p_enabled, debug_redraw_time, debug_redraw_color);
}

void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
Expand Down Expand Up @@ -2155,6 +2166,9 @@ RendererCanvasCull::RendererCanvasCull() {
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));

disable_scale = false;

debug_redraw_time = GLOBAL_DEF("debug/canvas_items/debug_redraw_time", 1.0);
debug_redraw_color = GLOBAL_DEF("debug/canvas_items/debug_redraw_color", Color(1.0, 0.2, 0.2, 0.5));
}

RendererCanvasCull::~RendererCanvasCull() {
Expand Down
6 changes: 6 additions & 0 deletions servers/rendering/renderer_canvas_cull.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ class RendererCanvasCull {
bool sdf_used = false;
bool snapping_2d_transforms_to_pixel = false;

bool debug_redraw = false;
double debug_redraw_time = 0;
Color debug_redraw_color;

PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator;
SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list;

Expand Down Expand Up @@ -260,6 +264,8 @@ class RendererCanvasCull {

void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false);

void canvas_item_set_debug_redraw(bool p_enabled);

RID canvas_light_allocate();
void canvas_light_initialize(RID p_rid);

Expand Down
5 changes: 5 additions & 0 deletions servers/rendering/renderer_canvas_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ class RendererCanvasRender {
Command *last_command = nullptr;
Vector<CommandBlock> blocks;
uint32_t current_block;
#ifdef DEBUG_ENABLED
mutable double debug_redraw_time = 0;
#endif

template <class T>
T *alloc_command() {
Expand Down Expand Up @@ -517,6 +520,8 @@ class RendererCanvasRender {
virtual bool free(RID p_rid) = 0;
virtual void update() = 0;

virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0;

RendererCanvasRender() { singleton = this; }
virtual ~RendererCanvasRender() {}
};
Expand Down
47 changes: 47 additions & 0 deletions servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,48 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend

c = c->next;
}
#ifdef DEBUG_ENABLED
if (debug_redraw && p_item->debug_redraw_time > 0.0) {
Color dc = debug_redraw_color;
dc.a *= p_item->debug_redraw_time / debug_redraw_time;

RID pipeline = pipeline_variants->variants[PIPELINE_LIGHT_MODE_DISABLED][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);

//bind textures

_bind_canvas_texture(p_draw_list, RID(), current_filter, current_repeat, last_texture, push_constant, texpixel_size);

Rect2 src_rect;
Rect2 dst_rect;

dst_rect = Rect2(Vector2(), p_item->rect.size);
src_rect = Rect2(0, 0, 1, 1);

push_constant.modulation[0] = dc.r;
push_constant.modulation[1] = dc.g;
push_constant.modulation[2] = dc.b;
push_constant.modulation[3] = dc.a;

push_constant.src_rect[0] = src_rect.position.x;
push_constant.src_rect[1] = src_rect.position.y;
push_constant.src_rect[2] = src_rect.size.width;
push_constant.src_rect[3] = src_rect.size.height;

push_constant.dst_rect[0] = dst_rect.position.x;
push_constant.dst_rect[1] = dst_rect.position.y;
push_constant.dst_rect[2] = dst_rect.size.width;
push_constant.dst_rect[3] = dst_rect.size.height;

RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
RD::get_singleton()->draw_list_draw(p_draw_list, true);

p_item->debug_redraw_time -= RSG::rasterizer->get_frame_delta_time();

RenderingServerDefault::redraw_request();
}
#endif
if (current_clip && reclip) {
//will make it re-enable clipping if needed afterwards
current_clip = nullptr;
Expand Down Expand Up @@ -2741,6 +2782,12 @@ void RendererCanvasRenderRD::set_shadow_texture_size(int p_size) {
}
}

void RendererCanvasRenderRD::set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) {
debug_redraw = p_enabled;
debug_redraw_time = p_time;
debug_redraw_color = p_color;
}

RendererCanvasRenderRD::~RendererCanvasRenderRD() {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
//canvas state
Expand Down
6 changes: 6 additions & 0 deletions servers/rendering/renderer_rd/renderer_canvas_render_rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender {

RID _create_base_uniform_set(RID p_to_render_target, bool p_backbuffer);

bool debug_redraw = false;
Color debug_redraw_color;
double debug_redraw_time = 1.0;

inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size, bool p_texture_is_data = false); //recursive, so regular inline used instead.
void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used);
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false);
Expand Down Expand Up @@ -450,6 +454,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {

virtual void set_shadow_texture_size(int p_size);

void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color);

void set_time(double p_time);
void update();
bool free(RID p_rid);
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/rendering_server_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,8 @@ class RenderingServerDefault : public RenderingServer {

FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool)

FUNC1(canvas_item_set_debug_redraw, bool)

FUNCRIDSPLIT(canvas_light)

FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,8 @@ class RenderingServer : public Object {

virtual void canvas_item_set_canvas_group_mode(RID p_item, CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false) = 0;

virtual void canvas_item_set_debug_redraw(bool p_enabled) = 0;

/* CANVAS LIGHT */
virtual RID canvas_light_create() = 0;

Expand Down

0 comments on commit 407b16a

Please sign in to comment.