From 278614a4158e774873d7293f50ae3c9d496eb1a5 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 19 Jul 2025 18:15:48 +1000 Subject: [PATCH] FullscreenUI: Display game cover when loading --- src/core/achievements.cpp | 2 +- src/core/fullscreen_ui.cpp | 9 ++++++--- src/core/fullscreen_ui.h | 1 + src/core/game_list.cpp | 24 +++++++++++++++++------- src/core/gpu_hw.cpp | 10 ++++++---- src/core/gpu_hw_texture_cache.cpp | 3 ++- src/core/system.cpp | 16 ++++++++++++++++ src/core/system.h | 4 ++++ src/util/imgui_fullscreen.cpp | 2 +- 9 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/core/achievements.cpp b/src/core/achievements.cpp index 5623f7710..4f6a6d295 100644 --- a/src/core/achievements.cpp +++ b/src/core/achievements.cpp @@ -1856,7 +1856,7 @@ bool Achievements::DoState(StateWrapper& sw) { // Messy because GPU-thread, but at least it looks pretty. GPUThread::RunOnThread([]() { - FullscreenUI::OpenLoadingScreen(ImGuiManager::LOGO_IMAGE_NAME, + FullscreenUI::OpenLoadingScreen(System::GetImageForLoadingScreen(GPUThread::GetGameSerial()), TRANSLATE_SV("Achievements", "Downloading achievements data...")); }); diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 5d633ba80..98c72742a 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -9165,6 +9165,8 @@ void FullscreenUI::BackgroundProgressCallback::SetCancelled() LoadingScreenProgressCallback::LoadingScreenProgressCallback() : ProgressCallback(), m_open_time(Timer::GetCurrentValue()), m_on_gpu_thread(GPUThread::IsOnThread()) { + m_image = System::GetImageForLoadingScreen( + std::string_view(m_on_gpu_thread ? GPUThread::GetGameSerial() : System::GetGameSerial())); } LoadingScreenProgressCallback::~LoadingScreenProgressCallback() @@ -9269,15 +9271,16 @@ void LoadingScreenProgressCallback::Redraw(bool force) m_last_progress_percent = percent; if (m_on_gpu_thread) { - ImGuiFullscreen::RenderLoadingScreen(ImGuiManager::LOGO_IMAGE_NAME, m_status_text, 0, - static_cast(m_progress_range), static_cast(m_progress_value)); + ImGuiFullscreen::RenderLoadingScreen(m_image, m_status_text, 0, static_cast(m_progress_range), + static_cast(m_progress_value)); } else { - GPUThread::RunOnThread([status_text = SmallString(std::string_view(m_status_text)), + GPUThread::RunOnThread([image = std::move(m_image), status_text = SmallString(std::string_view(m_status_text)), range = static_cast(m_progress_range), value = static_cast(m_progress_value)]() { ImGuiFullscreen::OpenOrUpdateLoadingScreen(ImGuiManager::LOGO_IMAGE_NAME, status_text, 0, range, value); }); + m_image = {}; } } diff --git a/src/core/fullscreen_ui.h b/src/core/fullscreen_ui.h index a3654b2cd..6b902dbfc 100644 --- a/src/core/fullscreen_ui.h +++ b/src/core/fullscreen_ui.h @@ -138,6 +138,7 @@ private: float m_open_delay = 1.0f; s32 m_last_progress_percent = -1; bool m_on_gpu_thread = false; + std::string m_image; }; // Host UI triggers from Big Picture mode. diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index 04e9bd239..ebf65835d 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -1182,36 +1182,46 @@ static std::string GetFullCoverPath(std::string_view filename, std::string_view std::string GameList::GetCoverImagePath(const std::string& path, const std::string& serial, const std::string& title) { static constexpr const std::array extensions = {"jpg", "jpeg", "png", "webp"}; + std::string ret; for (const char* extension : extensions) { // Prioritize lookup by serial (Most specific) if (!serial.empty()) { - const std::string cover_path(GetFullCoverPath(serial, extension)); + std::string cover_path(GetFullCoverPath(serial, extension)); if (FileSystem::FileExists(cover_path.c_str())) - return cover_path; + { + ret = std::move(cover_path); + return ret; + } } // Try file title (for modded games or specific like above) const std::string_view file_title(Path::GetFileTitle(path)); if (!file_title.empty() && title != file_title) { - const std::string cover_path(GetFullCoverPath(file_title, extension)); + std::string cover_path(GetFullCoverPath(file_title, extension)); if (FileSystem::FileExists(cover_path.c_str())) - return cover_path; + { + ret = std::move(cover_path); + return ret; + } } // Last resort, check the game title if (!title.empty()) { - const std::string cover_path(GetFullCoverPath(title, extension)); + std::string cover_path(GetFullCoverPath(title, extension)); if (FileSystem::FileExists(cover_path.c_str())) - return cover_path; + { + ret = std::move(cover_path); + return ret; + } } } - return {}; + return ret; } std::string GameList::GetNewCoverImagePathForEntry(const Entry* entry, const char* new_filename, bool use_serial) diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 1eb93fa93..a274ee385 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -8,6 +8,7 @@ #include "gpu_hw_shadergen.h" #include "gpu_presenter.h" #include "gpu_sw_rasterizer.h" +#include "gpu_thread.h" #include "gte_types.h" #include "host.h" #include "imgui_overlays.h" @@ -184,9 +185,9 @@ class ShaderCompileProgressTracker { public: ShaderCompileProgressTracker(std::string title, u32 total) - : m_title(std::move(title)), m_min_time(Timer::ConvertSecondsToValue(1.0)), - m_update_interval(Timer::ConvertSecondsToValue(0.1)), m_start_time(Timer::GetCurrentValue()), - m_last_update_time(0), m_progress(0), m_total(total) + : m_title(std::move(title)), m_image(System::GetImageForLoadingScreen(GPUThread::GetGameSerial())), + m_min_time(Timer::ConvertSecondsToValue(1.0)), m_update_interval(Timer::ConvertSecondsToValue(0.1)), + m_start_time(Timer::GetCurrentValue()), m_last_update_time(0), m_progress(0), m_total(total) { } ~ShaderCompileProgressTracker() = default; @@ -209,7 +210,7 @@ public: const u64 tv = Timer::GetCurrentValue(); if ((tv - m_start_time) >= m_min_time && (tv - m_last_update_time) >= m_update_interval) { - ImGuiFullscreen::RenderLoadingScreen(ImGuiManager::LOGO_IMAGE_NAME, m_title, 0, static_cast(m_total), + ImGuiFullscreen::RenderLoadingScreen(m_image, m_title, 0, static_cast(m_total), static_cast(m_progress)); m_last_update_time = tv; } @@ -219,6 +220,7 @@ public: private: std::string m_title; + std::string m_image; Timer::Value m_min_time; Timer::Value m_update_interval; Timer::Value m_start_time; diff --git a/src/core/gpu_hw_texture_cache.cpp b/src/core/gpu_hw_texture_cache.cpp index 9aff26937..4c5b8b6e6 100644 --- a/src/core/gpu_hw_texture_cache.cpp +++ b/src/core/gpu_hw_texture_cache.cpp @@ -3455,11 +3455,12 @@ void GPUTextureCache::PreloadReplacementTextures() u32 num_textures_loaded = 0; const size_t total_textures = s_state.vram_replacements.size() + s_state.vram_write_texture_replacements.size() + s_state.texture_page_texture_replacements.size(); + std::string image_path = System::GetImageForLoadingScreen(GPUThread::GetGameSerial()); #define UPDATE_PROGRESS() \ if (last_update_time.GetTimeSeconds() >= UPDATE_INTERVAL) \ { \ - ImGuiFullscreen::RenderLoadingScreen(ImGuiManager::LOGO_IMAGE_NAME, "Preloading replacement textures...", 0, \ + ImGuiFullscreen::RenderLoadingScreen(image_path, "Preloading replacement textures...", 0, \ static_cast(total_textures), static_cast(num_textures_loaded)); \ last_update_time.Reset(); \ } diff --git a/src/core/system.cpp b/src/core/system.cpp index 53bc349dc..bf7b73e4f 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -6007,6 +6007,22 @@ bool System::ChangeGPUDump(std::string new_path) return true; } +std::string System::GetImageForLoadingScreen(std::string_view serial) +{ + std::string ret; + + const auto lock = GameList::GetLock(); + const GameList::Entry* entry = GameList::GetEntryBySerial(serial); + + if (entry) + ret = GameList::GetCoverImagePathForEntry(entry); + + if (ret.empty()) + ret = ImGuiManager::LOGO_IMAGE_NAME; + + return ret; +} + void System::UpdateSessionTime(const std::string& prev_serial) { const Timer::Value ctime = Timer::GetCurrentValue(); diff --git a/src/core/system.h b/src/core/system.h index 51bd2f13e..2db013dfe 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -423,6 +423,10 @@ void ToggleSoftwareRendering(); /// If the scale is set to 0, the internal resolution will be used, otherwise it is treated as a multiplier to 1x. void RequestDisplaySize(float scale = 0.0f); +/// Returns the path to a possible cover image for the current serial. +/// Only intended to be used for loading screens, so it may not be correct with custom titles and such. +std::string GetImageForLoadingScreen(std::string_view serial); + ////////////////////////////////////////////////////////////////////////// // Memory Save States (Rewind and Runahead) ////////////////////////////////////////////////////////////////////////// diff --git a/src/util/imgui_fullscreen.cpp b/src/util/imgui_fullscreen.cpp index fecde981d..7aabf0a4b 100644 --- a/src/util/imgui_fullscreen.cpp +++ b/src/util/imgui_fullscreen.cpp @@ -3915,7 +3915,7 @@ void ImGuiFullscreen::OpenOrUpdateLoadingScreen(std::string_view image, std::str s32 progress_min /*= -1*/, s32 progress_max /*= -1*/, s32 progress_value /*= -1*/) { - if (s_state.loading_screen_image != image) + if (!image.empty() && s_state.loading_screen_image != image) s_state.loading_screen_image = image; if (s_state.loading_screen_message != message) s_state.loading_screen_message = message;