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:
parent
741cc493c6
commit
0ac247c89c
@ -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
79
src/util/util_flush.cpp
Normal 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
71
src/util/util_flush.h
Normal 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user