From 65592effc58d8886a334144dd39220166432ff7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 24 Aug 2026 17:21:17 +0200 Subject: [PATCH] Block until game info is ready in LaunchFile When launching a file from outside the main screen (file association, shortcut, drag-and-drop), the info hasn't been computed yet, so the file type and ID checks that decide what to do with the file were reading empty data. Add GameInfo::WaitUntilReady() - a condition variable signalled from MarkReadyNoLock(), which every exit path of the work item goes through - and use it there. Also demote a noisy PRX decryption log line to DEBUG. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01EMLTdwyyzU6Mze3w8VC2JL --- Core/ELF/PrxDecrypter.cpp | 5 ++--- UI/GameInfoCache.h | 18 ++++++++++++++++++ UI/MainScreen.cpp | 7 +++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Core/ELF/PrxDecrypter.cpp b/Core/ELF/PrxDecrypter.cpp index dfb90034ac..2ae7b4633f 100644 --- a/Core/ELF/PrxDecrypter.cpp +++ b/Core/ELF/PrxDecrypter.cpp @@ -769,9 +769,8 @@ struct PRXType9 }; static_assert(sizeof(PRXType9) == 0x150, "inconsistent size of PRX Type 9"); -static int pspDecryptType0(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size) -{ - INFO_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); +static int pspDecryptType0(KirkState *kirk, const u8 *inbuf, u8 *outbuf, u32 size) { + DEBUG_LOG(Log::Loader, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]); const auto decryptSize = *(s32_le*)&inbuf[0xB0]; const auto pti = GetTagInfo((u32)*(u32_le *)&inbuf[0xD0]); diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 51d9f7bf49..dae51138c8 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "Common/Thread/Event.h" #include "Core/ELF/ParamSFO.h" @@ -123,9 +124,23 @@ public: return ((int)hasFlags & (int)flags) == (int)flags; } + // Blocks the calling thread until the specified flags have been loaded. Note that you must + // have requested them through GetInfo first, otherwise nobody will ever compute them and + // this will simply hang. + // Only use this where there's really no way to wait asynchronously by polling Ready() every + // frame - loading can take a while, especially from slow or remote storage. + void WaitUntilReady(GameInfoFlags flags) { + std::unique_lock guard(lock); + readyCond.wait(guard, [this, flags]() { + // Avoid the operator, we want to check all the bits. + return ((int)hasFlags & (int)flags) == (int)flags; + }); + } + void MarkReadyNoLock(GameInfoFlags flags) { hasFlags |= flags; pendingFlags &= ~flags; + readyCond.notify_all(); } GameInfoTex *GetPIC1() { @@ -140,6 +155,9 @@ public: // to it. std::mutex lock; + // Signalled whenever flags are marked as ready, see WaitUntilReady. Goes with the lock above. + std::condition_variable readyCond; + // Controls access to the fileLoader pointer. std::mutex loaderLock; diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 550d33c7df..232c10cef4 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -70,8 +70,11 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons } else { // 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. - // Otherwise, we probably technically should wait for it... - auto info = g_gameInfoCache->GetInfo(nullptr, path, GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO); + // 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. + const GameInfoFlags neededFlags = GameInfoFlags::FILE_TYPE | GameInfoFlags::PARAM_SFO; + std::shared_ptr info = g_gameInfoCache->GetInfo(nullptr, path, neededFlags); + info->WaitUntilReady(neededFlags); switch (info->fileType) { case IdentifiedFileType::PSP_UMD_VIDEO_ISO: