Séparation entre images et textures pour optimisation

Les images (chargées en RAM) sont séparées des textures
(chargées en GPU) dans les dossiers et le gestionnaire
de ressources. Le cache d'images est constitué de pointeurs
faibles pour ne pas entrer en conflit avec la gestion
de mémoire de SFGUI. On évite ainsi de recharger trop
souvent les textures, mais on évite aussi des images
qui resteraient indéfiniment en mémoire, affichées
à l'écran.

Ceci évite d'avoir des textures à la fois chargées en
RAM et GPU et réduit donc l'impact mémoire inutile.
Ceci pourrait résoudre le problème de l'invite
"Ne répond pas" qui s'affiche de manière intempestive
sans affecter le déroulement du programme.
This commit is contained in:
Mattéo Delabre 2016-04-28 22:40:05 +02:00
parent b8f1ca5634
commit 8ea50f3202
26 changed files with 55 additions and 33 deletions

View File

@ -3,6 +3,7 @@
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp> #include <SFML/Audio.hpp>
#include <SFGUI/Image.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
@ -18,6 +19,7 @@ private:
/** /**
* Chemins vers les différents dossiers de ressources * Chemins vers les différents dossiers de ressources
*/ */
boost::filesystem::path images_path;
boost::filesystem::path textures_path; boost::filesystem::path textures_path;
boost::filesystem::path fonts_path; boost::filesystem::path fonts_path;
boost::filesystem::path levels_path; boost::filesystem::path levels_path;
@ -25,7 +27,7 @@ private:
std::unordered_map< std::unordered_map<
std::string, std::string,
std::shared_ptr<sf::Image> std::weak_ptr<sfg::Image>
> images_cache; > images_cache;
std::unordered_map< std::unordered_map<
@ -55,6 +57,11 @@ public:
*/ */
std::vector<boost::filesystem::path> getFiles(boost::filesystem::path path) const; std::vector<boost::filesystem::path> getFiles(boost::filesystem::path path) const;
/**
* Récupère le chemin vers le dossier des images
*/
const boost::filesystem::path& getImagesPath() const;
/** /**
* Récupère le chemin vers le dossier des textures * Récupère le chemin vers le dossier des textures
*/ */
@ -78,9 +85,9 @@ public:
/** /**
* Charge l'image dont le chemin est donné en paramètre * Charge l'image dont le chemin est donné en paramètre
*/ */
std::shared_ptr<sf::Image> getImage(boost::filesystem::path path); sfg::Image::Ptr getImage(boost::filesystem::path path);
std::shared_ptr<sf::Image> getImage(std::string name); sfg::Image::Ptr getImage(std::string name);
std::shared_ptr<sf::Image> getImage(const char* name); sfg::Image::Ptr getImage(const char* name);
/** /**
* Charge l'image dont le chemin est donné en paramètre * Charge l'image dont le chemin est donné en paramètre

View File

@ -39,9 +39,7 @@ sfg::Button::Ptr ActionToolbar::createButton(std::string name) {
// création d'un bouton avec pour image l'image passée // création d'un bouton avec pour image l'image passée
sfg::Button::Ptr button = sfg::Button::Create(""); sfg::Button::Ptr button = sfg::Button::Create("");
button->SetClass("icon"); button->SetClass("icon");
button->SetImage(sfg::Image::Create( button->SetImage(ResourceManager::get().getImage(name + ".tga"));
*ResourceManager::get().getImage("toolbar/icon_" + name + ".tga")
));
return button; return button;
} }

View File

@ -69,9 +69,7 @@ ObjectToolbar::ObjectToolbar() {
void ObjectToolbar::addCreator(std::string path, std::function<Object::Ptr()> creator) { void ObjectToolbar::addCreator(std::string path, std::function<Object::Ptr()> creator) {
// on crée un bouton d'objet correspondant au créateur donné // on crée un bouton d'objet correspondant au créateur donné
ObjectButton::Ptr button = ObjectButton::Create( ObjectButton::Ptr button = ObjectButton::Create(
sfg::Image::Create( ResourceManager::get().getImage(path + ".tga")
*ResourceManager::get().getImage("toolbar/" + path + ".tga")
), creators_group
); );
creators[button] = creator; creators[button] = creator;

View File

@ -11,6 +11,8 @@ const float Manager::GRID = 32;
Manager::Manager() : title(sf::String(L"")), previous_time(sf::seconds(0)), Manager::Manager() : title(sf::String(L"")), previous_time(sf::seconds(0)),
previous_state(nullptr) { previous_state(nullptr) {
ResourceManager& res = ResourceManager::get();
// ajout des polices dans le gestionnaire de ressources // ajout des polices dans le gestionnaire de ressources
// de la librairie pour l'interface // de la librairie pour l'interface
desktop.GetEngine().GetResourceManager().AddFont( desktop.GetEngine().GetResourceManager().AddFont(
@ -28,9 +30,7 @@ Manager::Manager() : title(sf::String(L"")), previous_time(sf::seconds(0)),
// chargement du thème de l'interface // chargement du thème de l'interface
desktop.LoadThemeFromFile("res/gui.theme"); desktop.LoadThemeFromFile("res/gui.theme");
// chargement des textures // préchargement des textures dans le GPU
ResourceManager& res = ResourceManager::get();
for (const auto &texture : res.getFiles(res.getTexturesPath())) { for (const auto &texture : res.getFiles(res.getTexturesPath())) {
res.getTexture(texture); res.getTexture(texture);
@ -41,6 +41,15 @@ Manager::Manager() : title(sf::String(L"")), previous_time(sf::seconds(0)),
while (window.pollEvent(event)) {} while (window.pollEvent(event)) {}
} }
// préchargement des images dans la RAM
for (const auto &image : res.getFiles(res.getImagesPath())) {
res.getImage(image);
// mêmes raisons que ci-dessus
sf::Event event;
while (window.pollEvent(event)) {}
}
// création de la fenêtre du jeu // création de la fenêtre du jeu
window.create( window.create(
sf::VideoMode(704, 480), "Skizzle", sf::Style::Default, sf::VideoMode(704, 480), "Skizzle", sf::Style::Default,

View File

@ -14,6 +14,7 @@ ResourceManager::ResourceManager() : is_playing(false), is_muted(false) {
// mise en mémoire des chemins vers les dossiers de ressources // mise en mémoire des chemins vers les dossiers de ressources
fs::path res_path = fs::current_path() / "res"; fs::path res_path = fs::current_path() / "res";
images_path = res_path / "images";
textures_path = res_path / "textures"; textures_path = res_path / "textures";
fonts_path = res_path / "fonts"; fonts_path = res_path / "fonts";
levels_path = res_path / "levels"; levels_path = res_path / "levels";
@ -40,6 +41,10 @@ std::vector<fs::path> ResourceManager::getFiles(fs::path path) const {
return result; return result;
} }
const fs::path& ResourceManager::getImagesPath() const {
return images_path;
}
const fs::path& ResourceManager::getTexturesPath() const { const fs::path& ResourceManager::getTexturesPath() const {
return textures_path; return textures_path;
} }
@ -56,34 +61,42 @@ const fs::path& ResourceManager::getMusicsPath() const {
return musics_path; return musics_path;
} }
std::shared_ptr<sf::Image> ResourceManager::getImage(fs::path path) { sfg::Image::Ptr ResourceManager::getImage(fs::path path) {
std::string path_str = path.string(); std::string path_str = path.string();
// si l'image a déjà été chargée, on retourne la // si l'image a déjà été chargée, on retourne la
// version en cache mémoire // version en cache mémoire
if (images_cache.count(path_str) > 0) { if (images_cache.count(path_str) > 0) {
return images_cache[path_str]; // le cache d'images est constitué de pointeurs "faibles", càd
// que dès que la ressource n'est plus utilisée, le pointeur
// s'invalide. Ceci parce que SFGUI maintient son propre cache.
// on doit donc d'abord vérifier que le pointeur est toujours valide
if (!images_cache[path_str].expired()) {
return images_cache[path_str].lock();
}
} }
// on tente de charger l'image depuis son emplacement // on tente de charger l'image depuis son emplacement
auto image = std::shared_ptr<sf::Image>(new sf::Image); sf::Image image;
if (!image->loadFromFile(path_str)) { if (!image.loadFromFile(path_str)) {
std::cerr << "Impossible de charger l'image :" << std::endl; std::cerr << "Impossible de charger l'image :" << std::endl;
std::cerr << path_str << std::endl << std::endl; std::cerr << path_str << std::endl << std::endl;
} }
// on met en cache l'image pour les requêtes suivantes // création d'une nouvelle image SFGUI avec les infos chargées
// puis on la renvoie // et mise en cache du résultat
images_cache[path_str] = std::move(image); sfg::Image::Ptr sfg_image = sfg::Image::Create(image);
return images_cache[path_str]; images_cache[path_str] = sfg_image;
return sfg_image;
} }
std::shared_ptr<sf::Image> ResourceManager::getImage(std::string name) { sfg::Image::Ptr ResourceManager::getImage(std::string name) {
return getImage(textures_path / name); return getImage(images_path / name);
} }
std::shared_ptr<sf::Image> ResourceManager::getImage(const char* name) { sfg::Image::Ptr ResourceManager::getImage(const char* name) {
return getImage(std::string(name)); return getImage(std::string(name));
} }
@ -95,14 +108,11 @@ std::shared_ptr<sf::Texture> ResourceManager::getTexture(fs::path path) {
return textures_cache[path_str]; return textures_cache[path_str];
} }
// on récupère l'image depuis le disque // on tente de charger la texture depuis le disque vers le GPU
std::shared_ptr<sf::Image> image = getImage(path);
// on transfère l'image vers le GPU
auto texture = std::shared_ptr<sf::Texture>(new sf::Texture); auto texture = std::shared_ptr<sf::Texture>(new sf::Texture);
texture->setSmooth(true); texture->setSmooth(true);
if (!texture->loadFromImage(*image)) { if (!texture->loadFromFile(path_str)) {
std::cerr << "Impossible de créer la texture :" << std::endl; std::cerr << "Impossible de créer la texture :" << std::endl;
std::cerr << path_str << std::endl << std::endl; std::cerr << path_str << std::endl << std::endl;
} }

View File

@ -282,15 +282,15 @@ void Level::frame() {
sf::Vector2i window_size = (sf::Vector2i) window.getSize(); sf::Vector2i window_size = (sf::Vector2i) window.getSize();
// mise à jour de l'icône du mute en fonction de l'état // mise à jour de l'icône du mute en fonction de l'état
sf::Image image; sfg::Image::Ptr image;
if (ResourceManager::get().isMuted()) { if (ResourceManager::get().isMuted()) {
image = *ResourceManager::get().getImage("toolbar/icon_no_music.tga"); image = ResourceManager::get().getImage("no_music.tga");
} else { } else {
image = *ResourceManager::get().getImage("toolbar/icon_music.tga"); image = ResourceManager::get().getImage("music.tga");
} }
mute_button->SetImage(sfg::Image::Create(image)); mute_button->SetImage(image);
// positionnement de la barre d'actions // positionnement de la barre d'actions
action_toolbar.getWindow()->SetAllocation(sf::FloatRect( action_toolbar.getWindow()->SetAllocation(sf::FloatRect(