Skip to content

Commit

Permalink
Redraw windows on top when any window changes
Browse files Browse the repository at this point in the history
This commit restores redraws of entire windows, but only if a window below
has actually changed. It should fix most regressions from commit c6d8692
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).
  • Loading branch information
jyrkive authored and GregoryLundberg committed Nov 30, 2017
1 parent a84a03b commit b6e31bc
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/gui/widgets/window.cpp
Expand Up @@ -65,6 +65,10 @@

#include "utils/functional.hpp"

#include <algorithm>
#include <iterator>
#include <stdexcept>

namespace wfl { class function_symbol_table; }
namespace gui2 { class button; }

Expand Down Expand Up @@ -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_)
{

Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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");
Expand Down
10 changes: 10 additions & 0 deletions src/gui/widgets/window.hpp
Expand Up @@ -684,6 +684,16 @@ class window : public panel, public cursor::setter
*/
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.
*
Expand Down

0 comments on commit b6e31bc

Please sign in to comment.