Redraw windows on top when any window changes

This commit restores redraws of entire windows, but only if a window below
has actually changed. It should fix most regressions from commit c6d8692ac6
with a much smaller CPU usage cost.

The commit also includes a check for the situation where the title screen
changes all the time, which would restore the high CPU usage (that the
developer would be unlikely to notice immediately).
This commit is contained in:
Jyrki Vesterinen 2017-11-01 21:15:26 +02:00
parent 61bbd51f3a
commit e5fb29dba6
2 changed files with 44 additions and 0 deletions

View file

@ -65,6 +65,10 @@
#include "utils/functional.hpp"
#include <algorithm>
#include <iterator>
#include <stdexcept>
namespace wfl { class function_symbol_table; }
namespace gui2 { class button; }
@ -719,9 +723,23 @@ void window::draw()
}
if (dirty_list_.empty()) {
consecutive_changed_frames_ = 0u;
return;
}
++consecutive_changed_frames_;
if(consecutive_changed_frames_ >= 100u && id_ == "title_screen") {
/* The title screen has changed in 100 consecutive frames, i.e. every
frame for two seconds. It looks like the screen is constantly changing
or at least marking widgets as dirty.
That's a severe problem. Every time the title screen changes, all
other GUI windows need to be fully redrawn, with huge CPU usage cost.
For that reason, this situation is a hard error. */
throw std::logic_error("The title screen is constantly changing, "
"which has a huge CPU usage cost. See the code comment.");
}
for(auto & item : dirty_list_)
{
@ -812,6 +830,8 @@ void window::draw()
dirty_list_.clear();
redraw_windows_on_top();
std::vector<widget*> call_stack;
populate_dirty_list(*this, call_stack);
assert(dirty_list_.empty());
@ -1203,6 +1223,20 @@ void window_swap_grid(grid* g,
} // namespace
void window::redraw_windows_on_top() const
{
auto me = std::find(open_window_stack.begin(), open_window_stack.end(), this);
if(me == open_window_stack.end()) {
// Known to happen for tooltips.
return;
}
for(auto it = std::next(me); it != open_window_stack.end(); ++it) {
// Note that setting an entire window dirty like this is expensive.
(*it)->set_is_dirty(true);
}
}
void window::finalize(const std::shared_ptr<builder_grid>& content_grid)
{
window_swap_grid(nullptr, &get_grid(), content_grid->build(), "_window_content_grid");

View file

@ -684,6 +684,16 @@ private:
*/
std::vector<std::vector<widget*> > dirty_list_;
/**
* In how many consecutive frames the window has changed. This is used to
* detect the situation where the title screen changes in every frame,
* forcing all other windows to redraw everything all the time.
*/
unsigned int consecutive_changed_frames_ = 0u;
/** Schedules windows on top of us (if any) to redraw. */
void redraw_windows_on_top() const;
/**
* Finishes the initialization of the grid.
*