mirror of
https://github.com/stenzek/duckstation.git
synced 2025-07-24 19:10:20 +00:00
GPUThread: Store copy of game info
Don't save it in FullscreenUI.
This commit is contained in:
parent
5fd61b6e3a
commit
4440ae3b78
@ -432,7 +432,7 @@ static GPUTexture* GetTextureForGameListEntryType(GameList::EntryType type);
|
||||
static GPUTexture* GetGameListCover(const GameList::Entry* entry, bool fallback_to_achievements_icon,
|
||||
bool fallback_to_icon);
|
||||
static GPUTexture* GetGameListCoverTrophy(const GameList::Entry* entry, const ImVec2& image_size);
|
||||
static GPUTexture* GetCoverForCurrentGame();
|
||||
static GPUTexture* GetCoverForCurrentGame(const std::string& game_path);
|
||||
static void SwitchToAchievements();
|
||||
static void SwitchToLeaderboards();
|
||||
|
||||
@ -514,11 +514,7 @@ struct ALIGN_TO_CACHE_LINE UIState
|
||||
bool tried_to_initialize = false;
|
||||
bool pause_menu_was_open = false;
|
||||
bool was_paused_on_quick_menu_open = false;
|
||||
std::string current_game_title;
|
||||
std::string current_game_serial;
|
||||
std::string current_game_path;
|
||||
std::string achievements_user_badge_path;
|
||||
GameHash current_game_hash = 0;
|
||||
|
||||
// Resources
|
||||
std::shared_ptr<GPUTexture> app_icon_texture;
|
||||
@ -722,23 +718,11 @@ bool FullscreenUI::Initialize()
|
||||
|
||||
s_state.initialized = true;
|
||||
|
||||
// in case we open the pause menu while the game is running
|
||||
const bool open_main_window = (s_state.current_main_window == MainWindowType::None && !GPUThread::HasGPUBackend() &&
|
||||
!GPUThread::IsGPUBackendRequested());
|
||||
if (GPUThread::HasGPUBackend())
|
||||
{
|
||||
Host::RunOnCPUThread([]() {
|
||||
if (System::IsValid())
|
||||
{
|
||||
FullscreenUI::OnRunningGameChanged(System::GetDiscPath(), System::GetGameSerial(), System::GetGameTitle(),
|
||||
System::GetGameHash());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LoadBackground();
|
||||
|
||||
if (open_main_window)
|
||||
// in case we open the pause menu while the game is running
|
||||
if (s_state.current_main_window == MainWindowType::None && !GPUThread::HasGPUBackend() &&
|
||||
!GPUThread::IsGPUBackendRequested())
|
||||
{
|
||||
ReturnToMainWindow();
|
||||
ForceKeyNavEnabled();
|
||||
@ -1018,24 +1002,6 @@ void FullscreenUI::OnSystemDestroyed()
|
||||
});
|
||||
}
|
||||
|
||||
void FullscreenUI::OnRunningGameChanged(const std::string& path, const std::string& serial, const std::string& title,
|
||||
GameHash hash)
|
||||
{
|
||||
// NOTE: Called on CPU thread.
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
|
||||
GPUThread::RunOnThread([path = path, title = title, serial = serial, hash = hash]() mutable {
|
||||
if (!IsInitialized())
|
||||
return;
|
||||
|
||||
s_state.current_game_title = std::move(title);
|
||||
s_state.current_game_serial = std::move(serial);
|
||||
s_state.current_game_path = std::move(path);
|
||||
s_state.current_game_hash = hash;
|
||||
});
|
||||
}
|
||||
|
||||
void FullscreenUI::PauseForMenuOpen(bool set_pause_menu_open)
|
||||
{
|
||||
s_state.was_paused_on_quick_menu_open = GPUThread::IsSystemPaused();
|
||||
@ -1233,10 +1199,6 @@ void FullscreenUI::Shutdown(bool clear_state)
|
||||
s_state.fullscreen_mode_list_cache = {};
|
||||
s_state.graphics_adapter_list_cache = {};
|
||||
s_state.hotkey_list_cache = {};
|
||||
s_state.current_game_hash = 0;
|
||||
s_state.current_game_path = {};
|
||||
s_state.current_game_serial = {};
|
||||
s_state.current_game_title = {};
|
||||
}
|
||||
|
||||
DestroyResources();
|
||||
@ -1657,7 +1619,7 @@ void FullscreenUI::StartChangeDiscFromFile()
|
||||
};
|
||||
|
||||
OpenFileSelector(FSUI_ICONVSTR(ICON_FA_COMPACT_DISC, "Select Disc Image"), false, std::move(callback),
|
||||
GetDiscImageFilters(), std::string(Path::GetDirectory(s_state.current_game_path)));
|
||||
GetDiscImageFilters(), std::string(Path::GetDirectory(GPUThread::GetGamePath())));
|
||||
}
|
||||
|
||||
void FullscreenUI::BeginChangeDiscOnCPUThread(bool needs_pause)
|
||||
@ -3735,14 +3697,15 @@ void FullscreenUI::SwitchToGameSettingsForSerial(std::string_view serial, GameHa
|
||||
|
||||
bool FullscreenUI::SwitchToGameSettings()
|
||||
{
|
||||
if (s_state.current_game_serial.empty())
|
||||
const std::string& serial = GPUThread::GetGameSerial();
|
||||
if (serial.empty())
|
||||
return false;
|
||||
|
||||
auto lock = GameList::GetLock();
|
||||
const GameList::Entry* entry = GameList::GetEntryForPath(s_state.current_game_path);
|
||||
const GameList::Entry* entry = GameList::GetEntryForPath(GPUThread::GetGamePath());
|
||||
if (!entry)
|
||||
{
|
||||
SwitchToGameSettingsForSerial(s_state.current_game_serial, s_state.current_game_hash);
|
||||
SwitchToGameSettingsForSerial(serial, GPUThread::GetGameHash());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -6999,7 +6962,10 @@ void FullscreenUI::DrawPauseMenu()
|
||||
dl->AddRectFilled(ImVec2(0.0f, 0.0f), ImVec2(display_size.x, scaled_top_bar_height),
|
||||
ImGui::GetColorU32(ModAlpha(UIStyle.BackgroundColor, 0.95f)), 0.0f);
|
||||
|
||||
GPUTexture* const cover = GetCoverForCurrentGame();
|
||||
const std::string& game_title = GPUThread::GetGameTitle();
|
||||
const std::string& game_serial = GPUThread::GetGameSerial();
|
||||
const std::string& game_path = GPUThread::GetGamePath();
|
||||
GPUTexture* const cover = GetCoverForCurrentGame(game_path);
|
||||
const float image_padding = LayoutScale(5.0f); // compensate for font baseline
|
||||
const float image_size = scaled_top_bar_height - scaled_top_bar_padding - scaled_top_bar_padding - image_padding;
|
||||
const ImRect image_rect(
|
||||
@ -7008,14 +6974,14 @@ void FullscreenUI::DrawPauseMenu()
|
||||
ImVec2(static_cast<float>(cover->GetWidth()), static_cast<float>(cover->GetHeight()))));
|
||||
dl->AddImage(cover, image_rect.Min, image_rect.Max);
|
||||
|
||||
if (!s_state.current_game_serial.empty())
|
||||
buffer.format("{} - {}", s_state.current_game_serial, Path::GetFileName(s_state.current_game_path));
|
||||
if (!game_serial.empty())
|
||||
buffer.format("{} - {}", game_serial, Path::GetFileName(game_path));
|
||||
else
|
||||
buffer.assign(Path::GetFileName(s_state.current_game_path));
|
||||
buffer.assign(Path::GetFileName(game_path));
|
||||
|
||||
ImVec2 text_pos = ImVec2(scaled_top_bar_padding + image_size + scaled_top_bar_padding, scaled_top_bar_padding);
|
||||
RenderShadowedTextClipped(dl, UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, text_pos, display_size,
|
||||
title_text_color, s_state.current_game_title);
|
||||
title_text_color, game_title);
|
||||
text_pos.y += UIStyle.LargeFontSize + scaled_text_spacing;
|
||||
|
||||
if (Achievements::IsActive())
|
||||
@ -7042,9 +7008,9 @@ void FullscreenUI::DrawPauseMenu()
|
||||
title_text_color, buffer);
|
||||
text_pos.y += UIStyle.LargeFontSize + scaled_text_spacing;
|
||||
|
||||
if (!s_state.current_game_serial.empty())
|
||||
if (!game_serial.empty())
|
||||
{
|
||||
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(s_state.current_game_serial);
|
||||
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(game_serial);
|
||||
const std::time_t session_time = static_cast<std::time_t>(System::GetSessionPlayedTime());
|
||||
|
||||
buffer.format(FSUI_FSTR("Session: {}"), GameList::FormatTimespan(session_time, true));
|
||||
@ -7110,14 +7076,12 @@ void FullscreenUI::DrawPauseMenu()
|
||||
|
||||
if (MenuButtonWithoutSummary(FSUI_ICONVSTR(ICON_PF_DOWNLOAD, "Load State"), has_game))
|
||||
{
|
||||
BeginTransition(
|
||||
[]() { OpenSaveStateSelector(s_state.current_game_serial, s_state.current_game_path, true); });
|
||||
BeginTransition([]() { OpenSaveStateSelector(GPUThread::GetGameSerial(), GPUThread::GetGamePath(), true); });
|
||||
}
|
||||
|
||||
if (MenuButtonWithoutSummary(FSUI_ICONVSTR(ICON_PF_DISKETTE, "Save State"), has_game))
|
||||
{
|
||||
BeginTransition(
|
||||
[]() { OpenSaveStateSelector(s_state.current_game_serial, s_state.current_game_path, false); });
|
||||
BeginTransition([]() { OpenSaveStateSelector(GPUThread::GetGameSerial(), GPUThread::GetGamePath(), false); });
|
||||
}
|
||||
|
||||
if (MenuButtonWithoutSummary(FSUI_ICONVSTR(ICON_PF_GAMEPAD_ALT, "Toggle Analog")))
|
||||
@ -8925,11 +8889,11 @@ GPUTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType typ
|
||||
}
|
||||
}
|
||||
|
||||
GPUTexture* FullscreenUI::GetCoverForCurrentGame()
|
||||
GPUTexture* FullscreenUI::GetCoverForCurrentGame(const std::string& game_path)
|
||||
{
|
||||
auto lock = GameList::GetLock();
|
||||
|
||||
const GameList::Entry* entry = GameList::GetEntryForPath(s_state.current_game_path);
|
||||
const GameList::Entry* entry = GameList::GetEntryForPath(game_path);
|
||||
if (!entry)
|
||||
return s_state.fallback_disc_texture.get();
|
||||
|
||||
|
@ -30,7 +30,6 @@ void OnSystemStarting();
|
||||
void OnSystemPaused();
|
||||
void OnSystemResumed();
|
||||
void OnSystemDestroyed();
|
||||
void OnRunningGameChanged(const std::string& path, const std::string& serial, const std::string& title, GameHash hash);
|
||||
|
||||
void Shutdown(bool clear_state);
|
||||
void Render();
|
||||
|
@ -55,9 +55,8 @@ static constexpr u32 THREAD_SPIN_TIME_US = 50;
|
||||
static constexpr u32 THREAD_SPIN_TIME_US = 200;
|
||||
#endif
|
||||
|
||||
static bool Reconfigure(std::string serial, std::optional<GPURenderer> renderer, bool upload_vram,
|
||||
std::optional<bool> fullscreen, std::optional<bool> start_fullscreen_ui, bool recreate_device,
|
||||
Error* error);
|
||||
static bool Reconfigure(std::optional<GPURenderer> renderer, bool upload_vram, std::optional<bool> fullscreen,
|
||||
std::optional<bool> start_fullscreen_ui, bool recreate_device, Error* error);
|
||||
|
||||
// NOTE: Use with care! The handler needs to manually run the destructor.
|
||||
template<class T, typename... Args>
|
||||
@ -85,6 +84,9 @@ static void DestroyGPUPresenterOnThread();
|
||||
|
||||
static void SetThreadEnabled(bool enabled);
|
||||
static void UpdateSettingsOnThread(GPUSettings&& new_settings);
|
||||
static void UpdateGameInfoOnThread(GPUThreadUpdateGameInfoCommand* cmd);
|
||||
static void GameInfoChanged(bool serial_changed);
|
||||
static void ClearGameInfoOnThread();
|
||||
|
||||
static void UpdateRunIdle();
|
||||
|
||||
@ -115,7 +117,10 @@ struct ALIGN_TO_CACHE_LINE State
|
||||
GPUVSyncMode requested_vsync = GPUVSyncMode::Disabled;
|
||||
bool requested_allow_present_throttle = false;
|
||||
bool requested_fullscreen_ui = false;
|
||||
std::string game_title;
|
||||
std::string game_serial;
|
||||
std::string game_path;
|
||||
GameHash game_hash = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@ -463,6 +468,14 @@ void GPUThread::Internal::GPUThreadEntryPoint()
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUBackendCommandType::UpdateGameInfo:
|
||||
{
|
||||
GPUThreadUpdateGameInfoCommand* ccmd = static_cast<GPUThreadUpdateGameInfoCommand*>(cmd);
|
||||
UpdateGameInfoOnThread(ccmd);
|
||||
ccmd->~GPUThreadUpdateGameInfoCommand();
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUBackendCommandType::Shutdown:
|
||||
{
|
||||
// Should have consumed everything, and be shutdown.
|
||||
@ -498,15 +511,13 @@ void GPUThread::Internal::DoRunIdle()
|
||||
g_gpu_device->GetMainSwapChain()->ThrottlePresentation();
|
||||
}
|
||||
|
||||
bool GPUThread::Reconfigure(std::string serial, std::optional<GPURenderer> renderer, bool upload_vram,
|
||||
std::optional<bool> fullscreen, std::optional<bool> start_fullscreen_ui,
|
||||
bool recreate_device, Error* error)
|
||||
bool GPUThread::Reconfigure(std::optional<GPURenderer> renderer, bool upload_vram, std::optional<bool> fullscreen,
|
||||
std::optional<bool> start_fullscreen_ui, bool recreate_device, Error* error)
|
||||
{
|
||||
INFO_LOG("Reconfiguring GPU thread.");
|
||||
|
||||
bool result = false;
|
||||
GPUThreadReconfigureCommand* cmd = AllocateCommand<GPUThreadReconfigureCommand>(GPUBackendCommandType::Reconfigure);
|
||||
cmd->game_serial = std::move(serial);
|
||||
cmd->renderer = renderer;
|
||||
cmd->fullscreen = fullscreen;
|
||||
cmd->start_fullscreen_ui = start_fullscreen_ui;
|
||||
@ -535,7 +546,7 @@ bool GPUThread::StartFullscreenUI(bool fullscreen, Error* error)
|
||||
return true;
|
||||
}
|
||||
|
||||
return Reconfigure(std::string(), std::nullopt, false, fullscreen, true, false, error);
|
||||
return Reconfigure(std::nullopt, false, fullscreen, true, false, error);
|
||||
}
|
||||
|
||||
bool GPUThread::IsFullscreenUIRequested()
|
||||
@ -552,7 +563,7 @@ void GPUThread::StopFullscreenUI()
|
||||
return;
|
||||
}
|
||||
|
||||
Reconfigure(std::string(), std::nullopt, false, std::nullopt, false, false, nullptr);
|
||||
Reconfigure(std::nullopt, false, std::nullopt, false, false, nullptr);
|
||||
}
|
||||
|
||||
std::optional<GPURenderer> GPUThread::GetRequestedRenderer()
|
||||
@ -560,17 +571,17 @@ std::optional<GPURenderer> GPUThread::GetRequestedRenderer()
|
||||
return s_state.requested_renderer;
|
||||
}
|
||||
|
||||
bool GPUThread::CreateGPUBackend(std::string serial, GPURenderer renderer, bool upload_vram, bool fullscreen,
|
||||
bool force_recreate_device, Error* error)
|
||||
bool GPUThread::CreateGPUBackend(GPURenderer renderer, bool upload_vram, bool fullscreen, bool force_recreate_device,
|
||||
Error* error)
|
||||
{
|
||||
s_state.requested_renderer = renderer;
|
||||
return Reconfigure(std::move(serial), renderer, upload_vram, fullscreen ? std::optional<bool>(true) : std::nullopt,
|
||||
std::nullopt, force_recreate_device, error);
|
||||
return Reconfigure(renderer, upload_vram, fullscreen ? std::optional<bool>(true) : std::nullopt, std::nullopt,
|
||||
force_recreate_device, error);
|
||||
}
|
||||
|
||||
void GPUThread::DestroyGPUBackend()
|
||||
{
|
||||
Reconfigure(std::string(), std::nullopt, false, std::nullopt, std::nullopt, false, nullptr);
|
||||
Reconfigure(std::nullopt, false, std::nullopt, std::nullopt, false, nullptr);
|
||||
s_state.requested_renderer.reset();
|
||||
}
|
||||
|
||||
@ -779,15 +790,14 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
|
||||
// Are we shutting down everything?
|
||||
if (!cmd->renderer.has_value() && !s_state.requested_fullscreen_ui)
|
||||
{
|
||||
// Serial clear must be after backend destroy, otherwise textures won't dump.
|
||||
DestroyGPUBackendOnThread();
|
||||
DestroyGPUPresenterOnThread();
|
||||
DestroyDeviceOnThread(true);
|
||||
s_state.game_serial = {};
|
||||
ClearGameInfoOnThread();
|
||||
return;
|
||||
}
|
||||
|
||||
// Serial clear must be after backend destroy, otherwise textures won't dump.
|
||||
s_state.game_serial = std::move(cmd->game_serial);
|
||||
g_gpu_settings = std::move(cmd->settings);
|
||||
|
||||
// Readback old VRAM for hardware renderers.
|
||||
@ -844,6 +854,8 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
|
||||
INFO_LOG("GPU device recreated in {:.2f}ms", timer.GetTimeMilliseconds());
|
||||
}
|
||||
|
||||
// Full shutdown case handled above.
|
||||
Assert(cmd->renderer.has_value() || s_state.requested_fullscreen_ui);
|
||||
if (cmd->renderer.has_value())
|
||||
{
|
||||
Timer timer;
|
||||
@ -862,6 +874,7 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
|
||||
// No point keeping the presenter around.
|
||||
DestroyGPUBackendOnThread();
|
||||
DestroyGPUPresenterOnThread();
|
||||
ClearGameInfoOnThread();
|
||||
}
|
||||
}
|
||||
|
||||
@ -878,6 +891,7 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
|
||||
|
||||
// Don't need to present game frames anymore.
|
||||
DestroyGPUPresenterOnThread();
|
||||
ClearGameInfoOnThread();
|
||||
|
||||
// Don't need timing to run FSUI.
|
||||
g_gpu_device->SetGPUTimingEnabled(false);
|
||||
@ -889,12 +903,6 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
|
||||
DestroyDeviceOnThread(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Device is no longer needed.
|
||||
DestroyGPUBackendOnThread();
|
||||
DestroyDeviceOnThread(true);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUThread::DestroyGPUBackendOnThread()
|
||||
@ -965,7 +973,6 @@ void GPUThread::SetThreadEnabled(bool enabled)
|
||||
const bool fullscreen = Host::IsFullscreen();
|
||||
const bool requested_fullscreen_ui = s_state.requested_fullscreen_ui;
|
||||
const std::optional<GPURenderer> requested_renderer = s_state.requested_renderer;
|
||||
std::string serial = s_state.game_serial;
|
||||
|
||||
// Force VRAM download, we're recreating.
|
||||
if (requested_renderer.has_value())
|
||||
@ -979,7 +986,7 @@ void GPUThread::SetThreadEnabled(bool enabled)
|
||||
}
|
||||
|
||||
// Shutdown reconfigure.
|
||||
Reconfigure(std::string(), std::nullopt, false, false, false, false, nullptr);
|
||||
Reconfigure(std::nullopt, false, false, false, false, nullptr);
|
||||
|
||||
// Thread should be idle at this point. Reset the FIFO.
|
||||
ResetCommandFIFO();
|
||||
@ -988,8 +995,8 @@ void GPUThread::SetThreadEnabled(bool enabled)
|
||||
s_state.use_gpu_thread = enabled;
|
||||
|
||||
Error error;
|
||||
if (!Reconfigure(std::move(serial), requested_renderer, requested_renderer.has_value(), fullscreen,
|
||||
requested_fullscreen_ui, true, &error))
|
||||
if (!Reconfigure(requested_renderer, requested_renderer.has_value(), fullscreen, requested_fullscreen_ui, true,
|
||||
&error))
|
||||
{
|
||||
ERROR_LOG("Reconfigure failed: {}", error.GetDescription());
|
||||
ReportFatalErrorAndShutdown(fmt::format("Reconfigure failed: {}", error.GetDescription()));
|
||||
@ -1100,8 +1107,8 @@ void GPUThread::UpdateSettings(bool gpu_settings_changed, bool device_settings_c
|
||||
INFO_LOG("Reconfiguring after device settings changed.");
|
||||
|
||||
Error error;
|
||||
if (!Reconfigure(System::GetGameSerial(), s_state.requested_renderer, s_state.requested_renderer.has_value(),
|
||||
std::nullopt, std::nullopt, true, &error)) [[unlikely]]
|
||||
if (!Reconfigure(s_state.requested_renderer, s_state.requested_renderer.has_value(), std::nullopt, std::nullopt,
|
||||
true, &error)) [[unlikely]]
|
||||
{
|
||||
Host::ReportErrorAsync("Error", fmt::format("Failed to recreate GPU device: {}", error.GetDescription()));
|
||||
}
|
||||
@ -1134,6 +1141,71 @@ void GPUThread::UpdateSettings(bool gpu_settings_changed, bool device_settings_c
|
||||
}
|
||||
}
|
||||
|
||||
void GPUThread::UpdateGameInfo(const std::string& title, const std::string& serial, const std::string& path,
|
||||
GameHash hash, bool wake_thread /*= true*/)
|
||||
{
|
||||
if (!s_state.use_gpu_thread)
|
||||
{
|
||||
const bool serial_changed = (s_state.game_serial != serial);
|
||||
s_state.game_title = title;
|
||||
s_state.game_serial = serial;
|
||||
s_state.game_path = path;
|
||||
s_state.game_hash = hash;
|
||||
GameInfoChanged(serial_changed);
|
||||
return;
|
||||
}
|
||||
|
||||
GPUThreadUpdateGameInfoCommand* cmd =
|
||||
AllocateCommand<GPUThreadUpdateGameInfoCommand>(GPUBackendCommandType::UpdateGameInfo, title, serial, path, hash);
|
||||
|
||||
if (wake_thread)
|
||||
PushCommandAndWakeThread(cmd);
|
||||
else
|
||||
PushCommand(cmd);
|
||||
}
|
||||
|
||||
void GPUThread::ClearGameInfo()
|
||||
{
|
||||
if (!s_state.use_gpu_thread)
|
||||
{
|
||||
ClearGameInfoOnThread();
|
||||
return;
|
||||
}
|
||||
|
||||
PushCommandAndWakeThread(AllocateCommand<GPUThreadUpdateGameInfoCommand>(GPUBackendCommandType::UpdateGameInfo));
|
||||
}
|
||||
|
||||
void GPUThread::UpdateGameInfoOnThread(GPUThreadUpdateGameInfoCommand* cmd)
|
||||
{
|
||||
DEV_LOG("Updating game info on GPU thread: {}/{}", cmd->game_serial, cmd->game_title);
|
||||
const bool serial_changed = (s_state.game_serial != cmd->game_serial);
|
||||
s_state.game_title = std::move(cmd->game_title);
|
||||
s_state.game_serial = std::move(cmd->game_serial);
|
||||
s_state.game_path = std::move(cmd->game_path);
|
||||
s_state.game_hash = cmd->game_hash;
|
||||
GameInfoChanged(serial_changed);
|
||||
}
|
||||
|
||||
void GPUThread::GameInfoChanged(bool serial_changed)
|
||||
{
|
||||
if (!serial_changed)
|
||||
return;
|
||||
|
||||
if (HasGPUBackend())
|
||||
GPUTextureCache::GameSerialChanged();
|
||||
if (SaveStateSelectorUI::IsOpen())
|
||||
SaveStateSelectorUI::RefreshList();
|
||||
}
|
||||
|
||||
void GPUThread::ClearGameInfoOnThread()
|
||||
{
|
||||
DEV_LOG("Clearing game info on GPU thread.");
|
||||
s_state.game_hash = 0;
|
||||
s_state.game_path = {};
|
||||
s_state.game_serial = {};
|
||||
s_state.game_title = {};
|
||||
}
|
||||
|
||||
void GPUThread::ReportFatalErrorAndShutdown(std::string_view reason)
|
||||
{
|
||||
DebugAssert(IsOnThread());
|
||||
@ -1389,24 +1461,26 @@ void GPUThread::UpdateRunIdle()
|
||||
Host::OnGPUThreadRunIdleChanged(new_flag);
|
||||
}
|
||||
|
||||
const std::string& GPUThread::GetGameTitle()
|
||||
{
|
||||
DebugAssert(IsOnThread());
|
||||
return s_state.game_title;
|
||||
}
|
||||
|
||||
const std::string& GPUThread::GetGameSerial()
|
||||
{
|
||||
DebugAssert(IsOnThread());
|
||||
return s_state.game_serial;
|
||||
}
|
||||
|
||||
void GPUThread::SetGameSerial(std::string serial)
|
||||
const std::string& GPUThread::GetGamePath()
|
||||
{
|
||||
DebugAssert(!IsOnThread() || !s_state.use_gpu_thread);
|
||||
RunOnThread([serial = std::move(serial)]() mutable {
|
||||
const bool changed = (s_state.game_serial != serial);
|
||||
s_state.game_serial = std::move(serial);
|
||||
if (changed)
|
||||
{
|
||||
if (HasGPUBackend())
|
||||
GPUTextureCache::GameSerialChanged();
|
||||
if (SaveStateSelectorUI::IsOpen())
|
||||
SaveStateSelectorUI::RefreshList();
|
||||
}
|
||||
});
|
||||
DebugAssert(IsOnThread());
|
||||
return s_state.game_path;
|
||||
}
|
||||
|
||||
GameHash GPUThread::GetGameHash()
|
||||
{
|
||||
DebugAssert(IsOnThread());
|
||||
return s_state.game_hash;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
@ -46,12 +46,11 @@ void StopFullscreenUI();
|
||||
|
||||
/// Backend control.
|
||||
std::optional<GPURenderer> GetRequestedRenderer();
|
||||
bool CreateGPUBackend(std::string serial, GPURenderer renderer, bool upload_vram, bool fullscreen,
|
||||
bool force_recreate_device, Error* error);
|
||||
bool CreateGPUBackend(GPURenderer renderer, bool upload_vram, bool fullscreen, bool force_recreate_device,
|
||||
Error* error);
|
||||
void DestroyGPUBackend();
|
||||
bool HasGPUBackend();
|
||||
bool IsGPUBackendRequested();
|
||||
void SetGameSerial(std::string serial);
|
||||
|
||||
/// Re-presents the current frame. Call when things like window resizes happen to re-display
|
||||
/// the current frame with the correct proportions. Should only be called from the CPU thread.
|
||||
@ -67,6 +66,9 @@ void ResizeDisplayWindow(s32 width, s32 height, float scale);
|
||||
const WindowInfo& GetRenderWindowInfo();
|
||||
|
||||
void UpdateSettings(bool gpu_settings_changed, bool device_settings_changed, bool thread_changed);
|
||||
void UpdateGameInfo(const std::string& title, const std::string& serial, const std::string& path, GameHash hash,
|
||||
bool wake_thread = true);
|
||||
void ClearGameInfo();
|
||||
|
||||
/// Triggers an abnormal system shutdown and waits for it to destroy the backend.
|
||||
void ReportFatalErrorAndShutdown(std::string_view reason);
|
||||
@ -84,7 +86,10 @@ bool GetRunIdleReason(RunIdleReason reason);
|
||||
void SetRunIdleReason(RunIdleReason reason, bool enabled);
|
||||
bool IsRunningIdle();
|
||||
bool IsSystemPaused();
|
||||
const std::string& GetGameTitle();
|
||||
const std::string& GetGameSerial();
|
||||
const std::string& GetGamePath();
|
||||
GameHash GetGameHash();
|
||||
|
||||
GPUThreadCommand* AllocateCommand(GPUBackendCommandType command, u32 size);
|
||||
void PushCommand(GPUThreadCommand* cmd);
|
||||
|
@ -31,6 +31,7 @@ enum class GPUBackendCommandType : u8
|
||||
AsyncBackendCall,
|
||||
Reconfigure,
|
||||
UpdateSettings,
|
||||
UpdateGameInfo,
|
||||
Shutdown,
|
||||
ClearVRAM,
|
||||
ClearDisplay,
|
||||
@ -71,7 +72,6 @@ struct GPUThreadReconfigureCommand : public GPUThreadCommand
|
||||
{
|
||||
Error* error_ptr;
|
||||
bool* out_result;
|
||||
std::string game_serial;
|
||||
std::optional<GPURenderer> renderer;
|
||||
std::optional<bool> fullscreen;
|
||||
std::optional<bool> start_fullscreen_ui;
|
||||
@ -89,6 +89,21 @@ struct GPUThreadUpdateSettingsCommand : public GPUThreadCommand
|
||||
GPUSettings settings;
|
||||
};
|
||||
|
||||
struct GPUThreadUpdateGameInfoCommand : public GPUThreadCommand
|
||||
{
|
||||
GPUThreadUpdateGameInfoCommand() = default;
|
||||
GPUThreadUpdateGameInfoCommand(const std::string& game_title_, const std::string& game_serial_,
|
||||
const std::string& game_path_, const GameHash& game_hash_)
|
||||
: game_title(game_title_), game_serial(game_serial_), game_path(game_path_), game_hash(game_hash_)
|
||||
{
|
||||
}
|
||||
|
||||
std::string game_title;
|
||||
std::string game_serial;
|
||||
std::string game_path;
|
||||
GameHash game_hash;
|
||||
};
|
||||
|
||||
struct GPUThreadAsyncCallCommand : public GPUThreadCommand
|
||||
{
|
||||
GPUThreadAsyncCallCommand() = default;
|
||||
|
@ -1193,7 +1193,7 @@ void System::RecreateGPU(GPURenderer renderer)
|
||||
StopMediaCapture();
|
||||
|
||||
Error error;
|
||||
if (!GPUThread::CreateGPUBackend(s_state.running_game_serial, renderer, true, false, false, &error))
|
||||
if (!GPUThread::CreateGPUBackend(renderer, true, false, false, &error))
|
||||
{
|
||||
ERROR_LOG("Failed to switch to {} renderer: {}", Settings::GetRendererName(renderer), error.GetDescription());
|
||||
Panic("Failed to switch renderer.");
|
||||
@ -1910,24 +1910,23 @@ bool System::Initialize(std::unique_ptr<CDImage> disc, DiscRegion disc_region, b
|
||||
// TODO: Drop class
|
||||
g_gpu.Initialize();
|
||||
|
||||
// Game info must be set prior to backend creation because of texture replacements.
|
||||
// We don't do it in UpdateRunningGame() when booting because it can fail in a number of locations.
|
||||
GPUThread::UpdateGameInfo(s_state.running_game_title, s_state.running_game_serial, s_state.running_game_path,
|
||||
s_state.running_game_hash, false);
|
||||
|
||||
// This can fail due to the application being closed during startup.
|
||||
if (!GPUThread::CreateGPUBackend(s_state.running_game_serial,
|
||||
force_software_renderer ? GPURenderer::Software : g_settings.gpu_renderer, false,
|
||||
if (!GPUThread::CreateGPUBackend(force_software_renderer ? GPURenderer::Software : g_settings.gpu_renderer, false,
|
||||
fullscreen, false, error))
|
||||
{
|
||||
// Game info has to be manually cleared since the backend won't shutdown naturally.
|
||||
GPUThread::ClearGameInfo();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_settings.gpu_pgxp_enable)
|
||||
CPU::PGXP::Initialize();
|
||||
|
||||
// Was startup cancelled? (e.g. shading compilers took too long and the user closed the application)
|
||||
if (IsStartupCancelled())
|
||||
{
|
||||
Error::SetStringView(error, TRANSLATE_SV("System", "Startup was cancelled."));
|
||||
return false;
|
||||
}
|
||||
|
||||
DMA::Initialize();
|
||||
Pad::Initialize();
|
||||
Timers::Initialize();
|
||||
@ -4221,15 +4220,15 @@ void System::UpdateRunningGame(const std::string& path, CDImage* image, bool boo
|
||||
}
|
||||
|
||||
if (s_state.running_game_serial != prev_serial)
|
||||
{
|
||||
GPUThread::SetGameSerial(s_state.running_game_serial);
|
||||
UpdateSessionTime(prev_serial);
|
||||
}
|
||||
|
||||
UpdateRichPresence(booting);
|
||||
|
||||
FullscreenUI::OnRunningGameChanged(s_state.running_game_path, s_state.running_game_serial, s_state.running_game_title,
|
||||
s_state.running_game_hash);
|
||||
if (!booting)
|
||||
{
|
||||
GPUThread::UpdateGameInfo(s_state.running_game_title, s_state.running_game_serial, s_state.running_game_path,
|
||||
s_state.running_game_hash);
|
||||
}
|
||||
|
||||
Host::OnSystemGameChanged(s_state.running_game_path, s_state.running_game_serial, s_state.running_game_title,
|
||||
s_state.running_game_hash);
|
||||
|
Loading…
x
Reference in New Issue
Block a user