HostInterface: Add function to switch between sw/hw rendering

This commit is contained in:
Connor McLaughlin 2020-01-24 14:51:53 +10:00
parent f2231d6669
commit 4a3478b360
11 changed files with 43 additions and 39 deletions

View file

@ -105,6 +105,8 @@ public:
GPU(); GPU();
virtual ~GPU(); virtual ~GPU();
virtual bool IsHardwareRenderer() const = 0;
virtual bool Initialize(HostDisplay* host_display, System* system, DMA* dma, virtual bool Initialize(HostDisplay* host_display, System* system, DMA* dma,
InterruptController* interrupt_controller, Timers* timers); InterruptController* interrupt_controller, Timers* timers);
virtual void Reset(); virtual void Reset();

View file

@ -15,6 +15,11 @@ GPU_HW::GPU_HW() : GPU()
GPU_HW::~GPU_HW() = default; GPU_HW::~GPU_HW() = default;
bool GPU_HW::IsHardwareRenderer() const
{
return true;
}
bool GPU_HW::Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller, bool GPU_HW::Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller,
Timers* timers) Timers* timers)
{ {

View file

@ -29,6 +29,8 @@ public:
GPU_HW(); GPU_HW();
virtual ~GPU_HW(); virtual ~GPU_HW();
virtual bool IsHardwareRenderer() const override;
virtual bool Initialize(HostDisplay* host_display, System* system, DMA* dma, virtual bool Initialize(HostDisplay* host_display, System* system, DMA* dma,
InterruptController* interrupt_controller, Timers* timers) override; InterruptController* interrupt_controller, Timers* timers) override;
virtual void Reset() override; virtual void Reset() override;

View file

@ -15,6 +15,11 @@ GPU_SW::~GPU_SW()
m_host_display->SetDisplayTexture(nullptr, 0, 0, 0, 0, 0, 0, 1.0f); m_host_display->SetDisplayTexture(nullptr, 0, 0, 0, 0, 0, 0, 1.0f);
} }
bool GPU_SW::IsHardwareRenderer() const
{
return false;
}
bool GPU_SW::Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller, bool GPU_SW::Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller,
Timers* timers) Timers* timers)
{ {

View file

@ -12,6 +12,8 @@ public:
GPU_SW(); GPU_SW();
~GPU_SW() override; ~GPU_SW() override;
bool IsHardwareRenderer() const override;
bool Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller, bool Initialize(HostDisplay* host_display, System* system, DMA* dma, InterruptController* interrupt_controller,
Timers* timers) override; Timers* timers) override;
void Reset() override; void Reset() override;

View file

@ -515,7 +515,6 @@ std::string HostInterface::GetGameListDatabaseFileName() const
void HostInterface::UpdateSettings(const std::function<void()>& apply_callback) void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
{ {
// TODO: Should we move this to the base class?
const GPURenderer old_gpu_renderer = m_settings.gpu_renderer; const GPURenderer old_gpu_renderer = m_settings.gpu_renderer;
const u32 old_gpu_resolution_scale = m_settings.gpu_resolution_scale; const u32 old_gpu_resolution_scale = m_settings.gpu_resolution_scale;
const bool old_gpu_true_color = m_settings.gpu_true_color; const bool old_gpu_true_color = m_settings.gpu_true_color;
@ -528,7 +527,6 @@ void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
apply_callback(); apply_callback();
// TODO: Fast path for hardware->software switches
if (m_settings.gpu_renderer != old_gpu_renderer) if (m_settings.gpu_renderer != old_gpu_renderer)
SwitchGPURenderer(); SwitchGPURenderer();
@ -549,6 +547,18 @@ void HostInterface::UpdateSettings(const std::function<void()>& apply_callback)
m_display->SetDisplayLinearFiltering(m_settings.display_linear_filtering); m_display->SetDisplayLinearFiltering(m_settings.display_linear_filtering);
} }
void HostInterface::ToggleSoftwareRendering()
{
if (!m_system || m_settings.gpu_renderer == GPURenderer::Software)
return;
const GPURenderer new_renderer =
m_system->GetGPU()->IsHardwareRenderer() ? GPURenderer::Software : m_settings.gpu_renderer;
AddFormattedOSDMessage(2.0f, "Switching to %s renderer...", Settings::GetRendererDisplayName(new_renderer));
m_system->RecreateGPU(new_renderer);
}
void HostInterface::RunFrame() void HostInterface::RunFrame()
{ {
m_frame_timer.Reset(); m_frame_timer.Reset();

View file

@ -104,8 +104,13 @@ protected:
/// Returns the path of the game database cache file. /// Returns the path of the game database cache file.
std::string GetGameListDatabaseFileName() const; std::string GetGameListDatabaseFileName() const;
/// Applies new settings, updating internal state as needed. apply_callback should call m_settings.Load() after
/// locking any required mutexes.
void UpdateSettings(const std::function<void()>& apply_callback); void UpdateSettings(const std::function<void()>& apply_callback);
/// Quick switch between software and hardware rendering.
void ToggleSoftwareRendering();
void RunFrame(); void RunFrame();
/// Throttles the system, i.e. sleeps until it's time to execute the next frame. /// Throttles the system, i.e. sleeps until it's time to execute the next frame.

View file

@ -36,8 +36,8 @@ System::System(HostInterface* host_interface) : m_host_interface(host_interface)
m_spu = std::make_unique<SPU>(); m_spu = std::make_unique<SPU>();
m_mdec = std::make_unique<MDEC>(); m_mdec = std::make_unique<MDEC>();
m_sio = std::make_unique<SIO>(); m_sio = std::make_unique<SIO>();
m_region = host_interface->GetSettings().region; m_region = host_interface->m_settings.region;
m_cpu_execution_mode = host_interface->GetSettings().cpu_execution_mode; m_cpu_execution_mode = host_interface->m_settings.cpu_execution_mode;
} }
System::~System() = default; System::~System() = default;
@ -45,13 +45,13 @@ System::~System() = default;
std::unique_ptr<System> System::Create(HostInterface* host_interface) std::unique_ptr<System> System::Create(HostInterface* host_interface)
{ {
std::unique_ptr<System> system(new System(host_interface)); std::unique_ptr<System> system(new System(host_interface));
if (!system->CreateGPU()) if (!system->CreateGPU(host_interface->m_settings.gpu_renderer))
return {}; return {};
return system; return system;
} }
bool System::RecreateGPU() bool System::RecreateGPU(GPURenderer renderer)
{ {
// save current state // save current state
std::unique_ptr<ByteStream> state_stream = ByteStream_CreateGrowableMemoryStream(); std::unique_ptr<ByteStream> state_stream = ByteStream_CreateGrowableMemoryStream();
@ -62,7 +62,7 @@ bool System::RecreateGPU()
// create new renderer // create new renderer
m_gpu.reset(); m_gpu.reset();
if (!CreateGPU()) if (!CreateGPU(renderer))
{ {
Panic("Failed to recreate GPU"); Panic("Failed to recreate GPU");
return false; return false;
@ -193,9 +193,9 @@ void System::InitializeComponents()
m_mdec->Initialize(this, m_dma.get()); m_mdec->Initialize(this, m_dma.get());
} }
bool System::CreateGPU() bool System::CreateGPU(GPURenderer renderer)
{ {
switch (m_host_interface->GetSettings().gpu_renderer) switch (renderer)
{ {
case GPURenderer::HardwareOpenGL: case GPURenderer::HardwareOpenGL:
m_gpu = m_host_interface->GetDisplay()->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES ? m_gpu = m_host_interface->GetDisplay()->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES ?
@ -220,7 +220,6 @@ bool System::CreateGPU()
{ {
Log_ErrorPrintf("Failed to initialize GPU, falling back to software"); Log_ErrorPrintf("Failed to initialize GPU, falling back to software");
m_gpu.reset(); m_gpu.reset();
m_host_interface->GetSettings().gpu_renderer = GPURenderer::Software;
m_gpu = GPU::CreateSoftwareRenderer(); m_gpu = GPU::CreateSoftwareRenderer();
if (!m_gpu->Initialize(m_host_interface->GetDisplay(), this, m_dma.get(), m_interrupt_controller.get(), if (!m_gpu->Initialize(m_host_interface->GetDisplay(), this, m_dma.get(), m_interrupt_controller.get(),
m_timers.get())) m_timers.get()))

View file

@ -68,7 +68,7 @@ public:
bool SaveState(ByteStream* state); bool SaveState(ByteStream* state);
/// Recreates the GPU component, saving/loading the state so it is preserved. Call when the GPU renderer changes. /// Recreates the GPU component, saving/loading the state so it is preserved. Call when the GPU renderer changes.
bool RecreateGPU(); bool RecreateGPU(GPURenderer renderer);
/// Updates GPU settings, without recreating the renderer. /// Updates GPU settings, without recreating the renderer.
void UpdateGPUSettings(); void UpdateGPUSettings();
@ -98,7 +98,7 @@ private:
System(HostInterface* host_interface); System(HostInterface* host_interface);
bool DoState(StateWrapper& sw); bool DoState(StateWrapper& sw);
bool CreateGPU(); bool CreateGPU(GPURenderer renderer);
void InitializeComponents(); void InitializeComponents();

View file

@ -419,7 +419,7 @@ void SDLHostInterface::HandleSDLKeyEvent(const SDL_Event* event)
case SDL_SCANCODE_END: { case SDL_SCANCODE_END: {
if (pressed) if (pressed)
DoToggleSoftwareRendering(); ToggleSoftwareRendering();
} }
break; break;
@ -1549,31 +1549,6 @@ void SDLHostInterface::DoFrameStep()
m_paused = false; m_paused = false;
} }
void SDLHostInterface::DoToggleSoftwareRendering()
{
if (!m_system)
return;
if (m_settings.gpu_renderer != GPURenderer::Software)
{
m_settings.gpu_renderer = GPURenderer::Software;
AddOSDMessage("Switched to software GPU renderer.");
}
else
{
#ifdef WIN32
m_settings.gpu_renderer = m_display->GetRenderAPI() == HostDisplay::RenderAPI::D3D11 ? GPURenderer::HardwareD3D11 :
GPURenderer::HardwareOpenGL;
#else
m_settings.gpu_renderer = GPURenderer::HardwareOpenGL;
#endif
AddOSDMessage("Switched to hardware GPU renderer.");
}
m_system->RecreateGPU();
}
void SDLHostInterface::DoToggleFullscreen() void SDLHostInterface::DoToggleFullscreen()
{ {
m_settings.display_fullscreen = !m_settings.display_fullscreen; m_settings.display_fullscreen = !m_settings.display_fullscreen;

View file

@ -99,7 +99,6 @@ private:
void DoSaveState(u32 index); void DoSaveState(u32 index);
void DoTogglePause(); void DoTogglePause();
void DoFrameStep(); void DoFrameStep();
void DoToggleSoftwareRendering();
void DoToggleFullscreen(); void DoToggleFullscreen();
void DoModifyInternalResolution(s32 increment); void DoModifyInternalResolution(s32 increment);