|
|
@@ -1,4 +1,5 @@
|
|
|
-using System;
|
|
|
+using Ryujinx.Common.Logging;
|
|
|
+using System;
|
|
|
using System.Diagnostics;
|
|
|
using System.Linq;
|
|
|
|
|
|
@@ -7,12 +8,26 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
internal class AutoFlushCounter
|
|
|
{
|
|
|
// How often to flush on framebuffer change.
|
|
|
- private readonly static long FramebufferFlushTimer = Stopwatch.Frequency / 1000;
|
|
|
+ private readonly static long FramebufferFlushTimer = Stopwatch.Frequency / 1000; // (1ms)
|
|
|
+
|
|
|
+ // How often to flush on draw when fast flush mode is enabled.
|
|
|
+ private readonly static long DrawFlushTimer = Stopwatch.Frequency / 666; // (1.5ms)
|
|
|
+
|
|
|
+ // Average wait time that triggers fast flush mode to be entered.
|
|
|
+ private readonly static long FastFlushEnterThreshold = Stopwatch.Frequency / 666; // (1.5ms)
|
|
|
+
|
|
|
+ // Average wait time that triggers fast flush mode to be exited.
|
|
|
+ private readonly static long FastFlushExitThreshold = Stopwatch.Frequency / 10000; // (0.1ms)
|
|
|
+
|
|
|
+ // Number of frames to average waiting times over.
|
|
|
+ private const int SyncWaitAverageCount = 20;
|
|
|
|
|
|
private const int MinDrawCountForFlush = 10;
|
|
|
private const int MinConsecutiveQueryForFlush = 10;
|
|
|
private const int InitialQueryCountForFlush = 32;
|
|
|
|
|
|
+ private readonly VulkanRenderer _gd;
|
|
|
+
|
|
|
private long _lastFlush;
|
|
|
private ulong _lastDrawCount;
|
|
|
private bool _hasPendingQuery;
|
|
|
@@ -23,6 +38,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
private int _queryCountHistoryIndex;
|
|
|
private int _remainingQueries;
|
|
|
|
|
|
+ private long[] _syncWaitHistory = new long[SyncWaitAverageCount];
|
|
|
+ private int _syncWaitHistoryIndex;
|
|
|
+
|
|
|
+ private bool _fastFlushMode;
|
|
|
+
|
|
|
+ public AutoFlushCounter(VulkanRenderer gd)
|
|
|
+ {
|
|
|
+ _gd = gd;
|
|
|
+ }
|
|
|
+
|
|
|
public void RegisterFlush(ulong drawCount)
|
|
|
{
|
|
|
_lastFlush = Stopwatch.GetTimestamp();
|
|
|
@@ -69,6 +94,32 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
return _hasPendingQuery;
|
|
|
}
|
|
|
|
|
|
+ public bool ShouldFlushDraw(ulong drawCount)
|
|
|
+ {
|
|
|
+ if (_fastFlushMode)
|
|
|
+ {
|
|
|
+ long draws = (long)(drawCount - _lastDrawCount);
|
|
|
+
|
|
|
+ if (draws < MinDrawCountForFlush)
|
|
|
+ {
|
|
|
+ if (draws == 0)
|
|
|
+ {
|
|
|
+ _lastFlush = Stopwatch.GetTimestamp();
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ long flushTimeout = DrawFlushTimer;
|
|
|
+
|
|
|
+ long now = Stopwatch.GetTimestamp();
|
|
|
+
|
|
|
+ return now > _lastFlush + flushTimeout;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
public bool ShouldFlushAttachmentChange(ulong drawCount)
|
|
|
{
|
|
|
_queryCount = 0;
|
|
|
@@ -102,11 +153,27 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
|
|
|
public void Present()
|
|
|
{
|
|
|
+ // Query flush prediction.
|
|
|
+
|
|
|
_queryCountHistoryIndex = (_queryCountHistoryIndex + 1) % 3;
|
|
|
|
|
|
_remainingQueries = _queryCountHistory.Max() + 10;
|
|
|
|
|
|
_queryCountHistory[_queryCountHistoryIndex] = 0;
|
|
|
+
|
|
|
+ // Fast flush mode toggle.
|
|
|
+
|
|
|
+ _syncWaitHistory[_syncWaitHistoryIndex] = _gd.SyncManager.GetAndResetWaitTicks();
|
|
|
+
|
|
|
+ _syncWaitHistoryIndex = (_syncWaitHistoryIndex + 1) % SyncWaitAverageCount;
|
|
|
+
|
|
|
+ long averageWait = (long)_syncWaitHistory.Average();
|
|
|
+
|
|
|
+ if (_fastFlushMode ? averageWait < FastFlushExitThreshold : averageWait > FastFlushEnterThreshold)
|
|
|
+ {
|
|
|
+ _fastFlushMode = !_fastFlushMode;
|
|
|
+ Logger.Debug?.PrintMsg(LogClass.Gpu, $"Switched fast flush mode: ({_fastFlushMode})");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|