From 1f4dbd106037f040fcf05648392973f3e4a3c4ae Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 17 Nov 2019 19:37:10 +1000 Subject: [PATCH] Frontend: Implement D3D<->GL renderer switching --- src/duckstation/sdl_host_interface.cpp | 76 ++++++++++++++++++++++++-- src/duckstation/sdl_host_interface.h | 5 ++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/duckstation/sdl_host_interface.cpp b/src/duckstation/sdl_host_interface.cpp index ff5bf10bc..41fccb1f1 100644 --- a/src/duckstation/sdl_host_interface.cpp +++ b/src/duckstation/sdl_host_interface.cpp @@ -1,4 +1,5 @@ #include "sdl_host_interface.h" +#include "YBaseLib/AutoReleasePtr.h" #include "YBaseLib/ByteStream.h" #include "YBaseLib/Error.h" #include "YBaseLib/Log.h" @@ -13,8 +14,8 @@ #include "core/system.h" #include "core/timers.h" #ifdef Y_PLATFORM_WINDOWS -#include "d3d11_host_display.h" #include "YBaseLib/Windows/WindowsHeaders.h" +#include "d3d11_host_display.h" #include #endif #include "icon.h" @@ -34,6 +35,8 @@ SDLHostInterface::SDLHostInterface() : m_settings_filename("settings.ini") #ifdef Y_PLATFORM_WINDOWS timeBeginPeriod(1); #endif + + m_switch_gpu_renderer_event_id = SDL_RegisterEvents(1); } SDLHostInterface::~SDLHostInterface() @@ -78,6 +81,12 @@ bool SDLHostInterface::CreateSDLWindow() return true; } +void SDLHostInterface::DestroySDLWindow() +{ + SDL_DestroyWindow(m_window); + m_window = nullptr; +} + bool SDLHostInterface::CreateDisplay() { #ifdef WIN32 @@ -99,6 +108,12 @@ bool SDLHostInterface::CreateDisplay() return true; } +void SDLHostInterface::DestroyDisplay() +{ + m_app_icon_texture.reset(); + m_display.reset(); +} + void SDLHostInterface::CreateImGuiContext() { ImGui::CreateContext(); @@ -168,7 +183,52 @@ void SDLHostInterface::ResetPerformanceCounters() m_fps_timer.Reset(); } -void SDLHostInterface::SwitchGPURenderer() {} +void SDLHostInterface::QueueSwitchGPURenderer() +{ + SDL_Event ev = {}; + ev.type = SDL_USEREVENT; + ev.user.code = m_switch_gpu_renderer_event_id; + SDL_PushEvent(&ev); +} + +void SDLHostInterface::SwitchGPURenderer() +{ + // Due to the GPU class owning textures, we have to shut the system down. + AutoReleasePtr stream; + if (m_system) + { + stream = ByteStream_CreateGrowableMemoryStream(nullptr, 8 * 1024); + if (!m_system->SaveState(stream) || !stream->SeekAbsolute(0)) + ReportError("Failed to save state before GPU renderer switch"); + + DestroySystem(); + } + + ImGui::EndFrame(); + DestroyDisplay(); + DestroySDLWindow(); + + if (!CreateSDLWindow()) + Panic("Failed to recreate SDL window on GPU renderer switch"); + + if (!CreateDisplay()) + Panic("Failed to recreate display on GPU renderer switch"); + + ImGui::NewFrame(); + + if (stream) + { + CreateSystem(); + if (!BootSystem(nullptr, nullptr) || !m_system->LoadState(stream)) + { + ReportError("Failed to load state after GPU renderer switch, resetting"); + m_system->Reset(); + } + } + + ResetPerformanceCounters(); + ClearImGuiFocus(); +} void SDLHostInterface::UpdateFullscreen() { @@ -464,6 +524,13 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event) HandleSDLControllerButtonEventForController(event, m_controller.get()); } break; + + case SDL_USEREVENT: + { + if (static_cast(event->user.code) == m_switch_gpu_renderer_event_id) + SwitchGPURenderer(); + } + break; } } @@ -746,8 +813,7 @@ void SDLHostInterface::DrawQuickSettingsMenu() { m_settings.gpu_renderer = static_cast(i); settings_changed = true; - if (m_system) - SwitchGPURenderer(); + QueueSwitchGPURenderer(); } } @@ -1041,7 +1107,7 @@ void SDLHostInterface::DrawSettingsWindow() { m_settings.gpu_renderer = static_cast(gpu_renderer); settings_changed = true; - SwitchGPURenderer(); + QueueSwitchGPURenderer(); } } diff --git a/src/duckstation/sdl_host_interface.h b/src/duckstation/sdl_host_interface.h index d95c3c217..b2124ea36 100644 --- a/src/duckstation/sdl_host_interface.h +++ b/src/duckstation/sdl_host_interface.h @@ -59,7 +59,9 @@ private: #endif bool CreateSDLWindow(); + void DestroySDLWindow(); bool CreateDisplay(); + void DestroyDisplay(); void CreateImGuiContext(); bool CreateAudioStream(); @@ -69,6 +71,7 @@ private: void SaveSettings(); void ResetPerformanceCounters(); + void QueueSwitchGPURenderer(); void SwitchGPURenderer(); void UpdateFullscreen(); @@ -114,6 +117,8 @@ private: std::shared_ptr m_controller; + u32 m_switch_gpu_renderer_event_id = 0; + float m_vps = 0.0f; float m_fps = 0.0f; float m_speed = 0.0f;