mirror of https://github.com/PCSX2/pcsx2.git
GS: Fix use-after-free on lost device
This commit is contained in:
parent
95843dc84a
commit
4cc4a6561c
|
@ -210,14 +210,24 @@ static void CloseGSRenderer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSreopen(bool recreate_device, GSRendererType new_renderer, std::optional<const Pcsx2Config::GSOptions*> old_config)
|
bool GSreopen(bool recreate_device, bool recreate_renderer, GSRendererType new_renderer,
|
||||||
|
std::optional<const Pcsx2Config::GSOptions*> old_config)
|
||||||
{
|
{
|
||||||
Console.WriteLn("Reopening GS with %s device", recreate_device ? "new" : "existing");
|
Console.WriteLn("Reopening GS with %s device", recreate_device ? "new" : "existing");
|
||||||
|
|
||||||
g_gs_renderer->Flush(GSState::GSFlushReason::GSREOPEN);
|
g_gs_renderer->Flush(GSState::GSFlushReason::GSREOPEN);
|
||||||
|
|
||||||
if (GSConfig.UserHacks_ReadTCOnClose)
|
if (recreate_device && !recreate_renderer)
|
||||||
|
{
|
||||||
|
// Keeping the renderer around, this probably means we lost the device, so toss everything.
|
||||||
|
g_gs_renderer->PurgeTextureCache(true, true, true);
|
||||||
|
g_gs_device->ClearCurrent();
|
||||||
|
g_gs_device->PurgePool();
|
||||||
|
}
|
||||||
|
else if (GSConfig.UserHacks_ReadTCOnClose)
|
||||||
|
{
|
||||||
g_gs_renderer->ReadbackTextureCache();
|
g_gs_renderer->ReadbackTextureCache();
|
||||||
|
}
|
||||||
|
|
||||||
std::string capture_filename;
|
std::string capture_filename;
|
||||||
GSVector2i capture_size;
|
GSVector2i capture_size;
|
||||||
|
@ -232,21 +242,25 @@ bool GSreopen(bool recreate_device, GSRendererType new_renderer, std::optional<c
|
||||||
u8* basemem = g_gs_renderer->GetRegsMem();
|
u8* basemem = g_gs_renderer->GetRegsMem();
|
||||||
|
|
||||||
freezeData fd = {};
|
freezeData fd = {};
|
||||||
if (g_gs_renderer->Freeze(&fd, true) != 0)
|
std::unique_ptr<u8[]> fd_data;
|
||||||
|
if (recreate_renderer)
|
||||||
{
|
{
|
||||||
Console.Error("(GSreopen) Failed to get GS freeze size");
|
if (g_gs_renderer->Freeze(&fd, true) != 0)
|
||||||
return false;
|
{
|
||||||
}
|
Console.Error("(GSreopen) Failed to get GS freeze size");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<u8[]> fd_data = std::make_unique<u8[]>(fd.size);
|
fd_data = std::make_unique<u8[]>(fd.size);
|
||||||
fd.data = fd_data.get();
|
fd.data = fd_data.get();
|
||||||
if (g_gs_renderer->Freeze(&fd, false) != 0)
|
if (g_gs_renderer->Freeze(&fd, false) != 0)
|
||||||
{
|
{
|
||||||
Console.Error("(GSreopen) Failed to freeze GS");
|
Console.Error("(GSreopen) Failed to freeze GS");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseGSRenderer();
|
CloseGSRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
if (recreate_device)
|
if (recreate_device)
|
||||||
{
|
{
|
||||||
|
@ -274,16 +288,19 @@ bool GSreopen(bool recreate_device, GSRendererType new_renderer, std::optional<c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OpenGSRenderer(new_renderer, basemem))
|
if (recreate_renderer)
|
||||||
{
|
{
|
||||||
Console.Error("(GSreopen) Failed to create new renderer");
|
if (!OpenGSRenderer(new_renderer, basemem))
|
||||||
return false;
|
{
|
||||||
}
|
Console.Error("(GSreopen) Failed to create new renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_gs_renderer->Defrost(&fd) != 0)
|
if (g_gs_renderer->Defrost(&fd) != 0)
|
||||||
{
|
{
|
||||||
Console.Error("(GSreopen) Failed to defrost");
|
Console.Error("(GSreopen) Failed to defrost");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!capture_filename.empty())
|
if (!capture_filename.empty())
|
||||||
|
@ -693,7 +710,7 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||||
// Options which need a full teardown/recreate.
|
// Options which need a full teardown/recreate.
|
||||||
if (!GSConfig.RestartOptionsAreEqual(old_config))
|
if (!GSConfig.RestartOptionsAreEqual(old_config))
|
||||||
{
|
{
|
||||||
if (!GSreopen(true, GSConfig.Renderer, &old_config))
|
if (!GSreopen(true, true, GSConfig.Renderer, &old_config))
|
||||||
pxFailRel("Failed to do full GS reopen");
|
pxFailRel("Failed to do full GS reopen");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -702,7 +719,7 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||||
if (GSConfig.SWExtraThreads != old_config.SWExtraThreads ||
|
if (GSConfig.SWExtraThreads != old_config.SWExtraThreads ||
|
||||||
GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight)
|
GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight)
|
||||||
{
|
{
|
||||||
if (!GSreopen(false, GSConfig.Renderer, &old_config))
|
if (!GSreopen(false, true, GSConfig.Renderer, &old_config))
|
||||||
pxFailRel("Failed to do quick GS reopen");
|
pxFailRel("Failed to do quick GS reopen");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -738,7 +755,8 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||||
if (GSConfig.UserHacks_ReadTCOnClose)
|
if (GSConfig.UserHacks_ReadTCOnClose)
|
||||||
g_gs_renderer->ReadbackTextureCache();
|
g_gs_renderer->ReadbackTextureCache();
|
||||||
g_gs_renderer->PurgeTextureCache(true, true, true);
|
g_gs_renderer->PurgeTextureCache(true, true, true);
|
||||||
g_gs_renderer->PurgePool();
|
g_gs_device->ClearCurrent();
|
||||||
|
g_gs_device->PurgePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear out the sampler cache when AF options change, since the anisotropy gets baked into them
|
// clear out the sampler cache when AF options change, since the anisotropy gets baked into them
|
||||||
|
@ -776,7 +794,7 @@ void GSSetSoftwareRendering(bool software_renderer, GSInterlaceMode new_interlac
|
||||||
// Config might be SW, and we're switching to HW -> use Auto.
|
// Config might be SW, and we're switching to HW -> use Auto.
|
||||||
const GSRendererType renderer = (software_renderer ? GSRendererType::SW :
|
const GSRendererType renderer = (software_renderer ? GSRendererType::SW :
|
||||||
(GSConfig.Renderer == GSRendererType::SW ? GSRendererType::Auto : GSConfig.Renderer));
|
(GSConfig.Renderer == GSRendererType::SW ? GSRendererType::Auto : GSConfig.Renderer));
|
||||||
if (!GSreopen(false, renderer, std::nullopt))
|
if (!GSreopen(false, true, renderer, std::nullopt))
|
||||||
pxFailRel("Failed to reopen GS for renderer switch.");
|
pxFailRel("Failed to reopen GS for renderer switch.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1115,7 +1133,7 @@ BEGIN_HOTKEY_LIST(g_gs_hotkeys){"Screenshot", TRANSLATE_NOOP("Hotkeys", "Graphic
|
||||||
MTGS::RunOnGSThread([new_level]() {
|
MTGS::RunOnGSThread([new_level]() {
|
||||||
GSConfig.HWMipmap = new_level;
|
GSConfig.HWMipmap = new_level;
|
||||||
g_gs_renderer->PurgeTextureCache(true, false, true);
|
g_gs_renderer->PurgeTextureCache(true, false, true);
|
||||||
g_gs_renderer->PurgePool();
|
g_gs_device->PurgePool();
|
||||||
});
|
});
|
||||||
}},
|
}},
|
||||||
{"CycleInterlaceMode", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Cycle Deinterlace Mode"),
|
{"CycleInterlaceMode", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Cycle Deinterlace Mode"),
|
||||||
|
|
|
@ -57,7 +57,8 @@ s16 GSLookupBeforeDrawFunctionId(const std::string_view& name);
|
||||||
s16 GSLookupMoveHandlerFunctionId(const std::string_view& name);
|
s16 GSLookupMoveHandlerFunctionId(const std::string_view& name);
|
||||||
|
|
||||||
bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* basemem);
|
bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* basemem);
|
||||||
bool GSreopen(bool recreate_device, GSRendererType new_renderer, std::optional<const Pcsx2Config::GSOptions*> old_config);
|
bool GSreopen(bool recreate_device, bool recreate_renderer, GSRendererType new_renderer,
|
||||||
|
std::optional<const Pcsx2Config::GSOptions*> old_config);
|
||||||
void GSreset(bool hardware_reset);
|
void GSreset(bool hardware_reset);
|
||||||
void GSclose();
|
void GSclose();
|
||||||
void GSgifSoftReset(u32 mask);
|
void GSgifSoftReset(u32 mask);
|
||||||
|
|
|
@ -75,11 +75,6 @@ void GSRenderer::Destroy()
|
||||||
GSCapture::EndCapture();
|
GSCapture::EndCapture();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSRenderer::PurgePool()
|
|
||||||
{
|
|
||||||
g_gs_device->PurgePool();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GSRenderer::UpdateRenderFixes()
|
void GSRenderer::UpdateRenderFixes()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -518,7 +513,7 @@ bool GSRenderer::BeginPresentFrame(bool frame_skip)
|
||||||
|
|
||||||
// Device lost, something went really bad.
|
// Device lost, something went really bad.
|
||||||
// Let's just toss out everything, and try to hobble on.
|
// Let's just toss out everything, and try to hobble on.
|
||||||
if (!GSreopen(true, GSGetCurrentRenderer(), std::nullopt))
|
if (!GSreopen(true, false, GSGetCurrentRenderer(), std::nullopt))
|
||||||
{
|
{
|
||||||
pxFailRel("Failed to recreate GS device after loss.");
|
pxFailRel("Failed to recreate GS device after loss.");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -44,8 +44,6 @@ public:
|
||||||
|
|
||||||
virtual void UpdateRenderFixes();
|
virtual void UpdateRenderFixes();
|
||||||
|
|
||||||
void PurgePool();
|
|
||||||
|
|
||||||
virtual void VSync(u32 field, bool registers_written, bool idle_frame);
|
virtual void VSync(u32 field, bool registers_written, bool idle_frame);
|
||||||
virtual bool CanUpscale() { return false; }
|
virtual bool CanUpscale() { return false; }
|
||||||
virtual float GetUpscaleMultiplier() { return 1.0f; }
|
virtual float GetUpscaleMultiplier() { return 1.0f; }
|
||||||
|
|
Loading…
Reference in New Issue