1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-21 02:52:10 +01:00
dxvk/src/util/util_flush.cpp
Danylo Piliaiev 58d8ea2d31 [d3d11,d3d9,util] Add a config option for reproducible VK output
It ensures that for the same D3D commands the output VK commands
don't change between runs.

Useful for comparative benchmarking, can negatively affect performance.

Signed-off-by: Danylo Piliaiev <dpiliaiev@igalia.com>
2024-05-23 15:20:28 +02:00

89 lines
2.9 KiB
C++

#include "util_flush.h"
namespace dxvk {
GpuFlushTracker::GpuFlushTracker(
bool ensureReproducibleHeuristic)
: m_ensureReproducibleHeuristic(ensureReproducibleHeuristic) {
}
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;
if (m_ensureReproducibleHeuristic && flushType != GpuFlushType::ExplicitFlush)
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;
}
}