diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index d2ffc7374c25..cac73b76f516 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -54,7 +54,7 @@ void GameInfoTex::Clear() { } } -GameInfo::GameInfo() { +GameInfo::GameInfo(const Path &gamePath) : filePath_(gamePath) { // here due to a forward decl. fileType = IdentifiedFileType::UNKNOWN; } @@ -231,26 +231,13 @@ u64 GameInfo::GetInstallDataSizeInBytes() { return totalSize; } -bool GameInfo::LoadFromPath(const Path &gamePath) { - { - std::lock_guard guard(lock); - // No need to rebuild if we already have it loaded. - if (filePath_ == gamePath) { - return true; - } - } - - { +bool GameInfo::CreateLoader() { + if (!fileLoader) { std::lock_guard guard(loaderLock); - fileLoader.reset(ConstructFileLoader(gamePath)); + fileLoader.reset(ConstructFileLoader(filePath_)); if (!fileLoader) return false; } - - std::lock_guard guard(lock); - filePath_ = gamePath; - // This is a fallback title, while we're loading / if unable to load. - title = filePath_.GetFilename(); return true; } @@ -330,7 +317,7 @@ void GameInfo::ParseParamSFO() { std::string GameInfo::GetTitle() { std::lock_guard guard(lock); - if (hasFlags & GameInfoFlags::PARAM_SFO) { + if ((hasFlags & GameInfoFlags::PARAM_SFO) && !title.empty()) { return title; } else { return filePath_.GetFilename(); @@ -463,7 +450,7 @@ class GameInfoWorkItem : public Task { void Run() override { // An early-return will result in the destructor running, where we can set // flags like working and pending. - if (!info_->LoadFromPath(gamePath_)) { + if (!info_->CreateLoader()) { return; } @@ -515,6 +502,7 @@ class GameInfoWorkItem : public Task { info_->id_version = info_->id + "_1.00"; info_->region = GAMEREGION_MAX + 1; // Homebrew } + info_->MarkReadyNoLock(GameInfoFlags::PARAM_SFO); } } @@ -606,6 +594,7 @@ class GameInfoWorkItem : public Task { std::lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); + info_->MarkReadyNoLock(GameInfoFlags::PARAM_SFO); } } if (flags_ & GameInfoFlags::ICON) { @@ -623,6 +612,8 @@ class GameInfoWorkItem : public Task { { if (flags_ & GameInfoFlags::PARAM_SFO) { info_->SetTitle(SaveState::GetTitle(gamePath_)); + std::lock_guard lock(info_->lock); + info_->MarkReadyNoLock(GameInfoFlags::PARAM_SFO); } // Let's use the screenshot as an icon, too. @@ -664,8 +655,10 @@ class GameInfoWorkItem : public Task { } } - ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->icon.data, &info_->lock); - info_->icon.dataLoaded = true; + if (flags_ & GameInfoFlags::ICON) { + ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->icon.data, &info_->lock); + info_->icon.dataLoaded = true; + } if (flags_ & GameInfoFlags::BG) { ReadFileToString(&umd, "/PSP_GAME/PIC0.PNG", &info_->pic0.data, &info_->lock); info_->pic0.dataLoaded = true; @@ -704,6 +697,9 @@ class GameInfoWorkItem : public Task { std::lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); + + // quick-update the info while we have the lock, so we don't need to wait for the image load to display the title. + info_->MarkReadyNoLock(GameInfoFlags::PARAM_SFO); } } } @@ -781,8 +777,7 @@ class GameInfoWorkItem : public Task { // Time to update the flags. std::unique_lock lock(info_->lock); - info_->hasFlags |= flags_; - info_->pendingFlags &= ~flags_; + info_->MarkReadyNoLock(flags_); // INFO_LOG(SYSTEM, "Completed writing info for %s", info_->GetTitle().c_str()); } @@ -846,26 +841,39 @@ void GameInfoCache::FlushBGs() { void GameInfoCache::PurgeType(IdentifiedFileType fileType) { bool retry = false; + int retryCount = 10; // Trickery to avoid sleeping with the lock held. do { + if (retry) { + retryCount--; + if (retryCount == 0) { + break; + } + } + retry = false; { std::lock_guard lock(mapLock_); for (auto iter = info_.begin(); iter != info_.end();) { auto &info = iter->second; - + if (!(info->hasFlags & GameInfoFlags::FILE_TYPE)) { + iter++; + continue; + } + if (info->fileType != fileType) { + iter++; + continue; + } // TODO: Find a better way to wait here. - while (info->pendingFlags != (GameInfoFlags)0) { + if (info->pendingFlags != (GameInfoFlags)0) { + INFO_LOG(LOADER, "%s: pending flags %08x, retrying", info->GetTitle().c_str(), info->pendingFlags); retry = true; break; } - if (info->fileType == fileType) { - iter = info_.erase(iter); - } else { - iter++; - } + iter = info_.erase(iter); } } - sleep_ms(1); + + sleep_ms(10); } while (retry); } @@ -903,7 +911,7 @@ std::shared_ptr GameInfoCache::GetInfo(Draw::DrawContext *draw, const return info; } - std::shared_ptr info = std::make_shared(); + std::shared_ptr info = std::make_shared(gamePath); info->pendingFlags = wantFlags; info->lastAccessedTime = time_now_d(); info_.insert(std::make_pair(pathStr, info)); diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index f251aea49442..f8d91b86e707 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -82,12 +82,12 @@ struct GameInfoTex { class GameInfo { public: - GameInfo(); + GameInfo(const Path &gamePath); ~GameInfo(); bool Delete(); // Better be sure what you're doing when calling this. bool DeleteAllSaveData(); - bool LoadFromPath(const Path &gamePath); + bool CreateLoader(); bool HasFileLoader() const { return fileLoader.get() != nullptr; @@ -114,6 +114,11 @@ class GameInfo { return (hasFlags & flags) != 0; } + void MarkReadyNoLock(GameInfoFlags flags) { + hasFlags |= flags; + pendingFlags &= ~flags; + } + GameInfoTex *GetBGPic() { if (pic1.texture) return &pic1; diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index fd7b9b342ea7..6350d3aead6d 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -300,7 +300,7 @@ void SavedataButton::Draw(UIContext &dc) { u32 color = 0, shadowColor = 0; using namespace UI; - if (ginfo->icon.texture) { + if (ginfo->Ready(GameInfoFlags::ICON) && ginfo->icon.texture) { texture = ginfo->icon.texture; }