Hold a reference to current images in the placefile manager, removing old, unused images

This commit is contained in:
Dan Paulat 2023-09-17 00:28:54 -05:00
parent 9165d66a33
commit bbaae5d1ba
5 changed files with 68 additions and 63 deletions

View file

@ -51,7 +51,8 @@ public:
void ReadPlacefileSettings(); void ReadPlacefileSettings();
void WritePlacefileSettings(); void WritePlacefileSettings();
static void LoadResources(const std::shared_ptr<gr::Placefile>& placefile); static std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
LoadResources(const std::shared_ptr<gr::Placefile>& placefile);
boost::asio::thread_pool threadPool_ {1u}; boost::asio::thread_pool threadPool_ {1u};
@ -134,6 +135,8 @@ public:
std::mutex refreshMutex_ {}; std::mutex refreshMutex_ {};
std::mutex timerMutex_ {}; std::mutex timerMutex_ {};
std::vector<std::shared_ptr<boost::gil::rgba8_image_t>> images_ {};
std::string lastRadarSite_ {}; std::string lastRadarSite_ {};
std::chrono::system_clock::time_point lastUpdateTime_ {}; std::chrono::system_clock::time_point lastUpdateTime_ {};
}; };
@ -276,6 +279,7 @@ void PlacefileManager::set_placefile_url(const std::string& name,
auto placefileRecord = it->second; auto placefileRecord = it->second;
placefileRecord->name_ = normalizedUrl; placefileRecord->name_ = normalizedUrl;
placefileRecord->placefile_ = nullptr; placefileRecord->placefile_ = nullptr;
placefileRecord->images_.clear();
p->placefileRecordMap_.erase(it); p->placefileRecordMap_.erase(it);
p->placefileRecordMap_.insert_or_assign(normalizedUrl, placefileRecord); p->placefileRecordMap_.insert_or_assign(normalizedUrl, placefileRecord);
@ -633,7 +637,7 @@ void PlacefileManager::Impl::PlacefileRecord::Update()
if (updatedPlacefile != nullptr) if (updatedPlacefile != nullptr)
{ {
// Load placefile resources // Load placefile resources
Impl::LoadResources(updatedPlacefile); auto newImages = Impl::LoadResources(updatedPlacefile);
// Check the name matches, in case the name updated // Check the name matches, in case the name updated
if (name_ == name) if (name_ == name)
@ -643,6 +647,10 @@ void PlacefileManager::Impl::PlacefileRecord::Update()
title_ = placefile_->title(); title_ = placefile_->title();
lastUpdateTime_ = std::chrono::system_clock::now(); lastUpdateTime_ = std::chrono::system_clock::now();
// Update image resources
images_.swap(newImages);
newImages.clear();
if (p->radarSite_ != nullptr) if (p->radarSite_ != nullptr)
{ {
lastRadarSite_ = p->radarSite_->id(); lastRadarSite_ = p->radarSite_->id();
@ -736,7 +744,8 @@ std::shared_ptr<PlacefileManager> PlacefileManager::Instance()
return placefileManager; return placefileManager;
} }
void PlacefileManager::Impl::LoadResources( std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
PlacefileManager::Impl::LoadResources(
const std::shared_ptr<gr::Placefile>& placefile) const std::shared_ptr<gr::Placefile>& placefile)
{ {
const auto iconFiles = placefile->icon_files(); const auto iconFiles = placefile->icon_files();
@ -790,7 +799,7 @@ void PlacefileManager::Impl::LoadResources(
} }
} }
ResourceManager::LoadImageResources(urlStrings); return ResourceManager::LoadImageResources(urlStrings);
} }
} // namespace manager } // namespace manager

View file

@ -64,36 +64,40 @@ std::shared_ptr<util::Font> Font(types::Font font)
return nullptr; return nullptr;
} }
bool LoadImageResource(const std::string& urlString) std::shared_ptr<boost::gil::rgba8_image_t>
LoadImageResource(const std::string& urlString)
{ {
util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance(); util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance();
return textureAtlas.CacheTexture(urlString, urlString); return textureAtlas.CacheTexture(urlString, urlString);
} }
void LoadImageResources(const std::vector<std::string>& urlStrings) std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
LoadImageResources(const std::vector<std::string>& urlStrings)
{ {
std::mutex m {}; std::mutex m {};
bool textureCached = false; std::vector<std::shared_ptr<boost::gil::rgba8_image_t>> images {};
std::for_each(std::execution::par_unseq, std::for_each(std::execution::par_unseq,
urlStrings.begin(), urlStrings.begin(),
urlStrings.end(), urlStrings.end(),
[&](auto& urlString) [&](auto& urlString)
{ {
bool value = LoadImageResource(urlString); auto image = LoadImageResource(urlString);
if (value) if (image != nullptr)
{ {
std::unique_lock lock {m}; std::unique_lock lock {m};
textureCached = true; images.emplace_back(std::move(image));
} }
}); });
if (textureCached) if (!images.empty())
{ {
util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance(); util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance();
textureAtlas.BuildAtlas(2048, 2048); textureAtlas.BuildAtlas(2048, 2048);
} }
return images;
} }
static void LoadFonts() static void LoadFonts()

View file

@ -3,6 +3,10 @@
#include <scwx/qt/types/font_types.hpp> #include <scwx/qt/types/font_types.hpp>
#include <scwx/qt/util/font.hpp> #include <scwx/qt/util/font.hpp>
#include <vector>
#include <boost/gil/typedefs.hpp>
namespace scwx namespace scwx
{ {
namespace qt namespace qt
@ -18,8 +22,10 @@ void Shutdown();
int FontId(types::Font font); int FontId(types::Font font);
std::shared_ptr<util::Font> Font(types::Font font); std::shared_ptr<util::Font> Font(types::Font font);
bool LoadImageResource(const std::string& urlString); std::shared_ptr<boost::gil::rgba8_image_t>
void LoadImageResources(const std::vector<std::string>& urlStrings); LoadImageResource(const std::string& urlString);
std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
LoadImageResources(const std::vector<std::string>& urlStrings);
} // namespace ResourceManager } // namespace ResourceManager
} // namespace manager } // namespace manager

View file

@ -48,11 +48,12 @@ public:
static std::shared_ptr<boost::gil::rgba8_image_t> static std::shared_ptr<boost::gil::rgba8_image_t>
LoadImage(const std::string& imagePath); LoadImage(const std::string& imagePath);
std::unordered_map<std::string, std::string> texturePathMap_ {}; std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
std::shared_mutex texturePathMutex_ {}; registeredTextures_ {};
std::shared_mutex registeredTextureMutex_ {};
std::shared_mutex textureCacheMutex_ {}; std::shared_mutex textureCacheMutex_ {};
std::unordered_map<std::string, std::shared_ptr<boost::gil::rgba8_image_t>> std::unordered_map<std::string, std::weak_ptr<boost::gil::rgba8_image_t>>
textureCache_ {}; textureCache_ {};
std::vector<boost::gil::rgba8_image_t> atlasArray_ {}; std::vector<boost::gil::rgba8_image_t> atlasArray_ {};
@ -76,12 +77,14 @@ std::uint64_t TextureAtlas::BuildCount() const
void TextureAtlas::RegisterTexture(const std::string& name, void TextureAtlas::RegisterTexture(const std::string& name,
const std::string& path) const std::string& path)
{ {
std::unique_lock lock(p->texturePathMutex_); std::unique_lock lock(p->registeredTextureMutex_);
p->texturePathMap_.insert_or_assign(name, path);
std::shared_ptr<boost::gil::rgba8_image_t> image = CacheTexture(name, path);
p->registeredTextures_.emplace_back(std::move(image));
} }
bool TextureAtlas::CacheTexture(const std::string& name, std::shared_ptr<boost::gil::rgba8_image_t>
const std::string& path) TextureAtlas::CacheTexture(const std::string& name, const std::string& path)
{ {
// Attempt to load the image // Attempt to load the image
std::shared_ptr<boost::gil::rgba8_image_t> image = std::shared_ptr<boost::gil::rgba8_image_t> image =
@ -93,12 +96,12 @@ bool TextureAtlas::CacheTexture(const std::string& name,
// Store it in the texture cache // Store it in the texture cache
std::unique_lock lock(p->textureCacheMutex_); std::unique_lock lock(p->textureCacheMutex_);
p->textureCache_.insert_or_assign(name, std::move(image)); p->textureCache_.insert_or_assign(name, image);
return true; return image;
} }
return false; return nullptr;
} }
void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height) void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height)
@ -118,50 +121,28 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height)
ImageVector images {}; ImageVector images {};
std::vector<stbrp_rect> stbrpRects {}; std::vector<stbrp_rect> stbrpRects {};
// Load images
{
// Take a read lock on the texture path map
std::shared_lock lock(p->texturePathMutex_);
// For each registered texture
std::for_each(
p->texturePathMap_.cbegin(),
p->texturePathMap_.cend(),
[&](const auto& pair)
{
// Load texture image
std::shared_ptr<boost::gil::rgba8_image_t> image =
Impl::LoadImage(pair.second);
if (image != nullptr && image->width() > 0u && image->height() > 0u)
{
// Store STB rectangle pack data in a vector
stbrpRects.push_back(
stbrp_rect {0,
static_cast<stbrp_coord>(image->width()),
static_cast<stbrp_coord>(image->height()),
0,
0,
0});
// Store image data in a vector
images.emplace_back(pair.first, std::move(image));
}
});
}
// Cached images // Cached images
{ {
// Take a read lock on the texture cache map while adding textures images // Take a lock on the texture cache map while adding textures images to
// to the atlas vector. // the atlas vector.
std::shared_lock textureCacheLock(p->textureCacheMutex_); std::unique_lock textureCacheLock(p->textureCacheMutex_);
// For each cached texture // For each cached texture
for (auto& texture : p->textureCache_) for (auto it = p->textureCache_.begin(); it != p->textureCache_.end();)
{ {
auto& image = texture.second; auto& texture = *it;
auto image = texture.second.lock();
if (image != nullptr && image->width() > 0u && image->height() > 0u) if (image == nullptr)
{
logger_->trace("Removing texture from the cache: {}",
texture.first);
// If the image is no longer cached, erase the iterator and continue
it = p->textureCache_.erase(it);
continue;
}
else if (image->width() > 0u && image->height() > 0u)
{ {
// Store STB rectangle pack data in a vector // Store STB rectangle pack data in a vector
stbrpRects.push_back( stbrpRects.push_back(
@ -175,6 +156,9 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height)
// Store image data in a vector // Store image data in a vector
images.push_back({texture.first, image}); images.push_back({texture.first, image});
} }
// Increment iterator
++it;
} }
} }

View file

@ -6,6 +6,7 @@
#include <string> #include <string>
#include <boost/gil/point.hpp> #include <boost/gil/point.hpp>
#include <boost/gil/typedefs.hpp>
namespace scwx namespace scwx
{ {
@ -73,7 +74,8 @@ public:
std::uint64_t BuildCount() const; std::uint64_t BuildCount() const;
void RegisterTexture(const std::string& name, const std::string& path); void RegisterTexture(const std::string& name, const std::string& path);
bool CacheTexture(const std::string& name, const std::string& path); std::shared_ptr<boost::gil::rgba8_image_t>
CacheTexture(const std::string& name, const std::string& path);
void BuildAtlas(std::size_t width, std::size_t height); void BuildAtlas(std::size_t width, std::size_t height);
void BufferAtlas(gl::OpenGLFunctions& gl, GLuint texture); void BufferAtlas(gl::OpenGLFunctions& gl, GLuint texture);