From 436f39d3f69e7f1e4acfb0fad75dcab05d5cea05 Mon Sep 17 00:00:00 2001 From: The Dax Date: Sun, 14 Sep 2014 06:59:27 -0400 Subject: [PATCH] Win32: Add an UI option to change the GPU backend. It requires an application restart to work. --- Core/Config.cpp | 6 ++++++ Core/Config.h | 6 ++++++ UI/GameSettingsScreen.cpp | 35 +++++++++++++++++++++++++++++++++++ UI/GameSettingsScreen.h | 3 ++- Windows/main.cpp | 13 +++++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 23a3d43b8a..6343ac63b2 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -407,6 +407,8 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("FrameRate", &g_Config.iFpsLimit, 0), #ifdef _WIN32 ConfigSetting("FrameSkipUnthrottle", &g_Config.bFrameSkipUnthrottle, false), + ConfigSetting("TemporaryGPUBackend", &g_Config.iTempGPUBackend, -1, false), + ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), #else ConfigSetting("FrameSkipUnthrottle", &g_Config.bFrameSkipUnthrottle, true), #endif @@ -828,6 +830,10 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } CleanRecent(); + +#ifdef _WIN32 + iTempGPUBackend = iGPUBackend; +#endif } void Config::Save() { diff --git a/Core/Config.h b/Core/Config.h index d05bfbdfd1..2a59d15454 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -82,6 +82,12 @@ public: bool bTopMost; std::string sFont; bool bIgnoreWindowsKey; + + // Used for switching the GPU backend in GameSettingsScreen. + // Without this, PPSSPP instantly crashes if we edit iGPUBackend directly... + int iTempGPUBackend; + + bool bRestartRequired; #endif bool bPauseWhenMinimized; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index a1c806fb46..b02b2e9856 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -49,6 +49,10 @@ #include "GPU/GPUInterface.h" #include "GPU/GLES/Framebuffer.h" +#if defined(_WIN32) +#include "Windows/WndMainWindow.h" +#endif + #ifdef IOS extern bool iosCanUseJit; #endif @@ -112,6 +116,11 @@ void GameSettingsScreen::CreateViews() { tabHolder->AddTab(ms->T("Graphics"), graphicsSettingsScroll); graphicsSettings->Add(new ItemHeader(gs->T("Rendering Mode"))); +#if defined(_WIN32) + static const char *renderingBackend[] = { "OpenGL", "DirectX" }; + PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTempGPUBackend, gs->T("Backend"), renderingBackend, GPU_BACKEND_OPENGL, ARRAY_SIZE(renderingBackend), gs, screenManager())); + renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend); +#endif static const char *renderingMode[] = { "Non-Buffered Rendering", "Buffered Rendering", "Read Framebuffers To Memory (CPU)", "Read Framebuffers To Memory (GPU)"}; PopupMultiChoice *renderingModeChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iRenderingMode, gs->T("Mode"), renderingMode, 0, ARRAY_SIZE(renderingMode), gs, screenManager())); renderingModeChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingMode); @@ -603,6 +612,32 @@ void GlobalSettingsScreen::CreateViews() { enableReports_ = Reporting::IsEnabled(); }*/ +void GameSettingsScreen::CallbackRenderingBackend(bool yes) { +#if defined(_WIN32) + // If the user ends up deciding not to restart, set the temporary variable back to the current backend + // so it doesn't get switched by accident. + if (yes) { + g_Config.bRestartRequired = true; + PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0); + } else { + g_Config.iTempGPUBackend = g_Config.iGPUBackend; + } +#endif +} + +UI::EventReturn GameSettingsScreen::OnRenderingBackend(UI::EventParams &e) { +#if defined(_WIN32) + I18NCategory *d = GetI18NCategory("Dialog"); + + // It only makes sense to show the restart prompt if the backend was actually changed. + if (g_Config.iTempGPUBackend != g_Config.iGPUBackend) { + screenManager()->push(new PromptScreen(d->T("ChangingGPUBackends", "Changing GPU backends requires PPSSPP to restart. Restart now?"), d->T("Yes"), d->T("No"), + std::bind(&GameSettingsScreen::CallbackRenderingBackend, this, placeholder::_1))); + } +#endif + return UI::EVENT_DONE; +} + UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) { #if defined(_WIN32) || defined(USING_QT_UI) const size_t name_len = 256; diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 4b712614a1..33eeab2472 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -35,7 +35,7 @@ protected: virtual void CreateViews(); virtual void sendMessage(const char *message, const char *value); void CallbackRestoreDefaults(bool yes); - + void CallbackRenderingBackend(bool yes); bool UseVerticalLayout() const; private: @@ -75,6 +75,7 @@ private: UI::EventReturn OnShaderChange(UI::EventParams &e); UI::EventReturn OnRestoreDefaultSettings(UI::EventParams &e); UI::EventReturn OnRenderingMode(UI::EventParams &e); + UI::EventReturn OnRenderingBackend(UI::EventParams &e); UI::EventReturn OnJitAffectingSetting(UI::EventParams &e); UI::EventReturn OnSoftwareRendering(UI::EventParams &e); UI::EventReturn OnHardwareTransform(UI::EventParams &e); diff --git a/Windows/main.cpp b/Windows/main.cpp index 414c1cb0b8..e77b7d9c45 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -588,7 +588,20 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin DialogManager::DestroyAll(); timeEndPeriod(1); delete host; + + // Is there a safer place to do this? + // Doing this in Config::Save requires knowing if the UI state is UISTATE_EXIT, + // but that causes UnitTest to fail linking with 400 errors if System.h is included.. + if (g_Config.iTempGPUBackend != g_Config.iGPUBackend) + g_Config.iGPUBackend = g_Config.iTempGPUBackend; + g_Config.Save(); LogManager::Shutdown(); + + if (g_Config.bRestartRequired) { + wchar_t moduleFilename[MAX_PATH]; + GetModuleFileName(GetModuleHandle(NULL), moduleFilename, MAX_PATH); + ShellExecute(NULL, NULL, moduleFilename, NULL, NULL, SW_SHOW); + } return 0; }