aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs')
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs47
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();
}