aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.OpenGL')
-rw-r--r--Ryujinx.Graphics.OpenGL/Renderer.cs15
-rw-r--r--Ryujinx.Graphics.OpenGL/Sync.cs129
2 files changed, 144 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index acbc24de..4a3f51bf 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -26,6 +26,8 @@ namespace Ryujinx.Graphics.OpenGL
private TextureCopy _backgroundTextureCopy;
internal TextureCopy TextureCopy => BackgroundContextWorker.InBackground ? _backgroundTextureCopy : _textureCopy;
+ private Sync _sync;
+
internal ResourcePool ResourcePool { get; }
public string GpuVendor { get; private set; }
@@ -39,6 +41,7 @@ namespace Ryujinx.Graphics.OpenGL
_window = new Window(this);
_textureCopy = new TextureCopy(this);
_backgroundTextureCopy = new TextureCopy(this);
+ _sync = new Sync();
ResourcePool = new ResourcePool();
}
@@ -108,6 +111,7 @@ namespace Ryujinx.Graphics.OpenGL
public void PreFrame()
{
+ _sync.Cleanup();
ResourcePool.Tick();
}
@@ -164,6 +168,7 @@ namespace Ryujinx.Graphics.OpenGL
_pipeline.Dispose();
_window.Dispose();
_counters.Dispose();
+ _sync.Dispose();
}
public IProgram LoadProgramBinary(byte[] programBinary)
@@ -179,5 +184,15 @@ namespace Ryujinx.Graphics.OpenGL
return null;
}
+
+ public void CreateSync(ulong id)
+ {
+ _sync.Create(id);
+ }
+
+ public void WaitSync(ulong id)
+ {
+ _sync.Wait(id);
+ }
}
}
diff --git a/Ryujinx.Graphics.OpenGL/Sync.cs b/Ryujinx.Graphics.OpenGL/Sync.cs
new file mode 100644
index 00000000..97a71fc4
--- /dev/null
+++ b/Ryujinx.Graphics.OpenGL/Sync.cs
@@ -0,0 +1,129 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Graphics.OpenGL
+{
+ class Sync : IDisposable
+ {
+ private class SyncHandle
+ {
+ public ulong ID;
+ public IntPtr Handle;
+ }
+
+ private ulong _firstHandle = 0;
+
+ private List<SyncHandle> Handles = new List<SyncHandle>();
+
+ public void Create(ulong id)
+ {
+ SyncHandle handle = new SyncHandle
+ {
+ ID = id,
+ Handle = GL.FenceSync(SyncCondition.SyncGpuCommandsComplete, WaitSyncFlags.None)
+ };
+
+ lock (Handles)
+ {
+ Handles.Add(handle);
+ }
+ }
+
+ public void Wait(ulong id)
+ {
+ SyncHandle result = null;
+
+ lock (Handles)
+ {
+ if ((long)(_firstHandle - id) > 0)
+ {
+ return; // The handle has already been signalled or deleted.
+ }
+
+ foreach (SyncHandle handle in Handles)
+ {
+ if (handle.ID == id)
+ {
+ result = handle;
+ break;
+ }
+ }
+ }
+
+ if (result != null)
+ {
+ lock (result)
+ {
+ if (result.Handle == IntPtr.Zero)
+ {
+ return;
+ }
+
+ WaitSyncStatus syncResult = GL.ClientWaitSync(result.Handle, ClientWaitSyncFlags.SyncFlushCommandsBit, 1000000000);
+
+ if (syncResult == WaitSyncStatus.TimeoutExpired)
+ {
+ Logger.Error?.PrintMsg(LogClass.Gpu, $"GL Sync Object {result.ID} failed to signal within 1000ms. Continuing...");
+ }
+ }
+ }
+ }
+
+ public void Cleanup()
+ {
+ // Iterate through handles and remove any that have already been signalled.
+
+ while (true)
+ {
+ SyncHandle first = null;
+ lock (Handles)
+ {
+ first = Handles.FirstOrDefault();
+ }
+
+ if (first == null) break;
+
+ WaitSyncStatus syncResult = GL.ClientWaitSync(first.Handle, ClientWaitSyncFlags.SyncFlushCommandsBit, 0);
+
+ if (syncResult == WaitSyncStatus.AlreadySignaled)
+ {
+ // Delete the sync object.
+ lock (Handles)
+ {
+ lock (first)
+ {
+ _firstHandle = first.ID + 1;
+ Handles.RemoveAt(0);
+ GL.DeleteSync(first.Handle);
+ first.Handle = IntPtr.Zero;
+ }
+ }
+ } else
+ {
+ // This sync handle and any following have not been reached yet.
+ break;
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ lock (Handles)
+ {
+ foreach (SyncHandle handle in Handles)
+ {
+ lock (handle)
+ {
+ GL.DeleteSync(handle.Handle);
+ handle.Handle = IntPtr.Zero;
+ }
+ }
+
+ Handles.Clear();
+ }
+ }
+ }
+}