mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
GV7-2: drain the back queue at mid-frame MTGS-thread device seams
Sync-point audit fixes for pipelined mode: GSUpdateConfig's non-reopen branches, SaveSnapshotToMemory, and capture begin/end all touch renderer or GSDevice state from the MTGS thread while the back thread may be mid-draw on the same device. Each now drains queued records first (the front only parses on the MTGS thread, so nothing new queues during the operation). DrainBackQueue becomes public for the GS.cpp seam. Audit conclusions (no code needed): WaitGS callers never touch back-owned state EE-side (state access travels through MTGS ring packets into already drained seams); SIGNAL/FINISH are GIFRegHandlerNull in GSState — CSR semantics are entirely EE-side; a back-thread assert failure aborts the process on Linux, so it cannot deadlock the front. Gates: gs_vertex_tests 21/21; gsrunner PNG hashes identical to GV-0 baselines, modes 0 and 3, vk and sw. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
e7736345bb
commit
5aeb3dd8bc
@@ -864,6 +864,12 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
if (!g_gs_renderer)
|
||||
return;
|
||||
|
||||
// GV7-2: everything below mutates renderer/device state the back thread may
|
||||
// be reading mid-draw (settings, ImGui font textures, TC purges). The front
|
||||
// only parses on this (MTGS) thread, so a single drain up front quiesces the
|
||||
// back thread for the whole apply.
|
||||
g_gs_renderer->DrainBackQueue();
|
||||
|
||||
// Handle OSD scale changes by pushing a window resize through.
|
||||
if (new_config.OsdScale != old_config.OsdScale)
|
||||
ImGuiManager::RequestScaleUpdate();
|
||||
|
||||
+5
-1
@@ -47,6 +47,11 @@ public:
|
||||
GSBackQueue::Channel* GetBackChannel() { return m_chan; }
|
||||
bool IsBackThreadRunning() const { return m_chan->consumer_running; }
|
||||
|
||||
// GV7-2: external sync points (settings apply, screenshot-to-memory) that
|
||||
// touch renderer/device state from the MTGS thread must drain queued records
|
||||
// first — the back thread may otherwise be mid-draw on the same GSDevice.
|
||||
void DrainBackQueue();
|
||||
|
||||
static constexpr int GetSaveStateSize(int version);
|
||||
|
||||
private:
|
||||
@@ -631,7 +636,6 @@ public:
|
||||
|
||||
void StartBackThread();
|
||||
void StopBackThread();
|
||||
void DrainBackQueue();
|
||||
void BackThreadLoop();
|
||||
void ExecRecordSlot(const GSBackQueue::RecordSlot& slot);
|
||||
virtual void ExecVsyncRecord(const GSBackQueue::VsyncRecord& rec);
|
||||
|
||||
@@ -1056,6 +1056,9 @@ void GSSetDisplayAlignment(GSDisplayAlignment alignment)
|
||||
|
||||
bool GSRenderer::BeginCapture(std::string filename, const GSVector2i& size)
|
||||
{
|
||||
// GV7-2: capture start/stop can run mid-frame on the MTGS thread; teardown
|
||||
// frees download textures on the device the back thread may be drawing on.
|
||||
DrainBackQueue();
|
||||
const GSVector2i capture_resolution = (size.x != 0 && size.y != 0) ?
|
||||
size :
|
||||
(GSConfig.VideoCaptureAutoResolution ?
|
||||
@@ -1069,6 +1072,7 @@ bool GSRenderer::BeginCapture(std::string filename, const GSVector2i& size)
|
||||
|
||||
void GSRenderer::EndCapture()
|
||||
{
|
||||
DrainBackQueue(); // see BeginCapture
|
||||
GSCapture::EndCapture();
|
||||
}
|
||||
|
||||
@@ -1085,6 +1089,11 @@ bool GSRenderer::IsIdleFrame() const
|
||||
bool GSRenderer::SaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders,
|
||||
u32* width, u32* height, std::vector<u32>* pixels)
|
||||
{
|
||||
// GV7-2: mid-frame screenshot issues device calls (CreateRenderTarget /
|
||||
// StretchRect) on the MTGS thread; the back thread may be mid-draw on the
|
||||
// same device. The vsync-path callers are already post-drain (no-op there).
|
||||
DrainBackQueue();
|
||||
|
||||
GSTexture* const current = g_gs_device->GetCurrent();
|
||||
if (!current)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user