From f777e01a217778fe206f74d130fc6514bef11906 Mon Sep 17 00:00:00 2001 From: Benau Date: Sat, 13 Aug 2022 11:44:06 +0800 Subject: [PATCH] Make kart textures loading ondemand if needed --- lib/graphics_engine/include/ge_main.hpp | 3 + lib/graphics_engine/src/ge_main.cpp | 7 +- lib/graphics_engine/src/ge_vulkan_texture.cpp | 2 + lib/graphics_engine/src/ge_vulkan_texture.hpp | 4 + lib/irrlicht/include/ITexture.h | 4 + src/graphics/irr_driver.cpp | 2 + src/graphics/stk_tex_manager.hpp | 3 + src/karts/kart_properties.cpp | 56 ++++++++++-- src/karts/kart_properties.hpp | 4 +- src/karts/kart_properties_manager.cpp | 85 +++++++++++++++++++ src/karts/kart_properties_manager.hpp | 4 + src/main.cpp | 2 + src/race/race_manager.cpp | 14 +++ 13 files changed, 183 insertions(+), 7 deletions(-) diff --git a/lib/graphics_engine/include/ge_main.hpp b/lib/graphics_engine/include/ge_main.hpp index ec799b3a5..8356a68e7 100644 --- a/lib/graphics_engine/include/ge_main.hpp +++ b/lib/graphics_engine/include/ge_main.hpp @@ -3,8 +3,10 @@ #include #include + #include #include +#include namespace GE { @@ -14,6 +16,7 @@ struct GEConfig bool m_disable_npot_texture; bool m_convert_irrlicht_mesh; bool m_texture_compression; +std::unordered_set m_ondemand_load_texture_paths; }; void setVideoDriver(irr::video::IVideoDriver* driver); diff --git a/lib/graphics_engine/src/ge_main.cpp b/lib/graphics_engine/src/ge_main.cpp index badc8a940..559ab07b9 100644 --- a/lib/graphics_engine/src/ge_main.cpp +++ b/lib/graphics_engine/src/ge_main.cpp @@ -13,7 +13,12 @@ std::chrono::steady_clock::time_point g_mono_start = void setVideoDriver(irr::video::IVideoDriver* driver) { - g_driver = driver; + if (driver != g_driver) + { + // Reset everytime driver is recreated + g_config.m_ondemand_load_texture_paths.clear(); + g_driver = driver; + } } irr::video::IVideoDriver* getDriver() diff --git a/lib/graphics_engine/src/ge_vulkan_texture.cpp b/lib/graphics_engine/src/ge_vulkan_texture.cpp index 88b6156ce..4ed875116 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.cpp @@ -43,6 +43,8 @@ GEVulkanTexture::GEVulkanTexture(const std::string& path, return; } + auto& paths = getGEConfig()->m_ondemand_load_texture_paths; + m_ondemand_load = (paths.find(m_full_path.c_str()) != paths.end()); if (m_ondemand_load) { video::IImageLoader* loader = NULL; diff --git a/lib/graphics_engine/src/ge_vulkan_texture.hpp b/lib/graphics_engine/src/ge_vulkan_texture.hpp index d046c2ef6..11cb28248 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.hpp @@ -214,6 +214,10 @@ public: return getImageViewLive(); } // ------------------------------------------------------------------------ + virtual bool useOnDemandLoad() const { return m_ondemand_load; } + // ------------------------------------------------------------------------ + virtual const io::path& getFullPath() const { return m_full_path; } + // ------------------------------------------------------------------------ VkFormat getInternalFormat() const { return m_internal_format; } }; // GEVulkanTexture diff --git a/lib/irrlicht/include/ITexture.h b/lib/irrlicht/include/ITexture.h index a538889fc..12de6cf2f 100644 --- a/lib/irrlicht/include/ITexture.h +++ b/lib/irrlicht/include/ITexture.h @@ -204,6 +204,10 @@ public: virtual void reload() {} virtual bool loadingFailed() const { return LoadingFailed; } + + virtual bool useOnDemandLoad() const { return false; } + + virtual const io::path& getFullPath() const { return NamedPath.getPath(); } protected: //! Helper function, helps to get the desired texture creation format from the flags. diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 56d98012c..d81e7b8c1 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -1132,6 +1132,8 @@ void IrrDriver::applyResolutionSettings(bool recreate_device) kart_properties_manager->loadAllKarts(); + kart_properties_manager->onDemandLoadKartTextures( + { UserConfigParams::m_default_kart }, false/*unload_unused*/); attachment_manager->loadModels(); file_manager->popTextureSearchPath(); diff --git a/src/graphics/stk_tex_manager.hpp b/src/graphics/stk_tex_manager.hpp index f2b3d4ab2..678ebddf7 100644 --- a/src/graphics/stk_tex_manager.hpp +++ b/src/graphics/stk_tex_manager.hpp @@ -119,6 +119,9 @@ public: return getTexture(filename, std::string(error_message), std::string(detail)); } // getTexture + // ------------------------------------------------------------------------ + std::unordered_map& getAllTextures() + { return m_all_textures; } }; // STKTexManager diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 76e1a944c..84e68c810 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -47,6 +47,9 @@ #include #include +#ifndef SERVER_ONLY +#include +#endif float KartProperties::UNDEFINED = -99.9f; @@ -116,12 +119,27 @@ KartProperties::KartProperties(const std::string &filename) KartProperties::~KartProperties() { #ifndef SERVER_ONLY - if (CVS->isGLSL() && m_kart_model.use_count() == 1) + if (m_kart_model.use_count() == 1) { - m_kart_model = nullptr; - SP::SPShaderManager::get()->removeUnusedShaders(); - ShaderFilesManager::getInstance()->removeUnusedShaderFiles(); - SP::SPTextureManager::get()->removeUnusedTextures(); + if (CVS->isGLSL()) + { + m_kart_model = nullptr; + SP::SPShaderManager::get()->removeUnusedShaders(); + ShaderFilesManager::getInstance()->removeUnusedShaderFiles(); + SP::SPTextureManager::get()->removeUnusedTextures(); + } + + if (GE::getDriver()->getDriverType() != video::EDT_VULKAN) + return; + auto& paths = GE::getGEConfig()->m_ondemand_load_texture_paths; + auto it = paths.begin(); + while (it != paths.end()) + { + if (StringUtils::startsWith(*it, m_root_absolute_path)) + it = paths.erase(it); + else + it++; + } } #endif } // ~KartProperties @@ -176,6 +194,33 @@ void KartProperties::copyFrom(const KartProperties *source) } } // copyFrom +//----------------------------------------------------------------------------- +void KartProperties::handleOnDemandLoadTexture() +{ +#ifndef SERVER_ONLY + if (GE::getDriver()->getDriverType() != video::EDT_VULKAN) + return; + std::set files; + // Remove the last / + m_root_absolute_path = StringUtils::getPath(m_root); + m_root_absolute_path = file_manager->getFileSystem() + ->getAbsolutePath(m_root_absolute_path.c_str()).c_str(); + + file_manager->listFiles(files, m_root_absolute_path, + true/*make_full_path*/); + std::set image_extensions = + { + "png", "jpg", "jpeg", "jpe", "svg" + }; + for (const std::string& f : files) + { + if (image_extensions.find(StringUtils::getExtension(f)) != + image_extensions.end()) + GE::getGEConfig()->m_ondemand_load_texture_paths.insert(f); + } +#endif +} // handleOnDemandLoadTexture + //----------------------------------------------------------------------------- /** Loads the kart properties from a file. * \param filename Filename to load. @@ -220,6 +265,7 @@ void KartProperties::load(const std::string &filename, const std::string &node) m_is_addon = true; } + handleOnDemandLoadTexture(); try { if(!root || root->getName()!="kart") diff --git a/src/karts/kart_properties.hpp b/src/karts/kart_properties.hpp index 622de2d62..808ac7ae9 100644 --- a/src/karts/kart_properties.hpp +++ b/src/karts/kart_properties.hpp @@ -60,7 +60,7 @@ class KartProperties { private: /** Base directory for this kart. */ - std::string m_root; + std::string m_root, m_root_absolute_path; /** AI Properties for this kart, as a separate object in order to * reduce dependencies (and therefore compile time) when changing @@ -209,6 +209,8 @@ private: // closely (+-0,1%) with the specifications in kart_characteristics.xml m_wheel_base = fabsf(kart_length / 1.425f); } + + void handleOnDemandLoadTexture(); public: /** Returns the string representation of a handicap level. */ static std::string getHandicapAsString(HandicapLevel h); diff --git a/src/karts/kart_properties_manager.cpp b/src/karts/kart_properties_manager.cpp index 40256d12e..b8c662e52 100644 --- a/src/karts/kart_properties_manager.cpp +++ b/src/karts/kart_properties_manager.cpp @@ -38,6 +38,12 @@ #include #include +#ifndef SERVER_ONLY +#include +#include +#include "graphics/stk_tex_manager.hpp" +#endif + KartPropertiesManager *kart_properties_manager=0; std::vector KartPropertiesManager::m_kart_search_path; @@ -611,4 +617,83 @@ void KartPropertiesManager::getRandomKartList(int count, assert(count==0); } // getRandomKartList +//----------------------------------------------------------------------------- +void KartPropertiesManager::onDemandLoadKartTextures( + const std::set& kart_list, + bool unload_unused) +{ +#ifndef SERVER_ONLY + if (kart_list.empty()) + return; + + GE::GEVulkanDriver* gevd = GE::getVKDriver(); + if (!gevd) + return; + gevd->waitIdle(); + gevd->setDisableWaitIdle(true); + + std::set karts_folder; + for (auto& dir : m_kart_search_path) + { + std::string kart_dir = file_manager->getFileSystem() + ->getAbsolutePath(dir.c_str()).c_str(); + karts_folder.insert(StringUtils::getPath(kart_dir)); + } + + std::set ingame_karts_folder; + for (auto& kart : kart_list) + { + const KartProperties* kp = getKart(kart); + if (!kp) + continue; + std::string kart_dir = file_manager->getFileSystem() + ->getAbsolutePath(kp->getKartDir().c_str()).c_str(); + ingame_karts_folder.insert(StringUtils::getPath(kart_dir)); + } + + bool unloaded_unused = false; + for (auto tex : STKTexManager::getInstance()->getAllTextures()) + { + if (!tex.second || !tex.second->useOnDemandLoad()) + continue; + std::string full_path = tex.second->getFullPath().c_str(); + bool is_kart_texture = false; + bool in_use = false; + for (auto& dir : karts_folder) + { + if (StringUtils::startsWith(full_path, dir)) + { + is_kart_texture = true; + break; + } + } + if (is_kart_texture) + { + for (auto& dir : ingame_karts_folder) + { + if (StringUtils::startsWith(full_path, dir)) + { + in_use = true; + break; + } + } + } + // This will load the ondemand kart textures now or unload the unused + // kart textures + if (in_use) + tex.second->getTextureHandler(); + else if (unload_unused) + { + unloaded_unused = true; + tex.second->reload(); + } + } + + gevd->setDisableWaitIdle(false); + if (unloaded_unused) + gevd->handleDeletedTextures(); +#endif +} // onDemandLoadKartTextures + + /* EOF */ diff --git a/src/karts/kart_properties_manager.hpp b/src/karts/kart_properties_manager.hpp index 917659f1f..fa6b336a8 100644 --- a/src/karts/kart_properties_manager.hpp +++ b/src/karts/kart_properties_manager.hpp @@ -23,6 +23,7 @@ #include "utils/ptr_vector.hpp" #include #include +#include #include "network/remote_kart_info.hpp" #include "utils/no_copy.hpp" @@ -137,6 +138,9 @@ public: const unsigned int getNumberOfKarts() const { return (unsigned int)m_karts_properties.size(); } // getNumberOfKarts + // ------------------------------------------------------------------------ + void onDemandLoadKartTextures(const std::set& kart_list, + bool unload_unused = true); }; extern KartPropertiesManager *kart_properties_manager; diff --git a/src/main.cpp b/src/main.cpp index 32a5ac647..8854b2dc8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2282,6 +2282,8 @@ int main(int argc, char *argv[]) GUIEngine::addLoadingIcon( irr_driver->getTexture(FileManager::GUI_ICON, "options_video.png")); kart_properties_manager -> loadAllKarts (); + kart_properties_manager->onDemandLoadKartTextures( + { UserConfigParams::m_default_kart }, false/*unload_unused*/); OfficialKarts::load(); handleXmasMode(); handleEasterEarMode(); diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 158c95b62..32c7fd9bf 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -449,6 +449,12 @@ void RaceManager::startNew(bool from_overworld) Log::verbose("RaceManager", "Nb of karts=%u, ghost karts:%u ai:%lu players:%lu\n", (unsigned int) m_num_karts, m_num_ghost_karts, m_ai_kart_list.size(), m_player_karts.size()); + std::set used_karts; + for (auto& kart : m_ai_kart_list) + used_karts.insert(kart); + for (auto& kart : m_player_karts) + used_karts.insert(kart.getKartName()); + kart_properties_manager->onDemandLoadKartTextures(used_karts); assert((unsigned int)m_num_karts == m_num_ghost_karts+m_ai_kart_list.size()+m_player_karts.size()); @@ -979,6 +985,7 @@ void RaceManager::exitRace(bool delete_world) setNumKarts(0); setNumPlayers(0); + std::set used_karts; if (some_human_player_well_ranked) { startSingleRace("gpwin", 999, @@ -987,6 +994,9 @@ void RaceManager::exitRace(bool delete_world) scene->push(); scene->setKarts(winners); scene->setPlayerWon(some_human_player_won); + std::set karts; + for (auto& kart : winners) + used_karts.insert(kart.first); } else { @@ -998,6 +1008,8 @@ void RaceManager::exitRace(bool delete_world) if (humanLosers.size() >= 1) { scene->setKarts(humanLosers); + for (auto& kart : humanLosers) + used_karts.insert(kart.first); } else { @@ -1005,9 +1017,11 @@ void RaceManager::exitRace(bool delete_world) "This should have never happened\n"); std::vector > karts; karts.emplace_back(UserConfigParams::m_default_kart, 0.0f); + used_karts.insert(UserConfigParams::m_default_kart); scene->setKarts(karts); } } + kart_properties_manager->onDemandLoadKartTextures(used_karts); } if (delete_world)