diff options
author | riperiperi <rhy3756547@hotmail.com> | 2020-05-04 03:24:59 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-04 12:24:59 +1000 |
commit | cd48576f5846aa89a36bfc833e9de5dde9627aed (patch) | |
tree | 5bf04a43725cf7fdc098cde59856798a67b839e0 /Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs | |
parent | 651a07c6c2a3e89c059d56e916c45e1881d56abc (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.cs | 105 |
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); + } + } +} |