aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2020-05-04 03:24:59 +0100
committerGitHub <noreply@github.com>2020-05-04 12:24:59 +1000
commitcd48576f5846aa89a36bfc833e9de5dde9627aed (patch)
tree5bf04a43725cf7fdc098cde59856798a67b839e0 /Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs
parent651a07c6c2a3e89c059d56e916c45e1881d56abc (diff)
Implement Counter Queue and Partial Host Conditional Rendering (#1167)
* Implementation of query queue and host conditional rendering * Resolve some comments. * Use overloads instead of passing object. * Wake the consumer threads when incrementing syncpoints. Also, do a busy loop when awaiting the counter for a blocking flush, rather than potentially sleeping the thread. * Ensure there's a command between begin and end query.
Diffstat (limited to 'Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs')
-rw-r--r--Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs105
1 files changed, 105 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs b/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs
new file mode 100644
index 00000000..9750ec92
--- /dev/null
+++ b/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs
@@ -0,0 +1,105 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common.Logging;
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace Ryujinx.Graphics.OpenGL.Queries
+{
+ class BufferedQuery : IDisposable
+ {
+ private const int MaxQueryRetries = 5000;
+ private const long DefaultValue = -1;
+
+ public int Query { get; }
+
+ private int _buffer;
+ private IntPtr _bufferMap;
+ private QueryTarget _type;
+
+ public BufferedQuery(QueryTarget type)
+ {
+ _buffer = GL.GenBuffer();
+ Query = GL.GenQuery();
+ _type = type;
+
+ GL.BindBuffer(BufferTarget.QueryBuffer, _buffer);
+
+ unsafe
+ {
+ long defaultValue = DefaultValue;
+ GL.BufferStorage(BufferTarget.QueryBuffer, sizeof(long), (IntPtr)(&defaultValue), BufferStorageFlags.MapReadBit | BufferStorageFlags.MapWriteBit | BufferStorageFlags.MapPersistentBit);
+ }
+ _bufferMap = GL.MapBufferRange(BufferTarget.QueryBuffer, IntPtr.Zero, sizeof(long), BufferAccessMask.MapReadBit | BufferAccessMask.MapWriteBit | BufferAccessMask.MapPersistentBit);
+ }
+
+ public void Reset()
+ {
+ GL.EndQuery(_type);
+ GL.BeginQuery(_type, Query);
+ }
+
+ public void Begin()
+ {
+ GL.BeginQuery(_type, Query);
+ }
+
+ public unsafe void End()
+ {
+ GL.Flush();
+ GL.EndQuery(_type);
+
+ GL.BindBuffer(BufferTarget.QueryBuffer, _buffer);
+
+ Marshal.WriteInt64(_bufferMap, -1L);
+ GL.GetQueryObject(Query, GetQueryObjectParam.QueryResult, (long*)0);
+ }
+
+ public bool TryGetResult(out long result)
+ {
+ result = Marshal.ReadInt64(_bufferMap);
+
+ return result != DefaultValue;
+ }
+
+ public long AwaitResult(AutoResetEvent wakeSignal = null)
+ {
+ long data = DefaultValue;
+
+ if (wakeSignal == null)
+ {
+ while (data == DefaultValue)
+ {
+ data = Marshal.ReadInt64(_bufferMap);
+ }
+ }
+ else
+ {
+ int iterations = 0;
+ while (data == DefaultValue && iterations++ < MaxQueryRetries)
+ {
+ data = Marshal.ReadInt64(_bufferMap);
+ if (data == DefaultValue)
+ {
+ wakeSignal.WaitOne(1);
+ }
+ }
+
+ if (iterations >= MaxQueryRetries)
+ {
+ Logger.PrintError(LogClass.Gpu, $"Error: Query result timed out. Took more than {MaxQueryRetries} tries.");
+ }
+ }
+
+ return data;
+ }
+
+ public void Dispose()
+ {
+ GL.BindBuffer(BufferTarget.QueryBuffer, _buffer);
+ GL.UnmapBuffer(BufferTarget.QueryBuffer);
+ GL.DeleteBuffer(_buffer);
+ GL.DeleteQuery(Query);
+ }
+ }
+}