aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2021-01-17 20:08:06 +0000
committerGitHub <noreply@github.com>2021-01-17 17:08:06 -0300
commita1f77a5b6ab33bbcc0a8e070e50cee24ad82eac1 (patch)
tree9faccd644a7eac3f33ad5e66db87c947dab972ed /Ryujinx.Graphics.OpenGL
parentc4f56c570494a6186792439e3c0e74458cc82b5c (diff)
Implement lazy flush-on-read for Buffers (SSBO/Copy) (#1790)
* Initial implementation of buffer flush (VERY WIP) * Host shaders need to be rebuilt for the SSBO write flag. * New approach with reserved regions and gl sync * Fix a ton of buffer issues. * Remove unused buffer unmapped behaviour * Revert "Remove unused buffer unmapped behaviour" This reverts commit f1700e52fb8760180ac5e0987a07d409d1e70ece. * Delete modified ranges on unmap Fixes potential crashes in Super Smash Bros, where a previously modified range could lie on either side of an unmap. * Cache some more delegates. * Dispose Sync on Close * Also create host sync for GPFifo syncpoint increment. * Copy buffer optimization, add docs * Fix race condition with OpenGL Sync * Enable read tracking on CommandBuffer, insert syncpoint on WaitForIdle * Performance: Only flush individual pages of SSBO at a time This avoids flushing large amounts of data when only a small amount is actually used. * Signal Modified rather than flushing after clear * Fix some docs and code style. * Introduce a new test for tracking memory protection. Sucessfully demonstrates that the bug causing write protection to be cleared by a read action has been fixed. (these tests fail on master) * Address Comments * Add host sync for SetReference This ensures that any indirect draws will correctly flush any related buffer data written before them. Fixes some flashing and misplaced world geometry in MH rise. * Make PageAlign static * Re-enable read tracking, for reads.
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();
+ }
+ }
+ }
+}