From 14b23952902f732b91cf1c0887aa109e19196535 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Wed, 14 Feb 2024 22:27:21 +0000 Subject: [PATCH] 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. --- src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs | 5 +- src/Ryujinx.Graphics.OpenGL/Pipeline.cs | 13 ++++- .../Queries/BufferedQuery.cs | 24 +++++++--- .../Queries/CounterQueue.cs | 13 +++-- .../Queries/CounterQueueEvent.cs | 5 +- .../Queries/Counters.cs | 47 +++++++++++++++++-- 6 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs index eabcb3c10..1dd08ff6a 100644 --- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs @@ -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); } diff --git a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs index 0757fcd99..a31a0ad12 100644 --- a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -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. } diff --git a/src/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs b/src/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs index 0a85970d7..d9add25cd 100644 --- a/src/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs +++ b/src/Ryujinx.Graphics.OpenGL/Queries/BufferedQuery.cs @@ -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 { diff --git a/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs b/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs index 345a99ffa..2f36840f0 100644 --- a/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs +++ b/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueue.cs @@ -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 _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(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); } } diff --git a/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs b/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs index 32b75c615..a67d868e8 100644 --- a/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs +++ b/src/Ryujinx.Graphics.OpenGL/Queries/CounterQueueEvent.cs @@ -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) diff --git a/src/Ryujinx.Graphics.OpenGL/Queries/Counters.cs b/src/Ryujinx.Graphics.OpenGL/Queries/Counters.cs index 1530c9d26..de8fb1142 100644 --- a/src/Ryujinx.Graphics.OpenGL/Queries/Counters.cs +++ b/src/Ryujinx.Graphics.OpenGL/Queries/Counters.cs @@ -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 _queuedCopies; + private bool _flushedThisPass; public Counters() { int count = Enum.GetNames().Length; _counterQueues = new CounterQueue[count]; + _queuedCopies = new List(); } 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)