diff options
Diffstat (limited to 'Ryujinx.Graphics.OpenGL')
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Renderer.cs | 15 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Sync.cs | 129 |
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(); + } + } + } +} |
