TextureCache.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include "TextureCache.h"
  2. #include "AlbumTexture.h"
  3. #include "WallpaperEngine/FileSystem/Container.h"
  4. #include "CTexture.h"
  5. #include "WallpaperEngine/Assets/AssetLoadException.h"
  6. #include "WallpaperEngine/Render/Helpers/ContextAware.h"
  7. #include "WallpaperEngine/Data/Model/Project.h"
  8. #include "WallpaperEngine/Data/Parsers/TextureParser.h"
  9. #include <algorithm>
  10. #include <chrono>
  11. #include <filesystem>
  12. #include <fstream>
  13. using namespace WallpaperEngine::Render;
  14. using namespace WallpaperEngine::FileSystem;
  15. using namespace WallpaperEngine::Data::Parsers;
  16. using namespace WallpaperEngine::Data::Assets;
  17. TextureCache::TextureCache (RenderContext& context) : Helpers::ContextAware (context) {
  18. this->m_currentThumbnail = std::make_shared<AlbumTexture> (this->getContext ());
  19. #if !NDEBUG
  20. glObjectLabel (GL_TEXTURE, this->m_currentThumbnail->getTextureID (0), -1, "$mediaThumbnail");
  21. #endif
  22. this->m_previousThumbnail = std::make_shared<AlbumTexture> (this->getContext ());
  23. #if !NDEBUG
  24. glObjectLabel (GL_TEXTURE, this->m_previousThumbnail->getTextureID (0), -1, "$mediaPreviousThumbnail");
  25. #endif
  26. this->m_currentThumbnail->load ();
  27. this->store ("$mediaThumbnail", this->m_currentThumbnail);
  28. this->store ("$mediaPreviousThumbnail", this->m_previousThumbnail);
  29. this->m_mediaCallback = this->getContext ().getMediaSource ().addAlbumArtListener (
  30. [this] (const Media::MediaSource::MediaInfo& data) {
  31. if (this->m_currentThumbnail->isReady ()) {
  32. this->m_previousThumbnail->copyContents (*this->m_currentThumbnail);
  33. }
  34. this->m_currentThumbnail->load ();
  35. }
  36. );
  37. }
  38. TextureCache::~TextureCache () { this->m_mediaCallback (); }
  39. std::shared_ptr<const TextureProvider> TextureCache::resolve (const std::string& filename, const Project& requester) {
  40. if (const auto shared = this->m_sharedTextures.find (filename); shared != this->m_sharedTextures.end ()) {
  41. return shared->second;
  42. }
  43. const auto key = std::make_pair (&requester, filename);
  44. if (const auto found = this->m_textureCache.find (key); found != this->m_textureCache.end ()) {
  45. return found->second;
  46. }
  47. const auto load = [&] (const Project& project) {
  48. const auto contents = project.assetLocator->texture (filename);
  49. auto stream = BinaryReader (contents);
  50. auto metadataLoader = [&project] (const std::string& metaFilename) -> std::string {
  51. std::filesystem::path fullPath = std::filesystem::path ("materials") / metaFilename;
  52. return project.assetLocator->readString (fullPath);
  53. };
  54. auto parsedTexture = TextureParser::parse (stream, filename, metadataLoader);
  55. auto texture = std::make_shared<CTexture> (this->getContext (), std::move (parsedTexture));
  56. #if !NDEBUG
  57. glObjectLabel (GL_TEXTURE, texture->getTextureID (0), -1, filename.c_str ());
  58. #endif
  59. this->m_textureCache.insert_or_assign (key, texture);
  60. return texture;
  61. };
  62. try {
  63. return load (requester);
  64. } catch (AssetLoadException&) {
  65. // not shipped by the requesting project itself, it might still live in another loaded one
  66. }
  67. for (const auto& project : this->getContext ().getApp ().getBackgrounds () | std::views::values) {
  68. if (project.get () == &requester) {
  69. continue;
  70. }
  71. try {
  72. return load (*project);
  73. } catch (AssetLoadException&) {
  74. // ignored, this happens if we're looking at the wrong background
  75. }
  76. }
  77. // TODO: fill in with a checkered pattern texture instead?
  78. throw AssetLoadException ("Cannot find file", filename, std::error_code ());
  79. }
  80. void TextureCache::store (const std::string& name, std::shared_ptr<const TextureProvider> texture) {
  81. this->m_sharedTextures.insert_or_assign (name, texture);
  82. }
  83. void TextureCache::prune () {
  84. const auto& backgrounds = this->getContext ().getApp ().getBackgrounds ();
  85. // entries of a gone project must not be inherited by a new one allocated at the same address
  86. std::erase_if (this->m_textureCache, [&backgrounds] (const auto& entry) {
  87. const auto alive = std::ranges::any_of (backgrounds, [&entry] (const auto& background) {
  88. return background.second.get () == entry.first.first;
  89. });
  90. return !alive || entry.second.use_count () == 1;
  91. });
  92. }