[d3d9] Port flush heuristic from D3D11

This commit is contained in:
Philip Rebohle 2023-06-22 20:40:15 +02:00 committed by Joshie
parent 022bf1d134
commit ccb87d5ea9
3 changed files with 46 additions and 44 deletions

View File

@ -55,6 +55,7 @@ namespace dxvk {
, m_isSWVP ( (BehaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) ? true : false )
, m_csThread ( dxvkDevice, dxvkDevice->createContext(DxvkContextType::Primary) )
, m_csChunk ( AllocCsChunk() )
, m_submissionFence (new sync::Fence())
, m_d3d9Interop ( this )
, m_d3d9On12 ( this )
, m_d3d8Bridge ( this ) {
@ -1003,7 +1004,7 @@ namespace dxvk {
if (dstTexInfo->IsAutomaticMip() && mipLevels != dstTexInfo->Desc()->MipLevels)
MarkTextureMipsDirty(dstTexInfo);
FlushImplicit(false);
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
return D3D_OK;
}
@ -1450,7 +1451,9 @@ namespace dxvk {
return D3D_OK;
// Do a strong flush if the first render target is changed.
FlushImplicit(RenderTargetIndex == 0 ? TRUE : FALSE);
ConsiderFlush(RenderTargetIndex == 0
? GpuFlushType::ImplicitStrongHint
: GpuFlushType::ImplicitWeakHint);
m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
m_state.renderTargets[RenderTargetIndex] = rt;
@ -1529,7 +1532,7 @@ namespace dxvk {
if (m_state.depthStencil == ds)
return D3D_OK;
FlushImplicit(FALSE);
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
if (ds != nullptr && m_depthBiasRepresentation.depthBiasRepresentation != VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT) {
@ -1588,7 +1591,7 @@ namespace dxvk {
if (unlikely(!m_flags.test(D3D9DeviceFlag::InScene)))
return D3DERR_INVALIDCALL;
FlushImplicit(true);
ConsiderFlush(GpuFlushType::ImplicitStrongHint);
m_flags.clr(D3D9DeviceFlag::InScene);
@ -4377,7 +4380,7 @@ namespace dxvk {
// We don't have to wait, but misbehaving games may
// still try to spin on `Map` until the resource is
// idle, so we should flush pending commands
FlushImplicit(FALSE);
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
return false;
}
else {
@ -4890,7 +4893,7 @@ namespace dxvk {
slice.slice);
}
UnmapTextures();
FlushImplicit(false);
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
}
void D3D9DeviceEx::EmitGenerateMips(
@ -5049,7 +5052,7 @@ namespace dxvk {
TrackBufferMappingBufferSequenceNumber(pResource);
UnmapTextures();
FlushImplicit(false);
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
return D3D_OK;
}
@ -5080,25 +5083,15 @@ namespace dxvk {
void D3D9DeviceEx::EmitCsChunk(DxvkCsChunkRef&& chunk) {
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
m_csIsBusy = true;
}
void D3D9DeviceEx::FlushImplicit(BOOL StrongHint) {
// Flush only if the GPU is about to go idle, in
// order to keep the number of submissions low.
uint32_t pending = m_dxvkDevice->pendingSubmissions();
void D3D9DeviceEx::ConsiderFlush(GpuFlushType FlushType) {
uint64_t chunkId = GetCurrentSequenceNumber();
uint64_t submissionId = m_submissionFence->value();
if (StrongHint || pending <= MaxPendingSubmits) {
auto now = dxvk::high_resolution_clock::now();
uint32_t delay = MinFlushIntervalUs
+ IncFlushIntervalUs * pending;
// Prevent flushing too often in short intervals.
if (now - m_lastFlush >= std::chrono::microseconds(delay))
Flush();
}
if (m_flushTracker.considerFlush(FlushType, chunkId, submissionId))
Flush();
}
@ -5458,28 +5451,31 @@ namespace dxvk {
m_initializer->Flush();
m_converter->Flush();
if (m_csIsBusy || !m_csChunk->empty()) {
EmitStagingBufferMarker();
EmitStagingBufferMarker();
// Add commands to flush the threaded
// context, then flush the command list
EmitCs([](DxvkContext* ctx) {
ctx->flushCommandList(nullptr);
});
// Add commands to flush the threaded
// context, then flush the command list
uint64_t submissionId = ++m_submissionId;
FlushCsChunk();
EmitCs<false>([
cSubmissionFence = m_submissionFence,
cSubmissionId = submissionId
] (DxvkContext* ctx) {
ctx->signal(cSubmissionFence, cSubmissionId);
ctx->flushCommandList(nullptr);
});
// Reset flush timer used for implicit flushes
m_lastFlush = dxvk::high_resolution_clock::now();
m_csIsBusy = false;
}
FlushCsChunk();
m_flushSeqNum = m_csSeqNum;
m_flushTracker.notifyFlush(m_flushSeqNum, submissionId);
}
void D3D9DeviceEx::EndFrame() {
D3D9DeviceLock lock = LockDevice();
EmitCs([] (DxvkContext* ctx) {
EmitCs<false>([] (DxvkContext* ctx) {
ctx->endFrame();
});
}
@ -6789,9 +6785,9 @@ namespace dxvk {
if (unlikely(pQuery->IsEvent())) {
pQuery->IsStalling()
? Flush()
: FlushImplicit(TRUE);
: ConsiderFlush(GpuFlushType::ImplicitStrongHint);
} else if (pQuery->IsStalling()) {
FlushImplicit(FALSE);
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
}
}

View File

@ -38,6 +38,7 @@
#include <type_traits>
#include <unordered_map>
#include "../util/util_flush.h"
#include "../util/util_lru.h"
namespace dxvk {
@ -927,7 +928,7 @@ namespace dxvk {
void SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits);
void SetPixelBoolBitfield (uint32_t idx, uint32_t mask, uint32_t bits);
void FlushImplicit(BOOL StrongHint);
void ConsiderFlush(GpuFlushType FlushType);
bool ChangeReportedMemory(int64_t delta) {
if (IsExtended())
@ -995,12 +996,15 @@ namespace dxvk {
return DxvkCsChunkRef(chunk, &m_csChunkPool);
}
template<typename Cmd>
template<bool AllowFlush = true, typename Cmd>
void EmitCs(Cmd&& command) {
if (unlikely(!m_csChunk->push(command))) {
EmitCsChunk(std::move(m_csChunk));
m_csChunk = AllocCsChunk();
if constexpr (AllowFlush)
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
m_csChunk->push(command);
}
}
@ -1343,12 +1347,14 @@ namespace dxvk {
D3D9ViewportInfo m_viewportInfo;
DxvkCsChunkPool m_csChunkPool;
dxvk::high_resolution_clock::time_point m_lastFlush
= dxvk::high_resolution_clock::now();
DxvkCsThread m_csThread;
DxvkCsChunkRef m_csChunk;
uint64_t m_csSeqNum = 0ull;
bool m_csIsBusy = false;
Rc<sync::Fence> m_submissionFence;
uint64_t m_submissionId = 0ull;
uint64_t m_flushSeqNum = 0ull;
GpuFlushTracker m_flushTracker;
std::atomic<int64_t> m_availableMemory = { 0 };
std::atomic<int32_t> m_samplerCount = { 0 };

View File

@ -160,7 +160,7 @@ namespace dxvk {
// they didn't call end, do some flushy stuff...
if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
this->NotifyStall();
m_parent->FlushImplicit(FALSE);
m_parent->ConsiderFlush(GpuFlushType::ImplicitSynchronization);
}
return hr;