Compare commits
9 commits
d11c191ee5
...
004aeaba70
Author | SHA1 | Date | |
---|---|---|---|
|
004aeaba70 | ||
|
6ce49a2dc7 | ||
|
ccd330ba0f | ||
|
a46b1bd88c | ||
|
1a85c9a00b | ||
|
71901a54b8 | ||
|
711360f775 | ||
|
0aa6b31b39 | ||
|
14b2395290 |
22 changed files with 193 additions and 93 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -667,8 +667,36 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
if (PrepareOutputBuffer(cbs, hostSize, buffer, out VkBuffer copyToBuffer, out BufferHolder tempCopyHolder))
|
if (PrepareOutputBuffer(cbs, hostSize, buffer, out VkBuffer copyToBuffer, out BufferHolder tempCopyHolder))
|
||||||
{
|
{
|
||||||
|
// No barrier necessary, as this is a temporary copy buffer.
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BufferHolder.InsertBufferBarrier(
|
||||||
|
_gd,
|
||||||
|
cbs.CommandBuffer,
|
||||||
|
copyToBuffer,
|
||||||
|
BufferHolder.DefaultAccessFlags,
|
||||||
|
AccessFlags.TransferWriteBit,
|
||||||
|
PipelineStageFlags.AllCommandsBit,
|
||||||
|
PipelineStageFlags.TransferBit,
|
||||||
|
offset,
|
||||||
|
outSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertImageBarrier(
|
||||||
|
_gd.Api,
|
||||||
|
cbs.CommandBuffer,
|
||||||
|
image,
|
||||||
|
TextureStorage.DefaultAccessMask,
|
||||||
|
AccessFlags.TransferReadBit,
|
||||||
|
PipelineStageFlags.AllCommandsBit,
|
||||||
|
PipelineStageFlags.TransferBit,
|
||||||
|
Info.Format.ConvertAspectFlags(),
|
||||||
|
FirstLayer + layer,
|
||||||
|
FirstLevel + level,
|
||||||
|
1,
|
||||||
|
1);
|
||||||
|
|
||||||
CopyFromOrToBuffer(cbs.CommandBuffer, copyToBuffer, image, hostSize, true, layer, level, 1, 1, singleSlice: true, offset, stride);
|
CopyFromOrToBuffer(cbs.CommandBuffer, copyToBuffer, image, hostSize, true, layer, level, 1, 1, singleSlice: true, offset, stride);
|
||||||
|
|
||||||
|
@ -677,6 +705,19 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
CopyDataToOutputBuffer(cbs, tempCopyHolder, autoBuffer, hostSize, range.Offset);
|
CopyDataToOutputBuffer(cbs, tempCopyHolder, autoBuffer, hostSize, range.Offset);
|
||||||
tempCopyHolder.Dispose();
|
tempCopyHolder.Dispose();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BufferHolder.InsertBufferBarrier(
|
||||||
|
_gd,
|
||||||
|
cbs.CommandBuffer,
|
||||||
|
copyToBuffer,
|
||||||
|
AccessFlags.TransferWriteBit,
|
||||||
|
BufferHolder.DefaultAccessFlags,
|
||||||
|
PipelineStageFlags.TransferBit,
|
||||||
|
PipelineStageFlags.AllCommandsBit,
|
||||||
|
offset,
|
||||||
|
outSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer)
|
private ReadOnlySpan<byte> GetData(CommandBufferPool cbp, PersistentFlushBuffer flushBuffer)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
using LibHac.Ns;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Models
|
namespace Ryujinx.Ava.UI.Models
|
||||||
{
|
{
|
||||||
public class TitleUpdateModel
|
public class TitleUpdateModel
|
||||||
{
|
{
|
||||||
public ApplicationControlProperty Control { get; }
|
public uint Version { get; }
|
||||||
public string Path { get; }
|
public string Path { get; }
|
||||||
|
public string Label { get; }
|
||||||
|
|
||||||
public string Label => LocaleManager.Instance.UpdateAndGetDynamicValue(
|
public TitleUpdateModel(uint version, string displayVersion, string path)
|
||||||
System.IO.Path.GetExtension(Path)?.ToLower() == ".xci" ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel,
|
|
||||||
Control.DisplayVersionString.ToString()
|
|
||||||
);
|
|
||||||
|
|
||||||
public TitleUpdateModel(ApplicationControlProperty control, string path)
|
|
||||||
{
|
{
|
||||||
Control = control;
|
Version = version;
|
||||||
|
Label = LocaleManager.Instance.UpdateAndGetDynamicValue(
|
||||||
|
System.IO.Path.GetExtension(path)?.ToLower() == ".xci" ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel,
|
||||||
|
displayVersion
|
||||||
|
);
|
||||||
Path = path;
|
Path = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,26 +131,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
public void SortUpdates()
|
public void SortUpdates()
|
||||||
{
|
{
|
||||||
var list = TitleUpdates.ToList();
|
var sortedUpdates = TitleUpdates.OrderByDescending(update => update.Version);
|
||||||
|
|
||||||
list.Sort((first, second) =>
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
Views.Clear();
|
Views.Clear();
|
||||||
Views.Add(new BaseModel());
|
Views.Add(new BaseModel());
|
||||||
Views.AddRange(list);
|
Views.AddRange(sortedUpdates);
|
||||||
|
|
||||||
if (SelectedUpdate == null)
|
if (SelectedUpdate == null)
|
||||||
{
|
{
|
||||||
|
@ -204,7 +189,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||||
|
|
||||||
var update = new TitleUpdateModel(controlData, path);
|
var displayVersion = controlData.DisplayVersionString.ToString();
|
||||||
|
var update = new TitleUpdateModel(content.Version.Version, displayVersion, path);
|
||||||
|
|
||||||
TitleUpdates.Add(update);
|
TitleUpdates.Add(update);
|
||||||
|
|
||||||
if (selected)
|
if (selected)
|
||||||
|
|
Loading…
Add table
Reference in a new issue