Merge pull request #22394 from hrydgard/gameinfo-priorities

GameInfoCache: Prioritize loads, so launching doesn't wait behind search
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-09-29 17:05:27 -06:00
commit 3bcd93d594
4 files changed
+27 -10

No files matched your search

+2 -1
View File
@@ -473,7 +473,8 @@ void GameButton::Draw(UIContext &dc) {
} }
std::string GameButton::DescribeText() const { std::string GameButton::DescribeText() const {
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(nullptr, gamePath_, GameInfoFlags::PARAM_SFO); // LOW: search calls this for every game in the list, which mustn't hold up the visible ones.
std::shared_ptr<GameInfo> ginfo = g_gameInfoCache->GetInfo(nullptr, gamePath_, GameInfoFlags::PARAM_SFO, nullptr, GameInfoFlags::EMPTY, TaskPriority::LOW);
if (!ginfo->Ready(GameInfoFlags::PARAM_SFO)) if (!ginfo->Ready(GameInfoFlags::PARAM_SFO))
return "..."; return "...";
auto u = GetI18NCategory(I18NCat::UI_ELEMENTS); auto u = GetI18NCategory(I18NCat::UI_ELEMENTS);
+16 -6
View File
@@ -541,8 +541,8 @@ static bool LoadReplacementImage(GameInfo *info, GameInfoTex *tex, const char *f
class GameInfoWorkItem : public Task { class GameInfoWorkItem : public Task {
public: public:
GameInfoWorkItem(const Path &gamePath, std::shared_ptr<GameInfo> &info, GameInfoFlags flags) GameInfoWorkItem(const Path &gamePath, std::shared_ptr<GameInfo> &info, GameInfoFlags flags, TaskPriority priority)
: gamePath_(gamePath), info_(info), flags_(flags) {} : gamePath_(gamePath), info_(info), flags_(flags), priority_(priority) {}
~GameInfoWorkItem() { ~GameInfoWorkItem() {
info_->DisposeFileLoader(); info_->DisposeFileLoader();
@@ -553,10 +553,14 @@ public:
} }
TaskPriority Priority() const override { TaskPriority Priority() const override {
if (priority_ == TaskPriority::HIGH) {
// Someone's waiting on this, wherever it is.
return TaskPriority::HIGH;
}
switch (gamePath_.Type()) { switch (gamePath_.Type()) {
case PathType::NATIVE: case PathType::NATIVE:
case PathType::CONTENT_URI: case PathType::CONTENT_URI:
return TaskPriority::NORMAL; return priority_;
default: default:
// Remote/network access. // Remote/network access.
@@ -997,6 +1001,7 @@ private:
Path gamePath_; Path gamePath_;
std::shared_ptr<GameInfo> info_; std::shared_ptr<GameInfo> info_;
GameInfoFlags flags_{}; GameInfoFlags flags_{};
TaskPriority priority_;
DISALLOW_COPY_AND_ASSIGN(GameInfoWorkItem); DISALLOW_COPY_AND_ASSIGN(GameInfoWorkItem);
}; };
@@ -1110,7 +1115,7 @@ void GameInfoCache::PurgeType(IdentifiedFileType fileType) {
// Call on the main thread ONLY - that is from stuff called from NativeFrame. // Call on the main thread ONLY - that is from stuff called from NativeFrame.
// Can also be called from the audio thread for menu background music, but that cannot request images! // Can also be called from the audio thread for menu background music, but that cannot request images!
std::shared_ptr<GameInfo> GameInfoCache::GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags, GameInfoFlags *outHasFlags, GameInfoFlags refetchFlags) { std::shared_ptr<GameInfo> GameInfoCache::GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags, GameInfoFlags *outHasFlags, GameInfoFlags refetchFlags, TaskPriority priority) {
const std::string &pathStr = gamePath.ToString(); const std::string &pathStr = gamePath.ToString();
// _dbg_assert_(gamePath != GetSysDirectory(DIRECTORY_SAVEDATA)); // _dbg_assert_(gamePath != GetSysDirectory(DIRECTORY_SAVEDATA));
@@ -1139,6 +1144,11 @@ std::shared_ptr<GameInfo> GameInfoCache::GetInfo(Draw::DrawContext *draw, const
info->hasFlags &= ~refetchFlags; info->hasFlags &= ~refetchFlags;
} }
GameInfoFlags willHaveFlags = info->hasFlags | info->pendingFlags; // We don't want to re-fetch data that we have, so or in pendingFlags. GameInfoFlags willHaveFlags = info->hasFlags | info->pendingFlags; // We don't want to re-fetch data that we have, so or in pendingFlags.
if (priority == TaskPriority::HIGH) {
// A pending load may be sitting at the back of the queue (a search over a big list
// queues one per game), and the caller is about to block. Fetch it ourselves.
willHaveFlags = info->hasFlags;
}
wanted = (GameInfoFlags)((int)wantFlags & ~(int)willHaveFlags); // & is reserved for testing so we have to cast to int. ugh. wanted = (GameInfoFlags)((int)wantFlags & ~(int)willHaveFlags); // & is reserved for testing so we have to cast to int. ugh.
// FILE_TYPE is special: every work item switches on info->fileType, so it's not enough that // FILE_TYPE is special: every work item switches on info->fileType, so it's not enough that
// some *pending* item is going to compute it - that item may not have got there yet, and we'd // some *pending* item is going to compute it - that item may not have got there yet, and we'd
@@ -1154,7 +1164,7 @@ std::shared_ptr<GameInfo> GameInfoCache::GetInfo(Draw::DrawContext *draw, const
if (wanted != (GameInfoFlags)0) { if (wanted != (GameInfoFlags)0) {
// We're missing info that we want. Go get it! // We're missing info that we want. Go get it!
GameInfoWorkItem *item = new GameInfoWorkItem(gamePath, info, wanted); GameInfoWorkItem *item = new GameInfoWorkItem(gamePath, info, wanted, priority);
g_threadManager.EnqueueTask(item); g_threadManager.EnqueueTask(item);
} }
return info; return info;
@@ -1170,7 +1180,7 @@ std::shared_ptr<GameInfo> GameInfoCache::GetInfo(Draw::DrawContext *draw, const
mapLock_.unlock(); mapLock_.unlock();
// Just get all the stuff we wanted. // Just get all the stuff we wanted.
GameInfoWorkItem *item = new GameInfoWorkItem(gamePath, info, wantFlags); GameInfoWorkItem *item = new GameInfoWorkItem(gamePath, info, wantFlags, priority);
g_threadManager.EnqueueTask(item); g_threadManager.EnqueueTask(item);
return info; return info;
} }
+6 -1
View File
@@ -25,6 +25,7 @@
#include <condition_variable> #include <condition_variable>
#include "Common/Thread/Event.h" #include "Common/Thread/Event.h"
#include "Common/Thread/ThreadManager.h"
#include "Core/ELF/ParamSFO.h" #include "Core/ELF/ParamSFO.h"
#include "Core/Util/PSARUnpack.h" #include "Core/Util/PSARUnpack.h"
#include "Common/File/Path.h" #include "Common/File/Path.h"
@@ -227,7 +228,11 @@ public:
// because they're big. bgTextures and sound may be discarded over time as well. // because they're big. bgTextures and sound may be discarded over time as well.
// NOTE: This never returns null, so you don't need to check for that. Do check Ready() flags though. // NOTE: This never returns null, so you don't need to check for that. Do check Ready() flags though.
// It's OK to pass in nullptr for draw if you don't need the actual texture right now. // It's OK to pass in nullptr for draw if you don't need the actual texture right now.
std::shared_ptr<GameInfo> GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags, GameInfoFlags *outHasFlags = nullptr, GameInfoFlags refetchFlags = GameInfoFlags::EMPTY); // priority orders the background loads: NORMAL for what's on screen, LOW for speculative work like
// search. HIGH is for a one-off request you're about to block on: it doesn't wait behind a
// lower-priority load that's already queued for the same data, it queues its own - so don't use it
// every frame.
std::shared_ptr<GameInfo> GetInfo(Draw::DrawContext *draw, const Path &gamePath, GameInfoFlags wantFlags, GameInfoFlags *outHasFlags = nullptr, GameInfoFlags refetchFlags = GameInfoFlags::EMPTY, TaskPriority priority = TaskPriority::NORMAL);
void FlushBGs(); // Gets rid of all BG textures. Also gets rid of bg sounds. void FlushBGs(); // Gets rid of all BG textures. Also gets rid of bg sounds.
void CancelAll(); void CancelAll();
+3 -2
View File
@@ -72,9 +72,10 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons
// Check if we already know that this game isn't playable. // Check if we already know that this game isn't playable.
// If coming from the main screen, the info will already be computed here since the icon is displayed etc. // If coming from the main screen, the info will already be computed here since the icon is displayed etc.
// Otherwise (launching from a file association, a shortcut, drag-and-drop...) we have to block until // Otherwise (launching from a file association, a shortcut, drag-and-drop...) we have to block until
// it's available - we can't decide what to do below without it. // it's available - we can't decide what to do below without it. HIGH, so we don't wait behind
// whatever else is queued, like a search's loads for every game in a big list.
const GameInfoFlags neededFlags = GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO; const GameInfoFlags neededFlags = GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO;
std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(nullptr, path, neededFlags); std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(nullptr, path, neededFlags, nullptr, GameInfoFlags::EMPTY, TaskPriority::HIGH);
info->WaitUntilReady(neededFlags); info->WaitUntilReady(neededFlags);
switch (info->fileType) { switch (info->fileType) {