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

View File

@ -38,6 +38,7 @@
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include "../util/util_flush.h"
#include "../util/util_lru.h" #include "../util/util_lru.h"
namespace dxvk { namespace dxvk {
@ -927,7 +928,7 @@ namespace dxvk {
void SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits); void SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits);
void SetPixelBoolBitfield (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) { bool ChangeReportedMemory(int64_t delta) {
if (IsExtended()) if (IsExtended())
@ -995,12 +996,15 @@ namespace dxvk {
return DxvkCsChunkRef(chunk, &m_csChunkPool); return DxvkCsChunkRef(chunk, &m_csChunkPool);
} }
template<typename Cmd> template<bool AllowFlush = true, typename Cmd>
void EmitCs(Cmd&& command) { void EmitCs(Cmd&& command) {
if (unlikely(!m_csChunk->push(command))) { if (unlikely(!m_csChunk->push(command))) {
EmitCsChunk(std::move(m_csChunk)); EmitCsChunk(std::move(m_csChunk));
m_csChunk = AllocCsChunk(); m_csChunk = AllocCsChunk();
if constexpr (AllowFlush)
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
m_csChunk->push(command); m_csChunk->push(command);
} }
} }
@ -1343,12 +1347,14 @@ namespace dxvk {
D3D9ViewportInfo m_viewportInfo; D3D9ViewportInfo m_viewportInfo;
DxvkCsChunkPool m_csChunkPool; DxvkCsChunkPool m_csChunkPool;
dxvk::high_resolution_clock::time_point m_lastFlush
= dxvk::high_resolution_clock::now();
DxvkCsThread m_csThread; DxvkCsThread m_csThread;
DxvkCsChunkRef m_csChunk; DxvkCsChunkRef m_csChunk;
uint64_t m_csSeqNum = 0ull; 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<int64_t> m_availableMemory = { 0 };
std::atomic<int32_t> m_samplerCount = { 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... // they didn't call end, do some flushy stuff...
if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) { if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
this->NotifyStall(); this->NotifyStall();
m_parent->FlushImplicit(FALSE); m_parent->ConsiderFlush(GpuFlushType::ImplicitSynchronization);
} }
return hr; return hr;