Update counter queue to be similar to the OGL one

Fixes softlocks when games had to flush counters.
This commit is contained in:
riperiperi 2021-12-08 13:17:21 +00:00
parent d55f664908
commit 23b8bd8642
2 changed files with 34 additions and 32 deletions

View file

@ -206,16 +206,25 @@ namespace Ryujinx.Graphics.Vulkan
// The GPU will flush the queries to CPU and evaluate the condition there instead.
FlushCommandsImpl(); // The thread will be stalled manually flushing the counter, so flush GL commands now.
FlushPendingQuery(); // The thread will be stalled manually flushing the counter, so flush commands now.
return false;
}
public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
{
FlushCommandsImpl(); // The thread will be stalled manually flushing the counter, so flush GL commands now.
FlushPendingQuery(); // The thread will be stalled manually flushing the counter, so flush commands now.
return false;
}
private void FlushPendingQuery()
{
if (_hasPendingQuery)
{
_hasPendingQuery = false;
FlushCommandsImpl();
}
}
public void FlushCommandsImpl([System.Runtime.CompilerServices.CallerMemberName] string caller = "")
{
// System.Console.WriteLine("flush by " + caller);
@ -285,11 +294,7 @@ namespace Ryujinx.Graphics.Vulkan
protected override void SignalProgramChange()
{
if (_hasPendingQuery)
{
_hasPendingQuery = false;
FlushCommandsImpl();
}
FlushPendingQuery();
}
}
}

View file

@ -21,12 +21,14 @@ namespace Ryujinx.Graphics.Vulkan.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;
@ -69,7 +71,13 @@ namespace Ryujinx.Graphics.Vulkan.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();
}
}
}
@ -175,32 +183,17 @@ namespace Ryujinx.Graphics.Vulkan.Queries
public void FlushTo(CounterQueueEvent evt)
{
lock (_lock)
// Flush the counter queue on the main thread.
Interlocked.Increment(ref _waiterCount);
_wakeSignal.Set();
while (!evt.Disposed)
{
if (evt.Disposed)
{
return;
}
// Tell the queue to process all events up to this one.
while (_events.Count > 0)
{
CounterQueueEvent flush = _events.Peek();
if (flush.DrawIndex > evt.DrawIndex)
{
return;
}
_events.Dequeue();
flush.TryConsume(ref _accumulatedCounter, true);
if (flush == evt)
{
return;
}
}
_eventConsumed.WaitOne(1);
}
Interlocked.Decrement(ref _waiterCount);
}
public void Dispose()
@ -227,6 +220,10 @@ namespace Ryujinx.Graphics.Vulkan.Queries
{
query.Dispose();
}
_queuedEvent.Dispose();
_wakeSignal.Dispose();
_eventConsumed.Dispose();
}
}
}