diff options
Diffstat (limited to 'Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs')
-rw-r--r-- | Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs index 62a7dae7..58058be2 100644 --- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs +++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs @@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading private int _elementSize; private IRenderer _baseRenderer; private Thread _gpuThread; + private Thread _backendThread; private bool _disposed; private bool _running; @@ -38,6 +39,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading private CircularSpanPool _spanPool; private ManualResetEventSlim _invokeRun; + private AutoResetEvent _interruptRun; private bool _lastSampleCounterClear = true; @@ -54,6 +56,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading private int _refProducerPtr; private int _refConsumerPtr; + private Action _interruptAction; + public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured; internal BufferMap Buffers { get; } @@ -73,6 +77,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading _baseRenderer = renderer; renderer.ScreenCaptured += (sender, info) => ScreenCaptured?.Invoke(this, info); + renderer.SetInterruptAction(Interrupt); Pipeline = new ThreadedPipeline(this, renderer.Pipeline); Window = new ThreadedWindow(this, renderer); @@ -82,6 +87,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading _galWorkAvailable = new ManualResetEventSlim(false); _invokeRun = new ManualResetEventSlim(); + _interruptRun = new AutoResetEvent(false); _spanPool = new CircularSpanPool(this, SpanPoolBytes); SpanPool = _spanPool; @@ -95,6 +101,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading { _running = true; + _backendThread = Thread.CurrentThread; + _gpuThread = new Thread(() => { gpuLoop(); _running = false; @@ -116,10 +124,18 @@ namespace Ryujinx.Graphics.GAL.Multithreading _galWorkAvailable.Wait(); _galWorkAvailable.Reset(); + if (Volatile.Read(ref _interruptAction) != null) + { + _interruptAction(); + _interruptRun.Set(); + + Interlocked.Exchange(ref _interruptAction, null); + } + // The other thread can only increase the command count. // We can assume that if it is above 0, it will stay there or get higher. - while (_commandCount > 0) + while (_commandCount > 0 && Volatile.Read(ref _interruptAction) == null) { int commandPtr = _consumerPtr; @@ -281,10 +297,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading return sampler; } - public void CreateSync(ulong id) + public void CreateSync(ulong id, bool strict) { Sync.CreateSyncHandle(id); - New<CreateSyncCommand>().Set(id); + New<CreateSyncCommand>().Set(id, strict); QueueCommand(); } @@ -421,6 +437,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading _baseRenderer.WaitSync(id); } + private void Interrupt(Action action) + { + // Interrupt the backend thread from any external thread and invoke the given action. + + if (Thread.CurrentThread == _backendThread) + { + // If this is called from the backend thread, the action can run immediately. + action(); + } + else + { + while (Interlocked.CompareExchange(ref _interruptAction, action, null) != null) { } + + _galWorkAvailable.Set(); + + _interruptRun.WaitOne(); + } + } + + public void SetInterruptAction(Action<Action> interruptAction) + { + // Threaded renderer ignores given interrupt action, as it provides its own to the child renderer. + } + public void Dispose() { // Dispose must happen from the render thread, after all commands have completed. @@ -440,6 +480,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading _frameComplete.Dispose(); _galWorkAvailable.Dispose(); _invokeRun.Dispose(); + _interruptRun.Dispose(); Sync.Dispose(); } |