From a0c6d16c90d55b26874ead5255f00c449e43ba8f Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Tue, 5 Oct 2021 19:05:57 +0100 Subject: [PATCH] Add editor vital redraws only option When editor continuous redraws is switched off, the editor only redraws when a redraw_request was issued by an element in the scene. This works well in most situations, but when scenes have dynamic content they will continuously issue redraw_requests. This can be fine on high power desktops but can be an annoyance on lower power machines. This PR splits redraw requests into high and low priority requests, defaulting to high priority. Requests due to e.g. shaders using TIME are assigned low priority. An extra editor setting is used to record the user preference and an extra option is added to the editor spinner menu, to allow the user to select between 3 modes: * Continuous * Update all changes * Update vital changes --- core/os/os.cpp | 6 ++++ core/os/os.h | 23 ++++++++++++ doc/classes/VisualServer.xml | 11 ++++++ drivers/gles2/rasterizer_canvas_gles2.cpp | 4 +-- drivers/gles2/rasterizer_scene_gles2.cpp | 2 +- drivers/gles3/rasterizer_canvas_gles3.cpp | 6 ++-- drivers/gles3/rasterizer_scene_gles3.cpp | 2 +- editor/code_editor.cpp | 2 +- editor/editor_node.cpp | 25 +++++++++++-- editor/editor_node.h | 1 + editor/editor_settings.cpp | 13 +++++++ editor/editor_settings.h | 1 + editor/plugins/shader_editor_plugin.cpp | 2 +- main/main.cpp | 11 +++++- scene/2d/cpu_particles_2d.cpp | 9 +++-- scene/3d/cpu_particles.cpp | 15 ++++---- scene/animation/animation_tree.cpp | 12 ++++--- scene/animation/animation_tree_player.cpp | 5 +-- scene/gui/line_edit.cpp | 6 ++-- servers/visual/visual_server_canvas.cpp | 2 +- servers/visual/visual_server_raster.cpp | 20 ++++++++--- servers/visual/visual_server_raster.h | 44 ++++++++++++++--------- servers/visual/visual_server_scene.cpp | 10 +++--- servers/visual/visual_server_wrap_mt.h | 2 +- servers/visual_server.cpp | 6 +++- servers/visual_server.h | 9 ++++- 26 files changed, 190 insertions(+), 59 deletions(-) diff --git a/core/os/os.cpp b/core/os/os.cpp index 35e3b64e850..aecd3d2dc91 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -146,6 +146,10 @@ bool OS::is_in_low_processor_usage_mode() const { return low_processor_usage_mode; } +void OS::set_update_vital_only(bool p_enabled) { + _update_vital_only = p_enabled; +} + void OS::set_low_processor_usage_mode_sleep_usec(int p_usec) { low_processor_usage_mode_sleep_usec = p_usec; } @@ -834,6 +838,8 @@ OS::OS() { _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0. low_processor_usage_mode = false; low_processor_usage_mode_sleep_usec = 10000; + _update_vital_only = false; + _update_pending = false; _verbose_stdout = false; _debug_stdout = false; _no_window = false; diff --git a/core/os/os.h b/core/os/os.h index bc33c27829d..a61cf414c95 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -50,6 +50,8 @@ class OS { bool _keep_screen_on; bool low_processor_usage_mode; int low_processor_usage_mode_sleep_usec; + bool _update_vital_only; + bool _update_pending; bool _verbose_stdout; bool _debug_stdout; String _local_clipboard; @@ -287,6 +289,27 @@ public: virtual bool is_in_low_processor_usage_mode() const; virtual void set_low_processor_usage_mode_sleep_usec(int p_usec); virtual int get_low_processor_usage_mode_sleep_usec() const; + virtual void set_update_vital_only(bool p_enabled); + virtual void set_update_pending(bool p_pending) { _update_pending = p_pending; } + + // Convenience easy switch for turning this off outside tools builds, without littering calling code + // with #ifdefs. It will also hopefully be compiled out in release. +#ifdef TOOLS_ENABLED + // This function is used to throttle back updates of animations and particle systems when using UPDATE_VITAL_ONLY mode. + + // CASE 1) We are not in UPDATE_VITAL_ONLY mode - always return true and update. + // CASE 2) We are in UPDATE_VITAL_ONLY mode - + + // In most cases this will return false and prevent animations etc updating. + // The exception is that we can also choose to receive a true + // each time a frame is redrawn as a result of moving the mouse, clicking etc. + // This enables us to keep e.g. particle systems processing, but ONLY when other + // events have caused a redraw. + virtual bool is_update_pending(bool p_include_redraws = false) const { return !_update_vital_only || (_update_pending && p_include_redraws); } +#else + // Always update when outside the editor, UPDATE_VITAL_ONLY has no effect outside the editor. + virtual bool is_update_pending(bool p_include_redraws = false) const { return true; } +#endif virtual String get_executable_path() const; virtual Error execute(const String &p_path, const List &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0; diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 9d220af8195..207a9381a93 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -1178,8 +1178,10 @@ + Returns [code]true[/code] if changes have been made to the VisualServer's data. [method draw] is usually called if this happens. + As changes are registered as either high or low priority (e.g. dynamic shaders), this function takes an optional argument to query either low or high priority changes, or any changes. @@ -3841,5 +3843,14 @@ Performs a 3x3 blur on the SSAO output. Use this for smoothest SSAO. + + Used to query for any changes that request a redraw, whatever the priority. + + + Registered changes which have low priority can be optionally prevented from causing editor redraws. Examples might include dynamic shaders (typically using the [code]TIME[/code] built-in). + + + Registered changes which can cause a redraw default to high priority. + diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index d0b1971cb21..917a9362f13 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -1659,7 +1659,7 @@ void RasterizerCanvasGLES2::_legacy_canvas_render_item(Item *p_ci, RenderItemSta if (shader_ptr != r_ris.shader_cache) { if (shader_ptr->canvas_item.uses_time) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); @@ -2021,7 +2021,7 @@ void RasterizerCanvasGLES2::render_joined_item(const BItemJoined &p_bij, RenderI if (shader_ptr != r_ris.shader_cache) { if (shader_ptr->canvas_item.uses_time) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 780db1d1ec4..7fb0b916098 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -1242,7 +1242,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G // do not add anything here, as lights are duplicated elements.. if (p_material->shader->spatial.uses_time) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } } diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 8d0c9d445cc..376b2314095 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -170,7 +170,7 @@ void RasterizerCanvasGLES3::_legacy_canvas_render_item(Item *p_ci, RenderItemSta if (shader_ptr != r_ris.shader_cache || r_ris.rebind_shader) { if (shader_ptr->canvas_item.uses_time) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); @@ -968,7 +968,7 @@ void RasterizerCanvasGLES3::render_batches(Item *p_current_clip, bool &r_reclip, glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); storage->particles_request_process(particles_cmd->particles); //enable instancing @@ -1250,7 +1250,7 @@ void RasterizerCanvasGLES3::render_joined_item(const BItemJoined &p_bij, RenderI if (shader_ptr != r_ris.shader_cache || r_ris.rebind_shader) { if (shader_ptr->canvas_item.uses_time) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 90b4e7c7efe..8658bfdbaca 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2406,7 +2406,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G } if (p_material->shader->spatial.uses_time) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } } diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index da4903dc754..a6ca391976e 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -936,7 +936,7 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_line_length_guideline_hard_column(EditorSettings::get_singleton()->get("text_editor/appearance/line_length_guideline_hard_column")); text_editor->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file")); text_editor->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret")); - text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink")); + text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->is_caret_blink_active()); text_editor->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed")); text_editor->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete")); } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e7f163c5b91..c4dbf3012c4 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -636,9 +636,17 @@ void EditorNode::_update_update_spinner() { update_spinner->set_visible(EditorSettings::get_singleton()->get("interface/editor/show_update_spinner")); const bool update_continuously = EditorSettings::get_singleton()->get("interface/editor/update_continuously"); + const bool vital_only = EditorSettings::get_singleton()->get("interface/editor/update_vital_only"); PopupMenu *update_popup = update_spinner->get_popup(); update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_CONTINUOUSLY), update_continuously); - update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !update_continuously); + + if (update_continuously) { + update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), false); + update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_VITAL_ONLY), false); + } else { + update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !vital_only); + update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_VITAL_ONLY), vital_only); + } if (update_continuously) { update_spinner->set_tooltip(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it.")); @@ -656,6 +664,11 @@ void EditorNode::_update_update_spinner() { } OS::get_singleton()->set_low_processor_usage_mode(!update_continuously); + + // Only set low priority redraws to false in the editor. + // When we run the project in the editor, we don't want it to prevent + // rendering any frames. + OS::get_singleton()->set_update_vital_only(vital_only && !update_continuously); } void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_name) { @@ -2791,6 +2804,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case SETTINGS_UPDATE_WHEN_CHANGED: { EditorSettings::get_singleton()->set("interface/editor/update_continuously", false); + EditorSettings::get_singleton()->set("interface/editor/update_vital_only", false); + _update_update_spinner(); + } break; + case SETTINGS_UPDATE_VITAL_ONLY: { + EditorSettings::get_singleton()->set("interface/editor/update_continuously", false); + EditorSettings::get_singleton()->set("interface/editor/update_vital_only", true); _update_update_spinner(); } break; case SETTINGS_UPDATE_SPINNER_HIDE: { @@ -5951,6 +5970,7 @@ EditorNode::EditorNode() { EDITOR_DEF("interface/editor/quit_confirmation", true); EDITOR_DEF("interface/editor/show_update_spinner", false); EDITOR_DEF("interface/editor/update_continuously", false); + EDITOR_DEF("interface/editor/update_vital_only", false); EDITOR_DEF_RST("interface/scene_tabs/restore_scenes_on_load", false); EDITOR_DEF_RST("interface/scene_tabs/show_thumbnail_on_hover", true); EDITOR_DEF_RST("interface/inspector/capitalize_properties", true); @@ -6622,7 +6642,8 @@ EditorNode::EditorNode() { update_spinner->get_popup()->connect("id_pressed", this, "_menu_option"); p = update_spinner->get_popup(); p->add_radio_check_item(TTR("Update Continuously"), SETTINGS_UPDATE_CONTINUOUSLY); - p->add_radio_check_item(TTR("Update When Changed"), SETTINGS_UPDATE_WHEN_CHANGED); + p->add_radio_check_item(TTR("Update All Changes"), SETTINGS_UPDATE_WHEN_CHANGED); + p->add_radio_check_item(TTR("Update Vital Changes"), SETTINGS_UPDATE_VITAL_ONLY); p->add_separator(); p->add_item(TTR("Hide Update Spinner"), SETTINGS_UPDATE_SPINNER_HIDE); _update_update_spinner(); diff --git a/editor/editor_node.h b/editor/editor_node.h index b6b0ba2a32b..18ae75fb63b 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -176,6 +176,7 @@ private: RUN_VCS_SETTINGS, RUN_VCS_SHUT_DOWN, SETTINGS_UPDATE_CONTINUOUSLY, + SETTINGS_UPDATE_VITAL_ONLY, SETTINGS_UPDATE_WHEN_CHANGED, SETTINGS_UPDATE_ALWAYS, SETTINGS_UPDATE_CHANGES, diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 878f013bdc6..4212904df4a 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -1292,6 +1292,19 @@ void EditorSettings::load_favorites() { } } +// The logic for this is rather convoluted as it takes into account whether +// vital updates only is selected. +bool EditorSettings::is_caret_blink_active() const { + bool blink = get("text_editor/cursor/caret_blink"); + bool vital_only = get("interface/editor/update_vital_only"); + bool continuous = get("interface/editor/update_continuously"); + + if (vital_only && !continuous) { + blink = false; + } + return blink; +} + bool EditorSettings::is_dark_theme() { int AUTO_COLOR = 0; int LIGHT_COLOR = 2; diff --git a/editor/editor_settings.h b/editor/editor_settings.h index d502c6f1bf0..ae5506c6f78 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -179,6 +179,7 @@ public: void load_favorites(); bool is_dark_theme(); + bool is_caret_blink_active() const; void list_text_editor_themes(); void load_text_editor_theme(); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index acc016990c2..0c0e40990e6 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -370,7 +370,7 @@ void ShaderEditor::_editor_settings_changed() { shader_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/highlighting/syntax_highlighting")); shader_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_all_occurrences")); shader_editor->get_text_edit()->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line")); - shader_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink")); + shader_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->is_caret_blink_active()); shader_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed")); shader_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/theme/line_spacing")); shader_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret")); diff --git a/main/main.cpp b/main/main.cpp index e0df6794ec4..42ec996973f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2277,7 +2277,16 @@ bool Main::iteration() { if (OS::get_singleton()->can_draw() && VisualServer::get_singleton()->is_render_loop_enabled()) { if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) { - if (VisualServer::get_singleton()->has_changed()) { + // We can choose whether to redraw as a result of any redraw request, or redraw only for vital requests. + VisualServer::ChangedPriority priority = (OS::get_singleton()->is_update_pending() ? VisualServer::CHANGED_PRIORITY_ANY : VisualServer::CHANGED_PRIORITY_HIGH); + + // Determine whether the scene has changed, to know whether to draw. + // If it has changed, inform the update pending system so it can keep + // particle systems etc updating when running in vital updates only mode. + bool has_changed = VisualServer::get_singleton()->has_changed(priority); + OS::get_singleton()->set_update_pending(has_changed); + + if (has_changed) { VisualServer::get_singleton()->draw(true, scaled_step); // flush visual commands Engine::get_singleton()->frames_drawn++; } diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 35043e1eb1f..e591e534da8 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -30,6 +30,7 @@ #include "cpu_particles_2d.h" #include "core/core_string_names.h" +#include "core/os/os.h" #include "scene/2d/canvas_item.h" #include "scene/2d/particles_2d.h" #include "scene/resources/particles_material.h" @@ -1028,9 +1029,11 @@ void CPUParticles2D::_set_redraw(bool p_redraw) { } void CPUParticles2D::_update_render_thread() { - update_mutex.lock(); - VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data); - update_mutex.unlock(); + if (OS::get_singleton()->is_update_pending(true)) { + update_mutex.lock(); + VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data); + update_mutex.unlock(); + } } void CPUParticles2D::_notification(int p_what) { diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 6f5c47f6fca..dadcba1a85a 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -30,6 +30,7 @@ #include "cpu_particles.h" +#include "core/os/os.h" #include "scene/3d/camera.h" #include "scene/3d/particles.h" #include "scene/resources/particles_material.h" @@ -1152,14 +1153,16 @@ void CPUParticles::_set_redraw(bool p_redraw) { } void CPUParticles::_update_render_thread() { - update_mutex.lock(); + if (OS::get_singleton()->is_update_pending(true)) { + update_mutex.lock(); - if (can_update.is_set()) { - VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data); - can_update.clear(); //wait for next time + if (can_update.is_set()) { + VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data); + can_update.clear(); //wait for next time + } + + update_mutex.unlock(); } - - update_mutex.unlock(); } void CPUParticles::_notification(int p_what) { diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index d6a0033b009..330d26e21fc 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -1236,12 +1236,14 @@ void AnimationTree::advance(float p_time) { } void AnimationTree::_notification(int p_what) { - if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) { - _process_graph(get_physics_process_delta_time()); - } + if (active && OS::get_singleton()->is_update_pending()) { + if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) { + _process_graph(get_physics_process_delta_time()); + } - if (active && p_what == NOTIFICATION_INTERNAL_PROCESS && process_mode == ANIMATION_PROCESS_IDLE) { - _process_graph(get_process_delta_time()); + if (p_what == NOTIFICATION_INTERNAL_PROCESS && process_mode == ANIMATION_PROCESS_IDLE) { + _process_graph(get_process_delta_time()); + } } if (p_what == NOTIFICATION_EXIT_TREE) { diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index e33520eff90..d4d37498f50 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -31,6 +31,7 @@ #include "animation_tree_player.h" #include "animation_player.h" +#include "core/os/os.h" #include "scene/scene_string_names.h" void AnimationTreePlayer::set_animation_process_mode(AnimationProcessMode p_mode) { @@ -433,7 +434,7 @@ void AnimationTreePlayer::_notification(int p_what) { break; } - if (processing) { + if (processing && OS::get_singleton()->is_update_pending()) { _process_animation(get_process_delta_time()); } } break; @@ -442,7 +443,7 @@ void AnimationTreePlayer::_notification(int p_what) { break; } - if (processing) { + if (processing && OS::get_singleton()->is_update_pending()) { _process_animation(get_physics_process_delta_time()); } } break; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index f48da22a216..3aa92839625 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -687,7 +687,8 @@ void LineEdit::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) { - cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false)); + EDITOR_DEF("text_editor/cursor/caret_blink", false); + cursor_set_blink_enabled(EditorSettings::get_singleton()->is_caret_blink_active()); cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65)); if (!EditorSettings::get_singleton()->is_connected("settings_changed", this, "_editor_settings_changed")) { @@ -1669,7 +1670,8 @@ PopupMenu *LineEdit::get_menu() const { void LineEdit::_editor_settings_changed() { #ifdef TOOLS_ENABLED - cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false)); + EDITOR_DEF("text_editor/cursor/caret_blink", false); + cursor_set_blink_enabled(EditorSettings::get_singleton()->is_caret_blink_active()); cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65)); #endif } diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index a23ac1bcb58..e6e51c5a31a 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -172,7 +172,7 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor } if (ci->update_when_visible) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } if ((!ci->commands.empty() && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 271d19c8bfc..d0e7b76bb61 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -40,7 +40,7 @@ // careful, these may run in different threads than the visual server -int VisualServerRaster::changes = 0; +int VisualServerRaster::changes[2] = { 0 }; /* BLACK BARS */ @@ -98,7 +98,8 @@ void VisualServerRaster::draw(bool p_swap_buffers, double frame_step) { //needs to be done before changes is reset to 0, to not force the editor to redraw VS::get_singleton()->emit_signal("frame_pre_draw"); - changes = 0; + changes[0] = 0; + changes[1] = 0; VSG::rasterizer->begin_frame(frame_step); @@ -127,8 +128,19 @@ void VisualServerRaster::draw(bool p_swap_buffers, double frame_step) { } void VisualServerRaster::sync() { } -bool VisualServerRaster::has_changed() const { - return changes > 0; + +bool VisualServerRaster::has_changed(ChangedPriority p_priority) const { + switch (p_priority) { + default: { + return (changes[0] > 0) || (changes[1] > 0); + } break; + case CHANGED_PRIORITY_LOW: { + return changes[0] > 0; + } break; + case CHANGED_PRIORITY_HIGH: { + return changes[1] > 0; + } break; + } } void VisualServerRaster::init() { VSG::rasterizer->initialize(); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 27e2ba6f1c9..63d92ce1811 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -53,7 +53,8 @@ class VisualServerRaster : public VisualServer { }; - static int changes; + // low and high priority + static int changes[2]; RID test_cube; int black_margin[4]; @@ -68,27 +69,36 @@ class VisualServerRaster : public VisualServer { List frame_drawn_callbacks; void _draw_margins(); - static void _changes_changed() {} -public: - //if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed() - //#define DEBUG_CHANGES - -#ifdef DEBUG_CHANGES - _FORCE_INLINE_ static void redraw_request() { - changes++; - _changes_changed(); + // This function is NOT dead code. + // It is specifically for debugging redraws to help identify problems with + // undesired constant editor updating. + // The function will be called in DEV builds (and thus does not require a recompile), + // allowing you to place a breakpoint either at the first line or the semicolon. + // You can then look at the callstack to find the cause of the redraw. + static void _changes_changed(int p_priority) { + if (p_priority) { + ; + } } -#define DISPLAY_CHANGED \ - changes++; \ - _changes_changed(); +public: + // if editor is redrawing when it shouldn't, use a DEV build and put a breakpoint in _changes_changed() + _FORCE_INLINE_ static void redraw_request(bool p_high_priority = true) { + int priority = p_high_priority ? 1 : 0; + changes[priority] += 1; +#ifdef DEV_ENABLED + _changes_changed(priority); +#endif + } +#ifdef DEV_ENABLED +#define DISPLAY_CHANGED \ + changes[1] += 1; \ + _changes_changed(1); #else - _FORCE_INLINE_ static void redraw_request() { changes++; } - #define DISPLAY_CHANGED \ - changes++; + changes[1] += 1; #endif #define BIND0R(m_r, m_name) \ @@ -736,7 +746,7 @@ public: virtual void draw(bool p_swap_buffers, double frame_step); virtual void sync(); - virtual bool has_changed() const; + virtual bool has_changed(ChangedPriority p_priority = CHANGED_PRIORITY_ANY) const; virtual void init(); virtual void finish(); diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index fb384f8eccb..d2b5b078fee 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2633,7 +2633,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceGeometryData *geom = static_cast(ins->base_data); if (ins->redraw_if_visible) { - VisualServerRaster::redraw_request(); + VisualServerRaster::redraw_request(false); } if (ins->base_type == VS::INSTANCE_PARTICLES) { @@ -2642,9 +2642,11 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca //but if nothing is going on, don't do it. keep = false; } else { - VSG::storage->particles_request_process(ins->base); - //particles visible? request redraw - VisualServerRaster::redraw_request(); + if (OS::get_singleton()->is_update_pending(true)) { + VSG::storage->particles_request_process(ins->base); + //particles visible? request redraw + VisualServerRaster::redraw_request(false); + } } } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 328f4d2afd8..68e157e5f0b 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -657,7 +657,7 @@ public: virtual void finish(); virtual void draw(bool p_swap_buffers, double frame_step); virtual void sync(); - FUNC0RC(bool, has_changed) + FUNC1RC(bool, has_changed, ChangedPriority) /* RENDER INFO */ diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 1eadd55cea6..12e0ee4cee0 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -2230,7 +2230,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("free_rid", "rid"), &VisualServer::free); // shouldn't conflict with Object::free() ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "where", "method", "userdata"), &VisualServer::request_frame_drawn_callback); - ClassDB::bind_method(D_METHOD("has_changed"), &VisualServer::has_changed); + ClassDB::bind_method(D_METHOD("has_changed", "queried_priority"), &VisualServer::has_changed, DEFVAL(CHANGED_PRIORITY_ANY)); ClassDB::bind_method(D_METHOD("init"), &VisualServer::init); ClassDB::bind_method(D_METHOD("finish"), &VisualServer::finish); ClassDB::bind_method(D_METHOD("get_render_info", "info"), &VisualServer::get_render_info); @@ -2522,6 +2522,10 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_2x2); BIND_ENUM_CONSTANT(ENV_SSAO_BLUR_3x3); + BIND_ENUM_CONSTANT(CHANGED_PRIORITY_ANY); + BIND_ENUM_CONSTANT(CHANGED_PRIORITY_LOW); + BIND_ENUM_CONSTANT(CHANGED_PRIORITY_HIGH); + ADD_SIGNAL(MethodInfo("frame_pre_draw")); ADD_SIGNAL(MethodInfo("frame_post_draw")); } diff --git a/servers/visual_server.h b/servers/visual_server.h index d04940f5d0d..bdf2308e759 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -1103,9 +1103,15 @@ public: /* EVENT QUEUING */ + enum ChangedPriority { + CHANGED_PRIORITY_ANY = 0, + CHANGED_PRIORITY_LOW, + CHANGED_PRIORITY_HIGH, + }; + virtual void draw(bool p_swap_buffers = true, double frame_step = 0.0) = 0; virtual void sync() = 0; - virtual bool has_changed() const = 0; + virtual bool has_changed(ChangedPriority p_priority = CHANGED_PRIORITY_ANY) const = 0; virtual void init() = 0; virtual void finish() = 0; @@ -1220,6 +1226,7 @@ VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOBlur); VARIANT_ENUM_CAST(VisualServer::InstanceFlags); VARIANT_ENUM_CAST(VisualServer::ShadowCastingSetting); VARIANT_ENUM_CAST(VisualServer::TextureType); +VARIANT_ENUM_CAST(VisualServer::ChangedPriority); //typedef VisualServer VS; // makes it easier to use #define VS VisualServer