From b3f0978869c7b621bf1c62ea6a8fc51f1e3a5c24 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Thu, 9 Feb 2023 01:03:41 +0000 Subject: [PATCH] Vulkan: Flush command buffers for queries less aggressively (#4387) The AutoFlushCounter would flush command buffers on any attachment change (write mask or bindings change) if there was a pending query. This is to get query results as soon as possible for draw skips, but it's assuming that a full occlusion query _pass_ happened, that we want to flush it's data before getting onto draws, rather than the queries being randomly interspersed throughout a pass that also draws. Xenoblade 2 repeatedly switches between performing a samples passed query and outputting to a render target on each draw, and flips the write mask to do so. Flushing the command buffer every 2 draws isn't ideal, so it's best that we only do this if the pattern matches the large block style of occlusion query. This change makes this flush only happen after a few consecutive query reports. "Consecutive" is interrupted by attachment changes or command buffer flush. This doesn't really solve the issue where it resets more queries than it uses, it just stops the game doing it as often. I'm not sure of the best way to do that. The cost of resetting could probably be reduced by using query pools with more than one element and resetting in bulk. --- Ryujinx.Graphics.Vulkan/AutoFlushCounter.cs | 11 +++++++++-- Ryujinx.Graphics.Vulkan/PipelineFull.cs | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Ryujinx.Graphics.Vulkan/AutoFlushCounter.cs b/Ryujinx.Graphics.Vulkan/AutoFlushCounter.cs index 2a4cbd52..953316a6 100644 --- a/Ryujinx.Graphics.Vulkan/AutoFlushCounter.cs +++ b/Ryujinx.Graphics.Vulkan/AutoFlushCounter.cs @@ -10,11 +10,13 @@ namespace Ryujinx.Graphics.Vulkan private readonly static long FramebufferFlushTimer = Stopwatch.Frequency / 1000; private const int MinDrawCountForFlush = 10; + private const int MinConsecutiveQueryForFlush = 10; private const int InitialQueryCountForFlush = 32; private long _lastFlush; private ulong _lastDrawCount; private bool _hasPendingQuery; + private int _consecutiveQueries; private int _queryCount; private int[] _queryCountHistory = new int[3]; @@ -27,11 +29,13 @@ namespace Ryujinx.Graphics.Vulkan _lastDrawCount = drawCount; _hasPendingQuery = false; + _consecutiveQueries = 0; } public bool RegisterPendingQuery() { _hasPendingQuery = true; + _consecutiveQueries++; _remainingQueries--; _queryCountHistory[_queryCountHistoryIndex]++; @@ -65,15 +69,18 @@ namespace Ryujinx.Graphics.Vulkan return _hasPendingQuery; } - public bool ShouldFlush(ulong drawCount) + public bool ShouldFlushAttachmentChange(ulong drawCount) { _queryCount = 0; - if (_hasPendingQuery) + // Flush when there's an attachment change out of a large block of queries. + if (_consecutiveQueries > MinConsecutiveQueryForFlush) { return true; } + _consecutiveQueries = 0; + long draws = (long)(drawCount - _lastDrawCount); if (draws < MinDrawCountForFlush) diff --git a/Ryujinx.Graphics.Vulkan/PipelineFull.cs b/Ryujinx.Graphics.Vulkan/PipelineFull.cs index d8e8cdfb..6c026a07 100644 --- a/Ryujinx.Graphics.Vulkan/PipelineFull.cs +++ b/Ryujinx.Graphics.Vulkan/PipelineFull.cs @@ -281,7 +281,7 @@ namespace Ryujinx.Graphics.Vulkan protected override void SignalAttachmentChange() { - if (AutoFlush.ShouldFlush(DrawCount)) + if (AutoFlush.ShouldFlushAttachmentChange(DrawCount)) { FlushCommandsImpl(); }