1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-04 16:24:29 +01:00

[util] Add helper class for common flush heuristic

This commit is contained in:
Philip Rebohle 2023-01-14 16:51:41 +01:00 committed by Philip Rebohle
parent 741cc493c6
commit 0ac247c89c
3 changed files with 151 additions and 0 deletions

View File

@ -2,6 +2,7 @@ util_src = files([
'util_env.cpp',
'util_string.cpp',
'util_fps_limiter.cpp',
'util_flush.cpp',
'util_gdi.cpp',
'util_luid.cpp',
'util_matrix.cpp',

79
src/util/util_flush.cpp Normal file
View File

@ -0,0 +1,79 @@
#include "util_flush.h"
namespace dxvk {
bool GpuFlushTracker::considerFlush(
GpuFlushType flushType,
uint64_t chunkId,
uint32_t lastCompleteSubmissionId) {
constexpr uint32_t minPendingSubmissions = 2;
constexpr uint32_t minChunkCount = 3u;
constexpr uint32_t maxChunkCount = 20u;
// Do not flush if there is nothing to flush
uint32_t chunkCount = uint32_t(chunkId - m_lastFlushChunkId);
if (!chunkCount)
return false;
// Take any earlier missed flush with a stronger hint into account, so
// that we still flush those as soon as possible. Ignore synchronization
// commands since they will either perform a flush or not need it at all.
flushType = std::min(flushType, m_lastMissedType);
if (flushType != GpuFlushType::ImplicitSynchronization)
m_lastMissedType = flushType;
switch (flushType) {
case GpuFlushType::ExplicitFlush: {
// This shouldn't really be called for explicit flushes,
// but handle them anyway for the sake of completeness
return true;
}
case GpuFlushType::ImplicitStrongHint: {
// Flush aggressively with a strong hint to reduce readback latency.
return chunkCount >= minChunkCount;
}
case GpuFlushType::ImplicitWeakHint: {
// Aim for a higher number of chunks per submission with
// a weak hint in order to avoid submitting too often.
if (chunkCount < 2 * minChunkCount)
return false;
// Actual heuristic is shared with synchronization commands
} [[fallthrough]];
case GpuFlushType::ImplicitSynchronization: {
// If the GPU is about to go idle, flush aggressively. This may be
// required if the application is spinning on a query or resource.
uint32_t pendingSubmissions = uint32_t(m_lastFlushSubmissionId - lastCompleteSubmissionId);
if (pendingSubmissions < minPendingSubmissions)
return true;
// Use the number of pending submissions to decide whether to flush. Other
// than ignoring the minimum chunk count condition, we should treat this
// the same as weak hints to avoid unnecessary synchronization.
uint32_t threshold = std::min(maxChunkCount, pendingSubmissions * minChunkCount);
return chunkCount >= threshold;
}
}
// Should be unreachable
return false;
}
void GpuFlushTracker::notifyFlush(
uint64_t chunkId,
uint64_t submissionId) {
m_lastMissedType = GpuFlushType::ImplicitWeakHint;
m_lastFlushChunkId = chunkId;
m_lastFlushSubmissionId = submissionId;
}
}

71
src/util/util_flush.h Normal file
View File

@ -0,0 +1,71 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <vector>
namespace dxvk {
/**
* \brief GPU context flush type
*/
enum class GpuFlushType : uint32_t {
/** Flush or Present called by application */
ExplicitFlush = 0,
/** Function that requires GPU synchronization and
* may require a flush called by application */
ImplicitSynchronization = 1,
/** GPU command that applications are likely to synchronize
* with soon has been recorded into the command list */
ImplicitStrongHint = 2,
/** GPU commands have been recorded and a flush should be
* performed if the current command list is large enough. */
ImplicitWeakHint = 3,
};
/**
* \brief GPU flush tracker
*
* Helper class that implements a context flush
* heuristic for various scenarios.
*/
class GpuFlushTracker {
public:
/**
* \brief Checks whether a context flush should be performed
*
* Note that this modifies internal state, and depending on the
* flush type, this may influence the decision for future flushes.
* \param [in] flushType Flush type
* \param [in] chunkId GPU command sequence number
* \param [in] lastCompleteSubmissionId Last completed command submission ID
* \returns \c true if a flush should be performed
*/
bool considerFlush(
GpuFlushType flushType,
uint64_t chunkId,
uint32_t lastCompleteSubmissionId);
/**
* \brief Notifies tracker about a context flush
*
* \param [in] chunkId GPU command sequence number
* \param [in] submissionId Command submission ID
*/
void notifyFlush(
uint64_t chunkId,
uint64_t submissionId);
private:
GpuFlushType m_lastMissedType = GpuFlushType::ImplicitWeakHint;
uint64_t m_lastFlushChunkId = 0ull;
uint64_t m_lastFlushSubmissionId = 0ull;
};
}