From e3940abe01a2d3039a35fd7aa5e21cfa8cf0d430 Mon Sep 17 00:00:00 2001 From: Mabel Date: Mon, 27 Jul 2026 20:03:45 +0000 Subject: [PATCH] Threaded Renderer Crash, Threaded Renderer Index Desync, Logger Disposal (#174) These 3 are all fixes made by LotP, who said they just didn't feel like making the PR atm and that someone else could do it if they wanted to (https://discord.com/channels/1294443224030511104/1295891559056674816/1531034369232211968) Addresses these 3 specific issues: 1. Toggling the hidden console tries to assign a new console logger, which is also done on setting initial state, but at that point a logger already exists so it just returns, except previously it did not dispose of the new logger. 2. The threaded renderer would sometimes just crash when emulation is stopped, the fix being to make sure the backend render thread is joined before touching common objects 3. The disposing workflow of other threads than the main GPU adds commands to the command queue, causing a problem where the index can get desynced because of race conditions Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/174 --- src/Ryujinx.Common/Logging/Logger.cs | 1 + .../Multithreading/ThreadedRenderer.cs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Ryujinx.Common/Logging/Logger.cs b/src/Ryujinx.Common/Logging/Logger.cs index 788d2ab3d..6bfa9b1aa 100644 --- a/src/Ryujinx.Common/Logging/Logger.cs +++ b/src/Ryujinx.Common/Logging/Logger.cs @@ -162,6 +162,7 @@ namespace Ryujinx.Common.Logging { if (_logTargets.Any(t => t.Name == target.Name)) { + target.Dispose(); return; } diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs index 66ac31ab4..42a0bd9af 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs @@ -195,11 +195,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading { // The reference table is sized so that it will never overflow, so long as the references are taken after the command is allocated. - int index = _refProducerPtr; + // make sure increment is thread safe + int index = Interlocked.Increment(ref _refProducerPtr) - 1; + + index %= _refQueue.Length; _refQueue[index] = obj; - _refProducerPtr = (_refProducerPtr + 1) % _refQueue.Length; + _refProducerPtr %= _refQueue.Length; return index; } @@ -531,10 +534,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading _running = false; _galWorkAvailable.Set(); - if (_gpuThread != null && _gpuThread.IsAlive) + if (_gpuThread is { IsAlive: true }) { _gpuThread.Join(); } + + if (_backendThread is { IsAlive: true }) + { + _backendThread.Join(); + } // Dispose the renderer. _baseRenderer.Dispose();