libretro: Work around crash in RetroArch Vulkan driver

This commit is contained in:
Connor McLaughlin 2020-11-25 23:06:39 +10:00
parent 917fa5dd0e
commit b45bee5954
7 changed files with 34 additions and 25 deletions

View File

@ -112,7 +112,7 @@ void GPU::SoftReset()
UpdateCommandTickEvent(); UpdateCommandTickEvent();
} }
bool GPU::DoState(StateWrapper& sw) bool GPU::DoState(StateWrapper& sw, bool update_display)
{ {
if (sw.IsReading()) if (sw.IsReading())
{ {
@ -225,7 +225,9 @@ bool GPU::DoState(StateWrapper& sw)
m_GPUSTAT.bits = old_GPUSTAT; m_GPUSTAT.bits = old_GPUSTAT;
UpdateCRTCConfig(); UpdateCRTCConfig();
UpdateDisplay(); if (update_display)
UpdateDisplay();
UpdateCRTCTickEvent(); UpdateCRTCTickEvent();
UpdateCommandTickEvent(); UpdateCommandTickEvent();
} }

View File

@ -64,7 +64,7 @@ public:
virtual bool Initialize(HostDisplay* host_display); virtual bool Initialize(HostDisplay* host_display);
virtual void Reset(); virtual void Reset();
virtual bool DoState(StateWrapper& sw); virtual bool DoState(StateWrapper& sw, bool update_display);
// Graphics API state reset/restore - call when drawing the UI etc. // Graphics API state reset/restore - call when drawing the UI etc.
virtual void ResetGraphicsAPIState(); virtual void ResetGraphicsAPIState();

View File

@ -95,9 +95,9 @@ void GPU_HW::Reset()
SetFullVRAMDirtyRectangle(); SetFullVRAMDirtyRectangle();
} }
bool GPU_HW::DoState(StateWrapper& sw) bool GPU_HW::DoState(StateWrapper& sw, bool update_display)
{ {
if (!GPU::DoState(sw)) if (!GPU::DoState(sw, update_display))
return false; return false;
// invalidate the whole VRAM read texture when loading state // invalidate the whole VRAM read texture when loading state

View File

@ -33,7 +33,7 @@ public:
virtual bool Initialize(HostDisplay* host_display) override; virtual bool Initialize(HostDisplay* host_display) override;
virtual void Reset() override; virtual void Reset() override;
virtual bool DoState(StateWrapper& sw) override; virtual bool DoState(StateWrapper& sw, bool update_display) override;
void UpdateResolutionScale() override final; void UpdateResolutionScale() override final;
std::tuple<u32, u32> GetEffectiveDisplayResolution() override final; std::tuple<u32, u32> GetEffectiveDisplayResolution() override final;

View File

@ -57,8 +57,8 @@ static bool SetExpansionROM(const char* filename);
/// Opens CD image, preloading if needed. /// Opens CD image, preloading if needed.
static std::unique_ptr<CDImage> OpenCDImage(const char* path, bool force_preload); static std::unique_ptr<CDImage> OpenCDImage(const char* path, bool force_preload);
static bool DoLoadState(ByteStream* stream, bool force_software_renderer); static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display);
static bool DoState(StateWrapper& sw); static bool DoState(StateWrapper& sw, bool update_display);
static bool CreateGPU(GPURenderer renderer); static bool CreateGPU(GPURenderer renderer);
static bool Initialize(bool force_software_renderer); static bool Initialize(bool force_software_renderer);
@ -486,14 +486,14 @@ std::optional<DiscRegion> GetRegionForPath(const char* image_path)
return GetRegionForImage(cdi.get()); return GetRegionForImage(cdi.get());
} }
bool RecreateGPU(GPURenderer renderer) bool RecreateGPU(GPURenderer renderer, bool update_display /* = true*/)
{ {
g_gpu->RestoreGraphicsAPIState(); g_gpu->RestoreGraphicsAPIState();
// save current state // save current state
std::unique_ptr<ByteStream> state_stream = ByteStream_CreateGrowableMemoryStream(); std::unique_ptr<ByteStream> state_stream = ByteStream_CreateGrowableMemoryStream();
StateWrapper sw(state_stream.get(), StateWrapper::Mode::Write, SAVE_STATE_VERSION); StateWrapper sw(state_stream.get(), StateWrapper::Mode::Write, SAVE_STATE_VERSION);
const bool state_valid = g_gpu->DoState(sw) && TimingEvents::DoState(sw); const bool state_valid = g_gpu->DoState(sw, false) && TimingEvents::DoState(sw);
if (!state_valid) if (!state_valid)
Log_ErrorPrintf("Failed to save old GPU state when switching renderers"); Log_ErrorPrintf("Failed to save old GPU state when switching renderers");
@ -515,7 +515,7 @@ bool RecreateGPU(GPURenderer renderer)
state_stream->SeekAbsolute(0); state_stream->SeekAbsolute(0);
sw.SetMode(StateWrapper::Mode::Read); sw.SetMode(StateWrapper::Mode::Read);
g_gpu->RestoreGraphicsAPIState(); g_gpu->RestoreGraphicsAPIState();
g_gpu->DoState(sw); g_gpu->DoState(sw, update_display);
TimingEvents::DoState(sw); TimingEvents::DoState(sw);
g_gpu->ResetGraphicsAPIState(); g_gpu->ResetGraphicsAPIState();
} }
@ -551,7 +551,7 @@ bool Boot(const SystemBootParameters& params)
if (params.state_stream) if (params.state_stream)
{ {
if (!DoLoadState(params.state_stream.get(), params.force_software_renderer)) if (!DoLoadState(params.state_stream.get(), params.force_software_renderer, true))
{ {
Shutdown(); Shutdown();
return false; return false;
@ -828,7 +828,7 @@ bool CreateGPU(GPURenderer renderer)
return true; return true;
} }
bool DoState(StateWrapper& sw) bool DoState(StateWrapper& sw, bool update_display)
{ {
if (!sw.DoMarker("System")) if (!sw.DoMarker("System"))
return false; return false;
@ -853,7 +853,7 @@ bool DoState(StateWrapper& sw)
return false; return false;
g_gpu->RestoreGraphicsAPIState(); g_gpu->RestoreGraphicsAPIState();
const bool gpu_result = sw.DoMarker("GPU") && g_gpu->DoState(sw); const bool gpu_result = sw.DoMarker("GPU") && g_gpu->DoState(sw, update_display);
g_gpu->ResetGraphicsAPIState(); g_gpu->ResetGraphicsAPIState();
if (!gpu_result) if (!gpu_result)
return false; return false;
@ -934,15 +934,15 @@ void Reset()
g_gpu->ResetGraphicsAPIState(); g_gpu->ResetGraphicsAPIState();
} }
bool LoadState(ByteStream* state) bool LoadState(ByteStream* state, bool update_display)
{ {
if (IsShutdown()) if (IsShutdown())
return false; return false;
return DoLoadState(state, false); return DoLoadState(state, false, update_display);
} }
bool DoLoadState(ByteStream* state, bool force_software_renderer) bool DoLoadState(ByteStream* state, bool force_software_renderer, bool update_display)
{ {
SAVE_STATE_HEADER header; SAVE_STATE_HEADER header;
if (!state->Read2(&header, sizeof(header))) if (!state->Read2(&header, sizeof(header)))
@ -1047,7 +1047,7 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer)
return false; return false;
StateWrapper sw(state, StateWrapper::Mode::Read, header.version); StateWrapper sw(state, StateWrapper::Mode::Read, header.version);
if (!DoState(sw)) if (!DoState(sw, update_display))
return false; return false;
if (s_state == State::Starting) if (s_state == State::Starting)
@ -1114,7 +1114,7 @@ bool SaveState(ByteStream* state, u32 screenshot_size /* = 128 */)
g_gpu->RestoreGraphicsAPIState(); g_gpu->RestoreGraphicsAPIState();
StateWrapper sw(state, StateWrapper::Mode::Write, SAVE_STATE_VERSION); StateWrapper sw(state, StateWrapper::Mode::Write, SAVE_STATE_VERSION);
const bool result = DoState(sw); const bool result = DoState(sw, false);
g_gpu->ResetGraphicsAPIState(); g_gpu->ResetGraphicsAPIState();

View File

@ -138,11 +138,11 @@ bool Boot(const SystemBootParameters& params);
void Reset(); void Reset();
void Shutdown(); void Shutdown();
bool LoadState(ByteStream* state); bool LoadState(ByteStream* state, bool update_display = true);
bool SaveState(ByteStream* state, u32 screenshot_size = 128); bool SaveState(ByteStream* state, u32 screenshot_size = 128);
/// 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(GPURenderer renderer); bool RecreateGPU(GPURenderer renderer, bool update_display = true);
void RunFrame(); void RunFrame();

View File

@ -376,7 +376,7 @@ bool LibretroHostInterface::retro_serialize(void* data, size_t size)
bool LibretroHostInterface::retro_unserialize(const void* data, size_t size) bool LibretroHostInterface::retro_unserialize(const void* data, size_t size)
{ {
std::unique_ptr<ByteStream> stream = ByteStream_CreateReadOnlyMemoryStream(data, static_cast<u32>(size)); std::unique_ptr<ByteStream> stream = ByteStream_CreateReadOnlyMemoryStream(data, static_cast<u32>(size));
if (!System::LoadState(stream.get())) if (!System::LoadState(stream.get(), false))
{ {
Log_ErrorPrintf("Failed to load save state from memory stream"); Log_ErrorPrintf("Failed to load save state from memory stream");
return false; return false;
@ -1229,15 +1229,22 @@ void LibretroHostInterface::HardwareRendererContextDestroy()
void LibretroHostInterface::SwitchToSoftwareRenderer() void LibretroHostInterface::SwitchToSoftwareRenderer()
{ {
// keep the hw renderer around in case we need it later // keep the hw renderer around in case we need it later
// but keep it active until we've recreated the GPU so we can save the state
std::unique_ptr<HostDisplay> save_display;
if (m_using_hardware_renderer) if (m_using_hardware_renderer)
{ {
m_hw_render_display = std::move(m_display); save_display = std::move(m_display);
m_hw_render_display->DestroyResources();
m_using_hardware_renderer = false; m_using_hardware_renderer = false;
} }
m_display = std::make_unique<LibretroHostDisplay>(); m_display = std::make_unique<LibretroHostDisplay>();
System::RecreateGPU(GPURenderer::Software); System::RecreateGPU(GPURenderer::Software, false);
if (save_display)
{
save_display->DestroyResources();
m_hw_render_display = std::move(save_display);
}
} }
bool LibretroHostInterface::DiskControlSetEjectState(bool ejected) bool LibretroHostInterface::DiskControlSetEjectState(bool ejected)