FullscreenUI: Display game cover when loading

This commit is contained in:
Stenzek 2025-07-19 18:15:48 +10:00
parent 75314f79de
commit 278614a415
No known key found for this signature in database
9 changed files with 54 additions and 17 deletions

View File

@ -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..."));
});

View File

@ -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<s32>(m_progress_range), static_cast<s32>(m_progress_value));
ImGuiFullscreen::RenderLoadingScreen(m_image, m_status_text, 0, static_cast<s32>(m_progress_range),
static_cast<s32>(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<s32>(m_progress_range), value = static_cast<s32>(m_progress_value)]() {
ImGuiFullscreen::OpenOrUpdateLoadingScreen(ImGuiManager::LOGO_IMAGE_NAME, status_text, 0, range, value);
});
m_image = {};
}
}

View File

@ -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.

View File

@ -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)

View File

@ -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<int>(m_total),
ImGuiFullscreen::RenderLoadingScreen(m_image, m_title, 0, static_cast<int>(m_total),
static_cast<int>(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;

View File

@ -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<int>(total_textures), static_cast<int>(num_textures_loaded)); \
last_update_time.Reset(); \
}

View File

@ -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();

View File

@ -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)
//////////////////////////////////////////////////////////////////////////

View File

@ -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;