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 a28d6249081..264fc9b647f 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