FullscreenUI: Fix incorrect state with per-game renderer setting

This commit is contained in:
Stenzek
2026-01-07 13:17:03 +10:00
parent a2f3d038db
commit 74a8e6653d
7 changed files with 65 additions and 48 deletions

View File

@@ -170,7 +170,7 @@ ALIGN_TO_CACHE_LINE static Locals s_locals;
// Main
//////////////////////////////////////////////////////////////////////////
void FullscreenUI::Initialize()
void FullscreenUI::Initialize(bool preserve_state /*= false */)
{
// some achievement callbacks fire early while e.g. there is a load state popup blocking system init
if (s_locals.initialized || !ImGuiManager::IsInitialized())
@@ -179,7 +179,7 @@ void FullscreenUI::Initialize()
s_locals.initialized = true;
// in case we open the pause menu while the game is running
if (s_locals.current_main_window == MainWindowType::None && !GPUThread::HasGPUBackend() &&
if (!preserve_state && s_locals.current_main_window == MainWindowType::None && !GPUThread::HasGPUBackend() &&
!GPUThread::IsGPUBackendRequested())
{
ReturnToMainWindow();
@@ -456,9 +456,9 @@ void FullscreenUI::ReturnToMainWindow(float transition_time)
});
}
void FullscreenUI::Shutdown(bool clear_state)
void FullscreenUI::Shutdown(bool preserve_fsui_state)
{
if (clear_state)
if (!preserve_fsui_state)
{
SoundEffectManager::Shutdown();

View File

@@ -19,7 +19,7 @@ class SmallStringBase;
struct GPUSettings;
namespace FullscreenUI {
void Initialize();
void Initialize(bool preserve_state = false);
bool IsInitialized();
bool HasActiveWindow();
void CheckForConfigChanges(const GPUSettings& old_settings);
@@ -28,7 +28,7 @@ void OnSystemPaused();
void OnSystemResumed();
void OnSystemDestroyed();
void Shutdown(bool clear_state);
void Shutdown(bool preserve_state);
void Render();
void InvalidateCoverCache(std::string path = {});

View File

@@ -396,28 +396,38 @@ void FullscreenUI::SetFont(ImFont* ui_font)
UIStyle.Font = ui_font;
}
bool FullscreenUI::InitializeWidgets(Error* error)
bool FullscreenUI::InitializeWidgets(bool preserve_fsui_state, Error* error)
{
std::unique_lock lock(s_state.shared_state_mutex);
s_state.has_initialized = true;
s_state.focus_reset_queued = FocusResetType::ViewChanged;
s_state.close_button_state = CloseButtonState::None;
if (!(s_state.placeholder_texture = LoadTexture("images/placeholder.png")))
Error::SetStringView(error, "Failed to load placeholder.png");
if (!s_state.placeholder_texture || !CompileTransitionPipelines(error))
{
ShutdownWidgets(true);
std::unique_lock lock(s_state.shared_state_mutex);
if (!(s_state.placeholder_texture = LoadTexture("images/placeholder.png")))
{
Error::SetStringView(error, "Failed to load placeholder.png");
return false;
}
}
if (!CompileTransitionPipelines(error))
{
ShutdownWidgets(preserve_fsui_state);
return false;
}
if (!preserve_fsui_state)
{
s_state.focus_reset_queued = FocusResetType::ViewChanged;
s_state.close_button_state = CloseButtonState::None;
ResetMenuButtonFrame();
}
UpdateWidgetsSettings();
ResetMenuButtonFrame();
s_state.has_initialized = true;
return true;
}
void FullscreenUI::ShutdownWidgets(bool clear_state)
void FullscreenUI::ShutdownWidgets(bool preserve_fsui_state)
{
std::unique_lock lock(s_state.shared_state_mutex);
@@ -435,7 +445,7 @@ void FullscreenUI::ShutdownWidgets(bool clear_state)
s_state.has_initialized = false;
if (clear_state)
if (!preserve_fsui_state)
{
s_state.fullscreen_footer_icon_mapping = {};
s_state.notifications.clear();

View File

@@ -213,10 +213,10 @@ ImRect CenterImage(const ImRect& fit_rect, const GPUTexture* texture);
ImRect FitImage(const ImVec2& fit_size, const ImVec2& image_size);
/// Initializes, setting up any state.
bool InitializeWidgets(Error* error);
bool InitializeWidgets(bool preserve_fsui_state, Error* error);
/// Shuts down, clearing all state.
void ShutdownWidgets(bool clear_state);
void ShutdownWidgets(bool preserve_fsui_state);
/// Loads settings from the settings interface.
void UpdateWidgetsSettings();

View File

@@ -72,8 +72,8 @@ static void WakeGPUThread();
static void WakeGPUThreadIfSleeping();
static bool SleepGPUThread(bool allow_sleep);
static bool CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_fsui_state_on_failure, Error* error);
static void DestroyDeviceOnThread(bool clear_fsui_state);
static bool CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool preserve_fsui_state, Error* error);
static void DestroyDeviceOnThread(bool preserve_fsui_state);
static void ResizeDisplayWindowOnThread(u32 width, u32 height, float scale);
static void UpdateDisplayWindowOnThread(bool fullscreen, bool allow_exclusive_fullscreen);
static void DisplayWindowResizedOnThread();
@@ -626,7 +626,7 @@ bool GPUThread::IsFullscreen()
return s_state.requested_fullscreen;
}
bool GPUThread::CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_fsui_state_on_failure, Error* error)
bool GPUThread::CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool preserve_fsui_state, Error* error)
{
DebugAssert(!g_gpu_device);
@@ -704,11 +704,11 @@ bool GPUThread::CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_
return false;
}
if (!ImGuiManager::Initialize(&create_error))
if (!ImGuiManager::Initialize(preserve_fsui_state, &create_error))
{
ERROR_LOG("Failed to initialize ImGuiManager: {}", create_error.GetDescription());
Error::SetStringFmt(error, "Failed to initialize ImGuiManager: {}", create_error.GetDescription());
ImGuiManager::Shutdown(clear_fsui_state_on_failure);
ImGuiManager::Shutdown(preserve_fsui_state);
g_gpu_device->Destroy();
g_gpu_device.reset();
if (wi.has_value())
@@ -717,7 +717,7 @@ bool GPUThread::CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_
}
if (s_state.requested_fullscreen_ui)
FullscreenUI::Initialize();
FullscreenUI::Initialize(preserve_fsui_state);
InputManager::SetDisplayWindowSize(ImGuiManager::GetWindowWidth(), ImGuiManager::GetWindowHeight());
@@ -739,7 +739,7 @@ bool GPUThread::CreateDeviceOnThread(RenderAPI api, bool fullscreen, bool clear_
return true;
}
void GPUThread::DestroyDeviceOnThread(bool clear_fsui_state)
void GPUThread::DestroyDeviceOnThread(bool preserve_fsui_state)
{
if (!g_gpu_device)
return;
@@ -747,8 +747,8 @@ void GPUThread::DestroyDeviceOnThread(bool clear_fsui_state)
// Presenter should be gone by this point
Assert(!s_state.gpu_presenter);
FullscreenUI::Shutdown(clear_fsui_state);
ImGuiManager::Shutdown(clear_fsui_state);
FullscreenUI::Shutdown(preserve_fsui_state);
ImGuiManager::Shutdown(preserve_fsui_state);
INFO_LOG("Destroying {} GPU device...", GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()));
g_gpu_device->Destroy();
@@ -832,7 +832,7 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
// Serial clear must be after backend destroy, otherwise textures won't dump.
DestroyGPUBackendOnThread();
DestroyGPUPresenterOnThread();
DestroyDeviceOnThread(true);
DestroyDeviceOnThread(false);
ClearGameInfoOnThread();
return;
}
@@ -864,12 +864,14 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
Settings::GetRenderAPIForRenderer(s_state.requested_renderer.value_or(g_gpu_settings.gpu_renderer));
if (cmd->force_recreate_device || !GPUDevice::IsSameRenderAPI(current_api, expected_api))
{
const bool preserve_fsui_state = FullscreenUI::IsInitialized();
Timer timer;
DestroyGPUPresenterOnThread();
DestroyDeviceOnThread(false);
DestroyDeviceOnThread(preserve_fsui_state);
Error local_error;
if (!CreateDeviceOnThread(expected_api, cmd->fullscreen, false, &local_error))
if (!CreateDeviceOnThread(expected_api, cmd->fullscreen, preserve_fsui_state, &local_error))
{
Host::AddIconOSDMessage(
OSDMessageType::Error, "DeviceSwitchFailed", ICON_FA_PAINT_ROLLER,
@@ -878,7 +880,8 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
local_error.GetDescription()));
Host::ReleaseRenderWindow();
if (current_api == RenderAPI::None || !CreateDeviceOnThread(current_api, cmd->fullscreen, true, &local_error))
if (current_api == RenderAPI::None ||
!CreateDeviceOnThread(current_api, cmd->fullscreen, preserve_fsui_state, &local_error))
{
if (cmd->error_ptr)
*cmd->error_ptr = local_error;
@@ -919,18 +922,16 @@ void GPUThread::ReconfigureOnThread(GPUThreadReconfigureCommand* cmd)
}
else if (s_state.requested_fullscreen_ui)
{
if (!(*cmd->out_result = g_gpu_device || CreateDeviceOnThread(expected_api, cmd->fullscreen, true, cmd->error_ptr)))
// s_state.requested_fullscreen_ui starts FullscreenUI in CreateDeviceOnThread().
if (!(*cmd->out_result =
g_gpu_device || CreateDeviceOnThread(expected_api, cmd->fullscreen, false, cmd->error_ptr)))
{
return;
}
// Don't need to present game frames anymore.
DestroyGPUPresenterOnThread();
ClearGameInfoOnThread();
// Don't need timing to run FSUI.
g_gpu_device->SetGPUTimingEnabled(false);
// Ensure FSUI is initialized.
FullscreenUI::Initialize();
}
}
@@ -960,6 +961,9 @@ void GPUThread::DestroyGPUPresenterOnThread()
Assert(!s_state.gpu_backend);
Assert(GPUBackend::GetQueuedFrameCount() == 0);
// Don't need timing anymore.
g_gpu_device->SetGPUTimingEnabled(false);
s_state.gpu_presenter.reset();
}

View File

@@ -191,7 +191,7 @@ void ImGuiManager::SetTextFontOrder(const TextFontOrder& order)
ReloadFontDataIfActive();
}
bool ImGuiManager::Initialize(Error* error)
bool ImGuiManager::Initialize(bool preserve_fsui_state, Error* error)
{
if (!LoadFontData(error))
{
@@ -230,8 +230,11 @@ bool ImGuiManager::Initialize(Error* error)
FullscreenUI::UpdateTheme();
FullscreenUI::UpdateLayoutScale();
if (!CreateFontAtlas(error) || !CompilePipelines(error) || !FullscreenUI::InitializeWidgets(error))
if (!CreateFontAtlas(error) || !CompilePipelines(error) ||
!FullscreenUI::InitializeWidgets(preserve_fsui_state, error))
{
return false;
}
NewFrame();
@@ -239,11 +242,11 @@ bool ImGuiManager::Initialize(Error* error)
return true;
}
void ImGuiManager::Shutdown(bool clear_fsui_state)
void ImGuiManager::Shutdown(bool preserve_fsui_state)
{
DestroySoftwareCursorTextures();
FullscreenUI::ShutdownWidgets(clear_fsui_state);
FullscreenUI::ShutdownWidgets(preserve_fsui_state);
s_state.text_font = nullptr;
s_state.fixed_font = nullptr;

View File

@@ -91,10 +91,10 @@ TextFontOrder GetDefaultTextFontOrder();
void SetTextFontOrder(const TextFontOrder& order);
/// Initializes ImGui, creates fonts, etc.
bool Initialize(Error* error);
bool Initialize(bool preserve_fsui_state, Error* error);
/// Frees all ImGui resources.
void Shutdown(bool clear_fsui_state);
void Shutdown(bool preserve_fsui_state);
/// Returns main ImGui context.
ImGuiContext* GetMainContext();