GUI: implement canvas caching

This commit is contained in:
Jyrki Vesterinen 2017-08-06 13:39:03 +03:00
parent 29519406be
commit 6110fb59db
4 changed files with 45 additions and 8 deletions

View file

@ -47,6 +47,8 @@ Version 1.13.8+dev:
* Fixed delay or clients gettings stuck when starting a mp game (Bug #1674) * Fixed delay or clients gettings stuck when starting a mp game (Bug #1674)
* Performance: * Performance:
* Rewrote the FPS cap implementation. This greatly improves smoothness ingame. * Rewrote the FPS cap implementation. This greatly improves smoothness ingame.
* Implemented GUI canvas caching. It speeds up multiple areas, but especially
the story screen.
* Units: * Units:
* Added new lvl0 Giant Scorpling, leveling into the Giant Scorpion. * Added new lvl0 Giant Scorpling, leveling into the Giant Scorpion.
* User Interface: * User Interface:

View file

@ -32,6 +32,8 @@ Version 1.13.8+dev:
* Performance: * Performance:
* Rewrote the FPS cap implementation. This greatly improves smoothness ingame. * Rewrote the FPS cap implementation. This greatly improves smoothness ingame.
* Implemented GUI canvas caching. It speeds up multiple areas, but especially
the story screen.
* User Interface: * User Interface:
* Unit recall dialog now sorts the units by both level and required XP for * Unit recall dialog now sorts the units by both level and required XP for

View file

@ -34,6 +34,8 @@
#include "video.hpp" #include "video.hpp"
#include "wml_exception.hpp" #include "wml_exception.hpp"
#include <iterator>
namespace gui2 namespace gui2
{ {
@ -1391,9 +1393,13 @@ void canvas::draw(const bool force)
variables_.add("height", wfl::variant(h_)); variables_.add("height", wfl::variant(h_));
} }
// create surface if(!canvas_.null()) {
DBG_GUI_D << "Canvas: create new empty canvas.\n"; DBG_GUI_D << "Canvas: use cached canvas.\n";
canvas_.assign(create_neutral_surface(w_, h_)); } else {
// create surface
DBG_GUI_D << "Canvas: create new empty canvas.\n";
canvas_.assign(create_neutral_surface(w_, h_));
}
SDL_DestroyRenderer(renderer_); SDL_DestroyRenderer(renderer_);
@ -1407,6 +1413,10 @@ void canvas::draw(const bool force)
shape->draw(canvas_, renderer_, variables_); shape->draw(canvas_, renderer_, variables_);
} }
// The shapes have been drawn and the draw result has been cached. Clear the list.
std::copy(shapes_.begin(), shapes_.end(), std::back_inserter(drawn_shapes_));
shapes_.clear();
SDL_RenderPresent(renderer_); SDL_RenderPresent(renderer_);
is_dirty_ = false; is_dirty_ = false;
@ -1484,12 +1494,29 @@ void canvas::parse_cfg(const config& cfg)
void canvas::clear_shapes(const bool force) void canvas::clear_shapes(const bool force)
{ {
const auto iter = std::remove_if(shapes_.begin(), shapes_.end(), [&force](const shape_ptr s) auto iter = std::remove_if(shapes_.begin(), shapes_.end(), [force](const shape_ptr s)
{ {
return !s->immutable() && !force; return !s->immutable() && !force;
}); });
shapes_.erase(iter, shapes_.end()); shapes_.erase(iter, shapes_.end());
iter = std::remove_if(drawn_shapes_.begin(), drawn_shapes_.end(), [force](const shape_ptr s)
{
return !s->immutable() && !force;
});
drawn_shapes_.erase(iter, drawn_shapes_.end());
}
void canvas::invalidate_cache()
{
canvas_.assign(nullptr);
if(shapes_.empty()) {
shapes_.swap(drawn_shapes_);
} else {
std::copy(drawn_shapes_.begin(), drawn_shapes_.end(), std::inserter(shapes_, shapes_.begin()));
drawn_shapes_.clear();
}
} }
/***** ***** ***** ***** ***** SHAPE ***** ***** ***** ***** *****/ /***** ***** ***** ***** ***** SHAPE ***** ***** ***** ***** *****/

View file

@ -35,9 +35,6 @@ namespace gui2
* *
* The class has a config which contains what to draw. * The class has a config which contains what to draw.
* *
* NOTE we might add some caching in a later state, for now every draw cycle
* does a full redraw.
*
* The copy constructor does a shallow copy of the shapes to draw. * The copy constructor does a shallow copy of the shapes to draw.
* a clone() will be implemented if really needed. * a clone() will be implemented if really needed.
*/ */
@ -121,6 +118,7 @@ public:
void set_cfg(const config& cfg, const bool force = false) void set_cfg(const config& cfg, const bool force = false)
{ {
clear_shapes(force); clear_shapes(force);
invalidate_cache();
parse_cfg(cfg); parse_cfg(cfg);
} }
@ -142,6 +140,7 @@ public:
{ {
w_ = width; w_ = width;
set_is_dirty(true); set_is_dirty(true);
invalidate_cache();
} }
unsigned get_width() const unsigned get_width() const
@ -153,6 +152,7 @@ public:
{ {
h_ = height; h_ = height;
set_is_dirty(true); set_is_dirty(true);
invalidate_cache();
} }
unsigned get_height() const unsigned get_height() const
@ -169,6 +169,7 @@ public:
{ {
variables_.add(key, value); variables_.add(key, value);
set_is_dirty(true); set_is_dirty(true);
invalidate_cache();
} }
void set_is_dirty(const bool is_dirty) void set_is_dirty(const bool is_dirty)
@ -180,6 +181,10 @@ private:
/** Vector with the shapes to draw. */ /** Vector with the shapes to draw. */
std::vector<shape_ptr> shapes_; std::vector<shape_ptr> shapes_;
/** All shapes which have been already drawn. Kept around in case
* the cache needs to be invalidated. */
std::vector<shape_ptr> drawn_shapes_;
/** /**
* The depth of the blur to use in the pre committing. * The depth of the blur to use in the pre committing.
* *
@ -223,6 +228,7 @@ private:
void parse_cfg(const config& cfg); void parse_cfg(const config& cfg);
void clear_shapes(const bool force); void clear_shapes(const bool force);
void invalidate_cache();
}; };
} // namespace gui2 } // namespace gui2