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.
This commit is contained in:
parent
4d0dbbfae2
commit
14b2395290
6 changed files with 87 additions and 20 deletions
|
@ -45,8 +45,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
public OpenGLRenderer()
|
||||
{
|
||||
_pipeline = new Pipeline();
|
||||
_counters = new Counters();
|
||||
_pipeline = new Pipeline(_counters);
|
||||
_window = new Window(this);
|
||||
_textureCopy = new TextureCopy(this);
|
||||
_backgroundTextureCopy = new TextureCopy(this);
|
||||
|
@ -241,7 +241,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
public void ResetCounter(CounterType type)
|
||||
{
|
||||
_counters.QueueReset(type);
|
||||
_counters.QueueReset(type, _pipeline.DrawCount);
|
||||
}
|
||||
|
||||
public void BackgroundContextAction(Action action, bool alwaysBackground = false)
|
||||
|
@ -283,6 +283,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
public void CreateSync(ulong id, bool strict)
|
||||
{
|
||||
_counters.CopyPending();
|
||||
_sync.Create(id);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
private const int SavedImages = 2;
|
||||
|
||||
private readonly Counters _counters;
|
||||
|
||||
private readonly DrawTextureEmulation _drawTexture;
|
||||
|
||||
internal ulong DrawCount { get; private set; }
|
||||
|
@ -68,8 +70,10 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
private ColorF _blendConstant;
|
||||
|
||||
internal Pipeline()
|
||||
internal Pipeline(Counters counters)
|
||||
{
|
||||
_counters = counters;
|
||||
|
||||
_drawTexture = new DrawTextureEmulation();
|
||||
_rasterizerDiscard = false;
|
||||
_clipOrigin = ClipOrigin.LowerLeft;
|
||||
|
@ -1154,10 +1158,14 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
RestoreComponentMask(index, force: false);
|
||||
}
|
||||
|
||||
_counters.CopyPending();
|
||||
}
|
||||
|
||||
public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
|
||||
{
|
||||
_counters.CopyPending();
|
||||
|
||||
EnsureFramebuffer();
|
||||
|
||||
for (int index = 0; index < colors.Length; index++)
|
||||
|
@ -1504,6 +1512,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
private void PreDraw(int vertexCount)
|
||||
{
|
||||
_counters.PreDraw();
|
||||
_vertexArray.PreDraw(vertexCount);
|
||||
PreDraw();
|
||||
}
|
||||
|
@ -1649,12 +1658,14 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
// 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.
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
return false; // We don't currently have a way to compare two counters for conditional rendering.
|
||||
}
|
||||
|
|
|
@ -18,8 +18,11 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
private readonly IntPtr _bufferMap;
|
||||
private readonly QueryTarget _type;
|
||||
|
||||
public BufferedQuery(QueryTarget type)
|
||||
private readonly Counters _parent;
|
||||
|
||||
public BufferedQuery(Counters parent, QueryTarget type)
|
||||
{
|
||||
_parent = parent;
|
||||
_buffer = GL.GenBuffer();
|
||||
Query = GL.GenQuery();
|
||||
_type = type;
|
||||
|
@ -42,20 +45,27 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
|
||||
public void Begin()
|
||||
{
|
||||
Marshal.WriteInt64(_bufferMap, -1L);
|
||||
GL.BeginQuery(_type, Query);
|
||||
}
|
||||
|
||||
public unsafe void End(bool withResult)
|
||||
public unsafe void CopyQueryResult()
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.QueryBuffer, _buffer);
|
||||
GL.GetQueryObject(Query, GetQueryObjectParam.QueryResult, (long*)0);
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.QueryBufferBarrierBit | MemoryBarrierFlags.ClientMappedBufferBarrierBit);
|
||||
}
|
||||
|
||||
public void End(bool withResult)
|
||||
{
|
||||
GL.EndQuery(_type);
|
||||
|
||||
if (withResult)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.QueryBuffer, _buffer);
|
||||
|
||||
Marshal.WriteInt64(_bufferMap, -1L);
|
||||
GL.GetQueryObject(Query, GetQueryObjectParam.QueryResult, (long*)0);
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.QueryBufferBarrierBit | MemoryBarrierFlags.ClientMappedBufferBarrierBit);
|
||||
if (!_parent.QueueCopy(this))
|
||||
{
|
||||
CopyQueryResult();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
public CounterType Type { get; }
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
private readonly Counters _parent;
|
||||
|
||||
private readonly Queue<CounterQueueEvent> _events = new();
|
||||
private CounterQueueEvent _current;
|
||||
|
||||
|
@ -28,8 +30,9 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
|
||||
private readonly Thread _consumerThread;
|
||||
|
||||
internal CounterQueue(CounterType type)
|
||||
internal CounterQueue(Counters parent, CounterType type)
|
||||
{
|
||||
_parent = parent;
|
||||
Type = type;
|
||||
|
||||
QueryTarget glType = GetTarget(Type);
|
||||
|
@ -37,7 +40,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
_queryPool = new Queue<BufferedQuery>(QueryPoolInitialSize);
|
||||
for (int i = 0; i < QueryPoolInitialSize; i++)
|
||||
{
|
||||
_queryPool.Enqueue(new BufferedQuery(glType));
|
||||
_queryPool.Enqueue(new BufferedQuery(parent, glType));
|
||||
}
|
||||
|
||||
_current = new CounterQueueEvent(this, glType, 0);
|
||||
|
@ -90,7 +93,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
}
|
||||
else
|
||||
{
|
||||
return new BufferedQuery(GetTarget(Type));
|
||||
return new BufferedQuery(_parent, GetTarget(Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,11 +137,11 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
return result;
|
||||
}
|
||||
|
||||
public void QueueReset()
|
||||
public void QueueReset(ulong lastDrawIndex)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_current.Clear();
|
||||
_current.Clear(lastDrawIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
public bool Disposed { get; private set; }
|
||||
public bool Invalid { get; set; }
|
||||
|
||||
public ulong DrawIndex { get; }
|
||||
public ulong DrawIndex { get; private set; }
|
||||
|
||||
private readonly CounterQueue _queue;
|
||||
private readonly BufferedQuery _counter;
|
||||
|
@ -40,10 +40,11 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
_counter.Begin();
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
internal void Clear(ulong drawIndex)
|
||||
{
|
||||
_counter.Reset();
|
||||
ClearCounter = true;
|
||||
DrawIndex = drawIndex;
|
||||
}
|
||||
|
||||
internal void Complete(bool withResult, double divisor)
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
{
|
||||
class Counters : IDisposable
|
||||
{
|
||||
private const int ForceCopyThreshold = 32;
|
||||
|
||||
private readonly CounterQueue[] _counterQueues;
|
||||
private readonly List<BufferedQuery> _queuedCopies;
|
||||
private bool _flushedThisPass;
|
||||
|
||||
public Counters()
|
||||
{
|
||||
int count = Enum.GetNames<CounterType>().Length;
|
||||
|
||||
_counterQueues = new CounterQueue[count];
|
||||
_queuedCopies = new List<BufferedQuery>();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
|
@ -19,7 +25,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
for (int index = 0; index < _counterQueues.Length; index++)
|
||||
{
|
||||
CounterType type = (CounterType)index;
|
||||
_counterQueues[index] = new CounterQueue(type);
|
||||
_counterQueues[index] = new CounterQueue(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,9 +34,9 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
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()
|
||||
|
@ -46,6 +52,41 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||
_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)
|
||||
{
|
||||
foreach (BufferedQuery query in _queuedCopies)
|
||||
{
|
||||
query.CopyQueryResult();
|
||||
}
|
||||
|
||||
_queuedCopies.Clear();
|
||||
}
|
||||
|
||||
if (newPass)
|
||||
{
|
||||
_flushedThisPass = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool QueueCopy(BufferedQuery query)
|
||||
{
|
||||
_queuedCopies.Add(query);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var queue in _counterQueues)
|
||||
|
|
Loading…
Reference in a new issue