Compare commits

...

7 commits

Author SHA1 Message Date
riperiperi
d11c191ee5
Merge a46b1bd88c into 95d252b7b8 2024-07-25 18:24:12 +02:00
riperiperi
a46b1bd88c When batching, don't place barriers between every copy 2024-02-24 20:13:31 +00:00
riperiperi
1a85c9a00b Disable delayed counter copy on NVIDIA 2024-02-24 20:13:31 +00:00
riperiperi
71901a54b8 Fix host reserved counter 2024-02-24 20:13:31 +00:00
riperiperi
711360f775 Fix host access reservation for real 2024-02-24 20:13:31 +00:00
riperiperi
0aa6b31b39 Fix host reserved counter 2024-02-24 20:13:31 +00:00
riperiperi
14b2395290 OpenGL: Batch counter copies
Similar to Vulkan, batches counter results to be copied back on render pass switch. We don't control render passes on OpenGL so it just guesses where to flush, as well as forcing it when the host is going to wait.
2024-02-24 20:13:31 +00:00
19 changed files with 139 additions and 66 deletions

View file

@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.GAL
void TextureBarrier(); void TextureBarrier();
void TextureBarrierTiled(); void TextureBarrierTiled();
bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual); bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual, bool forwarded = false);
bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual); bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual);
void EndHostConditionalRendering(); void EndHostConditionalRendering();
} }

View file

@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.GAL
void PreFrame(); void PreFrame();
ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved); ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, int hostReserved);
void ResetCounter(CounterType type); void ResetCounter(CounterType type);

View file

@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
private CounterType _type; private CounterType _type;
private TableRef<EventHandler<ulong>> _resultHandler; private TableRef<EventHandler<ulong>> _resultHandler;
private float _divisor; private float _divisor;
private bool _hostReserved; private int _hostReserved;
public void Set(TableRef<ThreadedCounterEvent> evt, CounterType type, TableRef<EventHandler<ulong>> resultHandler, float divisor, bool hostReserved) public void Set(TableRef<ThreadedCounterEvent> evt, CounterType type, TableRef<EventHandler<ulong>> resultHandler, float divisor, int hostReserved)
{ {
_event = evt; _event = evt;
_type = type; _type = type;

View file

@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
public static void Run(ref TryHostConditionalRenderingCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref TryHostConditionalRenderingCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
renderer.Pipeline.TryHostConditionalRendering(command._value.Get(threaded)?.Base, command._compare, command._isEqual); renderer.Pipeline.TryHostConditionalRendering(command._value.Get(threaded)?.Base, command._compare, command._isEqual, true);
} }
} }
} }

View file

@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
public CounterType Type { get; } public CounterType Type { get; }
public bool ClearCounter { get; } public bool ClearCounter { get; }
private bool _reserved; private int _reserved;
private int _createLock; private int _createLock;
public ThreadedCounterEvent(ThreadedRenderer renderer, CounterType type, bool clearCounter) public ThreadedCounterEvent(ThreadedRenderer renderer, CounterType type, bool clearCounter)
@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
else else
{ {
_reserved = true; Interlocked.Increment(ref _reserved);
} }
Volatile.Write(ref _createLock, 0); Volatile.Write(ref _createLock, 0);
@ -70,10 +70,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
} }
public void Create(IRenderer renderer, CounterType type, System.EventHandler<ulong> eventHandler, float divisor, bool hostReserved) public void Create(IRenderer renderer, CounterType type, System.EventHandler<ulong> eventHandler, float divisor, int hostReserved)
{ {
ThreadedHelpers.SpinUntilExchange(ref _createLock, 1, 0); ThreadedHelpers.SpinUntilExchange(ref _createLock, 1, 0);
Base = renderer.ReportCounter(type, eventHandler, divisor, hostReserved || _reserved); Base = renderer.ReportCounter(type, eventHandler, divisor, hostReserved + _reserved);
Volatile.Write(ref _createLock, 0); Volatile.Write(ref _createLock, 0);
} }
} }

View file

@ -357,7 +357,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual, bool forwarded = false)
{ {
var evt = value as ThreadedCounterEvent; var evt = value as ThreadedCounterEvent;
if (evt != null) if (evt != null)

View file

@ -427,7 +427,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
QueueCommand(); QueueCommand();
} }
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved) public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, int hostReserved)
{ {
ThreadedCounterEvent evt = new(this, type, _lastSampleCounterClear); ThreadedCounterEvent evt = new(this, type, _lastSampleCounterClear);
New<ReportCounterCommand>().Set(Ref(evt), type, Ref(resultHandler), divisor, hostReserved); New<ReportCounterCommand>().Set(Ref(evt), type, Ref(resultHandler), divisor, hostReserved);

View file

@ -179,13 +179,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
case ReportCounterType.SamplesPassed: case ReportCounterType.SamplesPassed:
float scale = _channel.TextureManager.RenderTargetScale; float scale = _channel.TextureManager.RenderTargetScale;
float divisor = scale * scale; float divisor = scale * scale;
counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler, divisor, false); counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler, divisor, 0);
break; break;
case ReportCounterType.PrimitivesGenerated: case ReportCounterType.PrimitivesGenerated:
counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler, 1f, false); counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler, 1f, 0);
break; break;
case ReportCounterType.TransformFeedbackPrimitivesWritten: case ReportCounterType.TransformFeedbackPrimitivesWritten:
counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler, 1f, false); counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler, 1f, 0);
break; break;
} }

View file

@ -45,8 +45,8 @@ namespace Ryujinx.Graphics.OpenGL
public OpenGLRenderer() public OpenGLRenderer()
{ {
_pipeline = new Pipeline();
_counters = new Counters(); _counters = new Counters();
_pipeline = new Pipeline(_counters);
_window = new Window(this); _window = new Window(this);
_textureCopy = new TextureCopy(this); _textureCopy = new TextureCopy(this);
_backgroundTextureCopy = new TextureCopy(this); _backgroundTextureCopy = new TextureCopy(this);
@ -221,7 +221,7 @@ namespace Ryujinx.Graphics.OpenGL
ResourcePool.Tick(); ResourcePool.Tick();
} }
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved) public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, int hostReserved)
{ {
return _counters.QueueReport(type, resultHandler, divisor, _pipeline.DrawCount, hostReserved); return _counters.QueueReport(type, resultHandler, divisor, _pipeline.DrawCount, hostReserved);
} }
@ -257,7 +257,7 @@ namespace Ryujinx.Graphics.OpenGL
public void ResetCounter(CounterType type) public void ResetCounter(CounterType type)
{ {
_counters.QueueReset(type); _counters.QueueReset(type, _pipeline.DrawCount);
} }
public void BackgroundContextAction(Action action, bool alwaysBackground = false) public void BackgroundContextAction(Action action, bool alwaysBackground = false)
@ -299,6 +299,7 @@ namespace Ryujinx.Graphics.OpenGL
public void CreateSync(ulong id, bool strict) public void CreateSync(ulong id, bool strict)
{ {
_counters.CopyPending();
_sync.Create(id); _sync.Create(id);
} }

View file

@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.OpenGL
{ {
private const int SavedImages = 2; private const int SavedImages = 2;
private readonly Counters _counters;
private readonly DrawTextureEmulation _drawTexture; private readonly DrawTextureEmulation _drawTexture;
internal ulong DrawCount { get; private set; } internal ulong DrawCount { get; private set; }
@ -68,8 +70,10 @@ namespace Ryujinx.Graphics.OpenGL
private ColorF _blendConstant; private ColorF _blendConstant;
internal Pipeline() internal Pipeline(Counters counters)
{ {
_counters = counters;
_drawTexture = new DrawTextureEmulation(); _drawTexture = new DrawTextureEmulation();
_rasterizerDiscard = false; _rasterizerDiscard = false;
_clipOrigin = ClipOrigin.LowerLeft; _clipOrigin = ClipOrigin.LowerLeft;
@ -1164,10 +1168,14 @@ namespace Ryujinx.Graphics.OpenGL
RestoreComponentMask(index, force: false); RestoreComponentMask(index, force: false);
} }
_counters.CopyPending();
} }
public void SetRenderTargets(ITexture[] colors, ITexture depthStencil) public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
{ {
_counters.CopyPending();
EnsureFramebuffer(); EnsureFramebuffer();
for (int index = 0; index < colors.Length; index++) for (int index = 0; index < colors.Length; index++)
@ -1523,6 +1531,7 @@ namespace Ryujinx.Graphics.OpenGL
private void PreDraw(int vertexCount) private void PreDraw(int vertexCount)
{ {
_counters.PreDraw();
_vertexArray.PreDraw(vertexCount); _vertexArray.PreDraw(vertexCount);
PreDraw(); PreDraw();
} }
@ -1639,7 +1648,7 @@ namespace Ryujinx.Graphics.OpenGL
} }
} }
public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual, bool forwarded = false)
{ {
// Compare an event and a constant value. // Compare an event and a constant value.
if (value is CounterQueueEvent evt) if (value is CounterQueueEvent evt)
@ -1652,7 +1661,8 @@ namespace Ryujinx.Graphics.OpenGL
if (compare == 0 && evt.Type == QueryTarget.SamplesPassed && evt.ClearCounter) if (compare == 0 && evt.Type == QueryTarget.SamplesPassed && evt.ClearCounter)
{ {
if (!value.ReserveForHostAccess()) // If the call is forwarded from backend threading, then we have already reserved host access.
if (!forwarded && !value.ReserveForHostAccess())
{ {
// If the event has been flushed, then just use the values on the CPU. // If the event has been flushed, then just use the values on the CPU.
// The query object may already be repurposed for another draw (eg. begin + end). // The query object may already be repurposed for another draw (eg. begin + end).
@ -1668,12 +1678,14 @@ namespace Ryujinx.Graphics.OpenGL
// The GPU will flush the queries to CPU and evaluate the condition there instead. // The GPU will flush the queries to CPU and evaluate the condition there instead.
_counters.CopyPending(false);
GL.Flush(); // The thread will be stalled manually flushing the counter, so flush GL commands now. GL.Flush(); // The thread will be stalled manually flushing the counter, so flush GL commands now.
return false; return false;
} }
public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual) public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
{ {
_counters.CopyPending(false);
GL.Flush(); // The GPU thread will be stalled manually flushing the counter, so flush GL commands now. GL.Flush(); // The GPU thread will be stalled manually flushing the counter, so flush GL commands now.
return false; // We don't currently have a way to compare two counters for conditional rendering. return false; // We don't currently have a way to compare two counters for conditional rendering.
} }

View file

@ -18,8 +18,11 @@ namespace Ryujinx.Graphics.OpenGL.Queries
private readonly IntPtr _bufferMap; private readonly IntPtr _bufferMap;
private readonly QueryTarget _type; private readonly QueryTarget _type;
public BufferedQuery(QueryTarget type) private readonly Counters _parent;
public BufferedQuery(Counters parent, QueryTarget type)
{ {
_parent = parent;
_buffer = GL.GenBuffer(); _buffer = GL.GenBuffer();
Query = GL.GenQuery(); Query = GL.GenQuery();
_type = type; _type = type;
@ -42,20 +45,31 @@ namespace Ryujinx.Graphics.OpenGL.Queries
public void Begin() public void Begin()
{ {
Marshal.WriteInt64(_bufferMap, -1L);
GL.BeginQuery(_type, Query); GL.BeginQuery(_type, Query);
} }
public unsafe void End(bool withResult) public unsafe void CopyQueryResult(bool withBarrier)
{
GL.BindBuffer(BufferTarget.QueryBuffer, _buffer);
GL.GetQueryObject(Query, GetQueryObjectParam.QueryResult, (long*)0);
if (withBarrier)
{
GL.MemoryBarrier(MemoryBarrierFlags.QueryBufferBarrierBit | MemoryBarrierFlags.ClientMappedBufferBarrierBit);
}
}
public void End(bool withResult)
{ {
GL.EndQuery(_type); GL.EndQuery(_type);
if (withResult) if (withResult)
{ {
GL.BindBuffer(BufferTarget.QueryBuffer, _buffer); if (!_parent.QueueCopy(this))
{
Marshal.WriteInt64(_bufferMap, -1L); CopyQueryResult(true);
GL.GetQueryObject(Query, GetQueryObjectParam.QueryResult, (long*)0); }
GL.MemoryBarrier(MemoryBarrierFlags.QueryBufferBarrierBit | MemoryBarrierFlags.ClientMappedBufferBarrierBit);
} }
else else
{ {

View file

@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.OpenGL.Queries
public CounterType Type { get; } public CounterType Type { get; }
public bool Disposed { get; private set; } public bool Disposed { get; private set; }
private readonly Counters _parent;
private readonly Queue<CounterQueueEvent> _events = new(); private readonly Queue<CounterQueueEvent> _events = new();
private CounterQueueEvent _current; private CounterQueueEvent _current;
@ -28,8 +30,9 @@ namespace Ryujinx.Graphics.OpenGL.Queries
private readonly Thread _consumerThread; private readonly Thread _consumerThread;
internal CounterQueue(CounterType type) internal CounterQueue(Counters parent, CounterType type)
{ {
_parent = parent;
Type = type; Type = type;
QueryTarget glType = GetTarget(Type); QueryTarget glType = GetTarget(Type);
@ -37,7 +40,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
_queryPool = new Queue<BufferedQuery>(QueryPoolInitialSize); _queryPool = new Queue<BufferedQuery>(QueryPoolInitialSize);
for (int i = 0; i < QueryPoolInitialSize; i++) for (int i = 0; i < QueryPoolInitialSize; i++)
{ {
_queryPool.Enqueue(new BufferedQuery(glType)); _queryPool.Enqueue(new BufferedQuery(parent, glType));
} }
_current = new CounterQueueEvent(this, glType, 0); _current = new CounterQueueEvent(this, glType, 0);
@ -90,7 +93,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
} }
else else
{ {
return new BufferedQuery(GetTarget(Type)); return new BufferedQuery(_parent, GetTarget(Type));
} }
} }
} }
@ -103,7 +106,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
} }
} }
public CounterQueueEvent QueueReport(EventHandler<ulong> resultHandler, float divisor, ulong lastDrawIndex, bool hostReserved) public CounterQueueEvent QueueReport(EventHandler<ulong> resultHandler, float divisor, ulong lastDrawIndex, int hostReserved)
{ {
CounterQueueEvent result; CounterQueueEvent result;
ulong draws = lastDrawIndex - _current.DrawIndex; ulong draws = lastDrawIndex - _current.DrawIndex;
@ -113,9 +116,9 @@ namespace Ryujinx.Graphics.OpenGL.Queries
// A query's result only matters if more than one draw was performed during it. // A query's result only matters if more than one draw was performed during it.
// Otherwise, dummy it out and return 0 immediately. // Otherwise, dummy it out and return 0 immediately.
if (hostReserved) while (hostReserved-- > 0)
{ {
// This counter event is guaranteed to be available for host conditional rendering. // This counter event is guaranteed to be available for host conditional rendering for the given number of uses.
_current.ReserveForHostAccess(); _current.ReserveForHostAccess();
} }
@ -134,11 +137,11 @@ namespace Ryujinx.Graphics.OpenGL.Queries
return result; return result;
} }
public void QueueReset() public void QueueReset(ulong lastDrawIndex)
{ {
lock (_lock) lock (_lock)
{ {
_current.Clear(); _current.Clear(lastDrawIndex);
} }
} }

View file

@ -16,12 +16,12 @@ namespace Ryujinx.Graphics.OpenGL.Queries
public bool Disposed { get; private set; } public bool Disposed { get; private set; }
public bool Invalid { get; set; } public bool Invalid { get; set; }
public ulong DrawIndex { get; } public ulong DrawIndex { get; private set; }
private readonly CounterQueue _queue; private readonly CounterQueue _queue;
private readonly BufferedQuery _counter; private readonly BufferedQuery _counter;
private bool _hostAccessReserved = false; private int _hostAccessReserved = 0;
private int _refCount = 1; // Starts with a reference from the counter queue. private int _refCount = 1; // Starts with a reference from the counter queue.
private readonly object _lock = new(); private readonly object _lock = new();
@ -40,10 +40,11 @@ namespace Ryujinx.Graphics.OpenGL.Queries
_counter.Begin(); _counter.Begin();
} }
internal void Clear() internal void Clear(ulong drawIndex)
{ {
_counter.Reset(); _counter.Reset();
ClearCounter = true; ClearCounter = true;
DrawIndex = drawIndex;
} }
internal void Complete(bool withResult, double divisor) internal void Complete(bool withResult, double divisor)
@ -114,12 +115,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
public bool ReserveForHostAccess() public bool ReserveForHostAccess()
{ {
if (_hostAccessReserved) if (_hostAccessReserved == 0 && IsValueAvailable())
{
return true;
}
if (IsValueAvailable())
{ {
return false; return false;
} }
@ -131,14 +127,14 @@ namespace Ryujinx.Graphics.OpenGL.Queries
return false; return false;
} }
_hostAccessReserved = true; Interlocked.Increment(ref _hostAccessReserved);
return true; return true;
} }
public void ReleaseHostAccess() public void ReleaseHostAccess()
{ {
_hostAccessReserved = false; Interlocked.Decrement(ref _hostAccessReserved);
DecrementRefCount(); DecrementRefCount();
} }

View file

@ -1,17 +1,23 @@
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.OpenGL.Queries namespace Ryujinx.Graphics.OpenGL.Queries
{ {
class Counters : IDisposable class Counters : IDisposable
{ {
private const int ForceCopyThreshold = 32;
private readonly CounterQueue[] _counterQueues; private readonly CounterQueue[] _counterQueues;
private readonly List<BufferedQuery> _queuedCopies;
private bool _flushedThisPass;
public Counters() public Counters()
{ {
int count = Enum.GetNames<CounterType>().Length; int count = Enum.GetNames<CounterType>().Length;
_counterQueues = new CounterQueue[count]; _counterQueues = new CounterQueue[count];
_queuedCopies = new List<BufferedQuery>();
} }
public void Initialize() public void Initialize()
@ -19,18 +25,18 @@ namespace Ryujinx.Graphics.OpenGL.Queries
for (int index = 0; index < _counterQueues.Length; index++) for (int index = 0; index < _counterQueues.Length; index++)
{ {
CounterType type = (CounterType)index; CounterType type = (CounterType)index;
_counterQueues[index] = new CounterQueue(type); _counterQueues[index] = new CounterQueue(this, type);
} }
} }
public CounterQueueEvent QueueReport(CounterType type, EventHandler<ulong> resultHandler, float divisor, ulong lastDrawIndex, bool hostReserved) public CounterQueueEvent QueueReport(CounterType type, EventHandler<ulong> resultHandler, float divisor, ulong lastDrawIndex, int hostReserved)
{ {
return _counterQueues[(int)type].QueueReport(resultHandler, divisor, lastDrawIndex, hostReserved); return _counterQueues[(int)type].QueueReport(resultHandler, divisor, lastDrawIndex, hostReserved);
} }
public void QueueReset(CounterType type) public void QueueReset(CounterType type, ulong lastDrawIndex)
{ {
_counterQueues[(int)type].QueueReset(); _counterQueues[(int)type].QueueReset(lastDrawIndex);
} }
public void Update() public void Update()
@ -46,6 +52,51 @@ namespace Ryujinx.Graphics.OpenGL.Queries
_counterQueues[(int)type].Flush(true); _counterQueues[(int)type].Flush(true);
} }
public void PreDraw()
{
// Force results to be copied some time into an occlusion query pass.
if (!_flushedThisPass && _queuedCopies.Count > ForceCopyThreshold)
{
_flushedThisPass = true;
CopyPending(false);
}
}
public void CopyPending(bool newPass = true)
{
if (_queuedCopies.Count > 0)
{
int i = 0;
foreach (BufferedQuery query in _queuedCopies)
{
query.CopyQueryResult(_queuedCopies.Count == ++i);
}
_queuedCopies.Clear();
}
if (newPass)
{
_flushedThisPass = false;
}
}
public bool QueueCopy(BufferedQuery query)
{
if (HwCapabilities.Vendor == HwCapabilities.GpuVendor.Nvidia)
{
// NVIDIA seems to make up a rule where query results can't be copied to buffers
// when unrelated query objects are in use.
return false;
}
else
{
_queuedCopies.Add(query);
return true;
}
}
public void Dispose() public void Dispose()
{ {
foreach (var queue in _counterQueues) foreach (var queue in _counterQueues)

View file

@ -133,7 +133,7 @@ namespace Ryujinx.Graphics.Vulkan
_activeConditionalRender = null; _activeConditionalRender = null;
} }
public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual) public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual, bool forwarded = false)
{ {
// Compare an event and a constant value. // Compare an event and a constant value.
if (value is CounterQueueEvent evt) if (value is CounterQueueEvent evt)
@ -146,7 +146,8 @@ namespace Ryujinx.Graphics.Vulkan
if (compare == 0 && evt.Type == CounterType.SamplesPassed && evt.ClearCounter) if (compare == 0 && evt.Type == CounterType.SamplesPassed && evt.ClearCounter)
{ {
if (!value.ReserveForHostAccess()) // If the call is forwarded from backend threading, then we have already reserved host access.
if (!forwarded && !value.ReserveForHostAccess())
{ {
// If the event has been flushed, then just use the values on the CPU. // If the event has been flushed, then just use the values on the CPU.
// The query object may already be repurposed for another draw (eg. begin + end). // The query object may already be repurposed for another draw (eg. begin + end).

View file

@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
} }
} }
public CounterQueueEvent QueueReport(EventHandler<ulong> resultHandler, float divisor, ulong lastDrawIndex, bool hostReserved) public CounterQueueEvent QueueReport(EventHandler<ulong> resultHandler, float divisor, ulong lastDrawIndex, int hostReserved)
{ {
CounterQueueEvent result; CounterQueueEvent result;
ulong draws = lastDrawIndex - _current.DrawIndex; ulong draws = lastDrawIndex - _current.DrawIndex;
@ -149,9 +149,9 @@ namespace Ryujinx.Graphics.Vulkan.Queries
// A query's result only matters if more than one draw was performed during it. // A query's result only matters if more than one draw was performed during it.
// Otherwise, dummy it out and return 0 immediately. // Otherwise, dummy it out and return 0 immediately.
if (hostReserved) while (hostReserved-- > 0)
{ {
// This counter event is guaranteed to be available for host conditional rendering. // This counter event is guaranteed to be available for host conditional rendering for the given number of uses.
_current.ReserveForHostAccess(); _current.ReserveForHostAccess();
} }

View file

@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
private readonly CounterQueue _queue; private readonly CounterQueue _queue;
private readonly BufferedQuery _counter; private readonly BufferedQuery _counter;
private bool _hostAccessReserved; private int _hostAccessReserved;
private int _refCount = 1; // Starts with a reference from the counter queue. private int _refCount = 1; // Starts with a reference from the counter queue.
private readonly object _lock = new(); private readonly object _lock = new();
@ -121,12 +121,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
public bool ReserveForHostAccess() public bool ReserveForHostAccess()
{ {
if (_hostAccessReserved) if (_hostAccessReserved == 0 && IsValueAvailable())
{
return true;
}
if (IsValueAvailable())
{ {
return false; return false;
} }
@ -138,14 +133,14 @@ namespace Ryujinx.Graphics.Vulkan.Queries
return false; return false;
} }
_hostAccessReserved = true; Interlocked.Increment(ref _hostAccessReserved);
return true; return true;
} }
public void ReleaseHostAccess() public void ReleaseHostAccess()
{ {
_hostAccessReserved = false; Interlocked.Decrement(ref _hostAccessReserved);
DecrementRefCount(); DecrementRefCount();
} }

View file

@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
_counterQueues[(int)CounterType.SamplesPassed].ResetFutureCounters(cmd, count); _counterQueues[(int)CounterType.SamplesPassed].ResetFutureCounters(cmd, count);
} }
public CounterQueueEvent QueueReport(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved) public CounterQueueEvent QueueReport(CounterType type, EventHandler<ulong> resultHandler, float divisor, int hostReserved)
{ {
return _counterQueues[(int)type].QueueReport(resultHandler, divisor, _pipeline.DrawCount, hostReserved); return _counterQueues[(int)type].QueueReport(resultHandler, divisor, _pipeline.DrawCount, hostReserved);
} }

View file

@ -869,7 +869,7 @@ namespace Ryujinx.Graphics.Vulkan
SyncManager.Cleanup(); SyncManager.Cleanup();
} }
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved) public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, int hostReserved)
{ {
return _counters.QueueReport(type, resultHandler, divisor, hostReserved); return _counters.QueueReport(type, resultHandler, divisor, hostReserved);
} }