diff options
Diffstat (limited to 'Ryujinx.Graphics.OpenGL/Queries')
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs | 1 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs | 47 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs | 59 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Queries/Counters.cs | 4 |
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) |
