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/Audio.hpp>
#include <SFGUI/Image.hpp>
#include <boost/filesystem.hpp>
#include <unordered_map>
#include <string>
@ -18,6 +19,7 @@ private:
/**
* Chemins vers les différents dossiers de ressources
*/
boost::filesystem::path images_path;
boost::filesystem::path textures_path;
boost::filesystem::path fonts_path;
boost::filesystem::path levels_path;
@ -25,7 +27,7 @@ private:
std::unordered_map<
std::string,
std::shared_ptr<sf::Image>
std::weak_ptr<sfg::Image>
> images_cache;
std::unordered_map<
@ -55,6 +57,11 @@ public:
*/
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
*/
@ -78,9 +85,9 @@ public:
/**
* Charge l'image dont le chemin est donné en paramètre
*/
std::shared_ptr<sf::Image> getImage(boost::filesystem::path path);
std::shared_ptr<sf::Image> getImage(std::string name);
std::shared_ptr<sf::Image> getImage(const char* name);
sfg::Image::Ptr getImage(boost::filesystem::path path);
sfg::Image::Ptr getImage(std::string name);
sfg::Image::Ptr getImage(const char* name);
/**
* 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
sfg::Button::Ptr button = sfg::Button::Create("");
button->SetClass("icon");
button->SetImage(sfg::Image::Create(
*ResourceManager::get().getImage("toolbar/icon_" + name + ".tga")
));
button->SetImage(ResourceManager::get().getImage(name + ".tga"));
return button;
}

View File

@ -69,9 +69,7 @@ ObjectToolbar::ObjectToolbar() {
void ObjectToolbar::addCreator(std::string path, std::function<Object::Ptr()> creator) {
// on crée un bouton d'objet correspondant au créateur donné
ObjectButton::Ptr button = ObjectButton::Create(
sfg::Image::Create(
*ResourceManager::get().getImage("toolbar/" + path + ".tga")
), creators_group
ResourceManager::get().getImage(path + ".tga")
);
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)),
previous_state(nullptr) {
ResourceManager& res = ResourceManager::get();
// ajout des polices dans le gestionnaire de ressources
// de la librairie pour l'interface
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
desktop.LoadThemeFromFile("res/gui.theme");
// chargement des textures
ResourceManager& res = ResourceManager::get();
// préchargement des textures dans le GPU
for (const auto &texture : res.getFiles(res.getTexturesPath())) {
res.getTexture(texture);
@ -41,6 +41,15 @@ Manager::Manager() : title(sf::String(L"")), previous_time(sf::seconds(0)),
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
window.create(
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
fs::path res_path = fs::current_path() / "res";
images_path = res_path / "images";
textures_path = res_path / "textures";
fonts_path = res_path / "fonts";
levels_path = res_path / "levels";
@ -40,6 +41,10 @@ std::vector<fs::path> ResourceManager::getFiles(fs::path path) const {
return result;
}
const fs::path& ResourceManager::getImagesPath() const {
return images_path;
}
const fs::path& ResourceManager::getTexturesPath() const {
return textures_path;
}
@ -56,34 +61,42 @@ const fs::path& ResourceManager::getMusicsPath() const {
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();
// si l'image a déjà été chargée, on retourne la
// version en cache mémoire
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
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 << path_str << std::endl << std::endl;
}
// on met en cache l'image pour les requêtes suivantes
// puis on la renvoie
images_cache[path_str] = std::move(image);
return images_cache[path_str];
// création d'une nouvelle image SFGUI avec les infos chargées
// et mise en cache du résultat
sfg::Image::Ptr sfg_image = sfg::Image::Create(image);
images_cache[path_str] = sfg_image;
return sfg_image;
}
std::shared_ptr<sf::Image> ResourceManager::getImage(std::string name) {
return getImage(textures_path / name);
sfg::Image::Ptr ResourceManager::getImage(std::string 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));
}
@ -95,14 +108,11 @@ std::shared_ptr<sf::Texture> ResourceManager::getTexture(fs::path path) {
return textures_cache[path_str];
}
// on récupère l'image depuis le disque
std::shared_ptr<sf::Image> image = getImage(path);
// on transfère l'image vers le GPU
// on tente de charger la texture depuis le disque vers le GPU
auto texture = std::shared_ptr<sf::Texture>(new sf::Texture);
texture->setSmooth(true);
if (!texture->loadFromImage(*image)) {
if (!texture->loadFromFile(path_str)) {
std::cerr << "Impossible de créer la texture :" << 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();
// mise à jour de l'icône du mute en fonction de l'état
sf::Image image;
sfg::Image::Ptr image;
if (ResourceManager::get().isMuted()) {
image = *ResourceManager::get().getImage("toolbar/icon_no_music.tga");
image = ResourceManager::get().getImage("no_music.tga");
} 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
action_toolbar.getWindow()->SetAllocation(sf::FloatRect(