aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL/Queries
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.OpenGL/Queries')
-rw-r--r--Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs1
-rw-r--r--Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs47
-rw-r--r--Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs59
-rw-r--r--Ryujinx.Graphics.OpenGL/Queries/Counters.cs4
4 files changed, 90 insertions, 21 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs b/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs
index a87655be..7323abfe 100644
--- a/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs
+++ b/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs
@@ -54,6 +54,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
Marshal.WriteInt64(_bufferMap, -1L);
GL.GetQueryObject(Query, GetQueryObjectParam.QueryResult, (long*)0);
+ GL.MemoryBarrier(MemoryBarrierFlags.QueryBufferBarrierBit | MemoryBarrierFlags.ClientMappedBufferBarrierBit);
}
}
diff --git a/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs b/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs
index 5984a7ca..f4ab02fb 100644
--- a/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs
+++ b/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs
@@ -17,12 +17,14 @@ namespace Ryujinx.Graphics.OpenGL.Queries
private CounterQueueEvent _current;
private ulong _accumulatedCounter;
+ private int _waiterCount;
private object _lock = new object();
private Queue<BufferedQuery> _queryPool;
private AutoResetEvent _queuedEvent = new AutoResetEvent(false);
private AutoResetEvent _wakeSignal = new AutoResetEvent(false);
+ private AutoResetEvent _eventConsumed = new AutoResetEvent(false);
private Thread _consumerThread;
@@ -63,7 +65,13 @@ namespace Ryujinx.Graphics.OpenGL.Queries
}
else
{
- evt.TryConsume(ref _accumulatedCounter, true, _wakeSignal);
+ // Spin-wait rather than sleeping if there are any waiters, by passing null instead of the wake signal.
+ evt.TryConsume(ref _accumulatedCounter, true, _waiterCount == 0 ? _wakeSignal : null);
+ }
+
+ if (_waiterCount > 0)
+ {
+ _eventConsumed.Set();
}
}
}
@@ -95,7 +103,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
}
}
- public CounterQueueEvent QueueReport(EventHandler<ulong> resultHandler, ulong lastDrawIndex)
+ public CounterQueueEvent QueueReport(EventHandler<ulong> resultHandler, ulong lastDrawIndex, bool hostReserved)
{
CounterQueueEvent result;
ulong draws = lastDrawIndex - _current.DrawIndex;
@@ -105,6 +113,12 @@ namespace Ryujinx.Graphics.OpenGL.Queries
// A query's result only matters if more than one draw was performed during it.
// Otherwise, dummy it out and return 0 immediately.
+ if (hostReserved)
+ {
+ // This counter event is guaranteed to be available for host conditional rendering.
+ _current.ReserveForHostAccess();
+ }
+
if (draws > 0)
{
_current.Complete(true);
@@ -175,25 +189,18 @@ namespace Ryujinx.Graphics.OpenGL.Queries
public void FlushTo(CounterQueueEvent evt)
{
- lock (_lock)
- {
- if (evt.Disposed)
- {
- return;
- }
+ // Flush the counter queue on the main thread.
- // Tell the queue to process all events up to this one.
- while (_events.Count > 0)
- {
- CounterQueueEvent flush = _events.Dequeue();
- flush.TryConsume(ref _accumulatedCounter, true);
+ Interlocked.Increment(ref _waiterCount);
- if (flush == evt)
- {
- return;
- }
- }
+ _wakeSignal.Set();
+
+ while (!evt.Disposed)
+ {
+ _eventConsumed.WaitOne(1);
}
+
+ Interlocked.Decrement(ref _waiterCount);
}
public void Dispose()
@@ -218,6 +225,10 @@ namespace Ryujinx.Graphics.OpenGL.Queries
{
query.Dispose();
}
+
+ _queuedEvent.Dispose();
+ _wakeSignal.Dispose();
+ _eventConsumed.Dispose();
}
}
}
diff --git a/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs b/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs
index 0e1025af..8b0ae30e 100644
--- a/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs
+++ b/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs
@@ -1,4 +1,5 @@
using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using System;
using System.Threading;
@@ -21,7 +22,11 @@ namespace Ryujinx.Graphics.OpenGL.Queries
private CounterQueue _queue;
private BufferedQuery _counter;
+ private bool _hostAccessReserved = false;
+ private int _refCount = 1; // Starts with a reference from the counter queue.
+
private object _lock = new object();
+ private ulong _result = ulong.MaxValue;
public CounterQueueEvent(CounterQueue queue, QueryTarget type, ulong drawIndex)
{
@@ -76,6 +81,8 @@ namespace Ryujinx.Graphics.OpenGL.Queries
result += (ulong)queryResult;
+ _result = result;
+
OnResult?.Invoke(this, result);
Dispose(); // Return the our resources to the pool.
@@ -95,10 +102,60 @@ namespace Ryujinx.Graphics.OpenGL.Queries
_queue.FlushTo(this);
}
+ public void DecrementRefCount()
+ {
+ if (Interlocked.Decrement(ref _refCount) == 0)
+ {
+ DisposeInternal();
+ }
+ }
+
+ public bool ReserveForHostAccess()
+ {
+ if (_hostAccessReserved)
+ {
+ return true;
+ }
+
+ if (IsValueAvailable())
+ {
+ return false;
+ }
+
+ if (Interlocked.Increment(ref _refCount) == 1)
+ {
+ Interlocked.Decrement(ref _refCount);
+
+ return false;
+ }
+
+ _hostAccessReserved = true;
+
+ return true;
+ }
+
+ public void ReleaseHostAccess()
+ {
+ _hostAccessReserved = false;
+
+ DecrementRefCount();
+ }
+
+ private void DisposeInternal()
+ {
+ _queue.ReturnQueryObject(_counter);
+ }
+
+ private bool IsValueAvailable()
+ {
+ return _result != ulong.MaxValue || _counter.TryGetResult(out _);
+ }
+
public void Dispose()
{
Disposed = true;
- _queue.ReturnQueryObject(_counter);
+
+ DecrementRefCount();
}
}
}
diff --git a/Ryujinx.Graphics.OpenGL/Queries/Counters.cs b/Ryujinx.Graphics.OpenGL/Queries/Counters.cs
index ac441d5f..0c0a915d 100644
--- a/Ryujinx.Graphics.OpenGL/Queries/Counters.cs
+++ b/Ryujinx.Graphics.OpenGL/Queries/Counters.cs
@@ -23,9 +23,9 @@ namespace Ryujinx.Graphics.OpenGL.Queries
}
}
- public CounterQueueEvent QueueReport(CounterType type, EventHandler<ulong> resultHandler, ulong lastDrawIndex)
+ public CounterQueueEvent QueueReport(CounterType type, EventHandler<ulong> resultHandler, ulong lastDrawIndex, bool hostReserved)
{
- return _counterQueues[(int)type].QueueReport(resultHandler, lastDrawIndex);
+ return _counterQueues[(int)type].QueueReport(resultHandler, lastDrawIndex, hostReserved);
}
public void QueueReset(CounterType type)