1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-20 19:54:19 +01:00

[d3d11] Throttle resource uploads via UpdateSubresource

Otherwise, some games (e.g. Frostpunk, New World) end up allocating over
a gigabyte of staging memory.
This commit is contained in:
Philip Rebohle 2024-10-07 15:11:37 +02:00 committed by Philip Rebohle
parent ec18dd7846
commit df60a061a4
3 changed files with 40 additions and 3 deletions

View File

@ -3010,6 +3010,9 @@ namespace dxvk {
CopyTiledResourceData(pDestTiledResource,
pDestTileRegionStartCoordinate,
pDestTileRegionSize, slice, Flags);
if constexpr (!IsDeferred)
static_cast<ContextType*>(this)->ThrottleAllocation();
}
@ -5099,6 +5102,9 @@ namespace dxvk {
if (pDstBuffer->HasSequenceNumber())
GetTypedContext()->TrackBufferSequenceNumber(pDstBuffer);
if constexpr (!IsDeferred)
static_cast<ContextType*>(this)->ThrottleAllocation();
}
@ -5151,6 +5157,9 @@ namespace dxvk {
UpdateImage(pDstTexture, &subresource,
offset, extent, std::move(stagingSlice));
if constexpr (!IsDeferred)
static_cast<ContextType*>(this)->ThrottleAllocation();
}

View File

@ -20,6 +20,7 @@ namespace dxvk {
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
m_submissionFence(new sync::CallbackFence()),
m_flushTracker(pParent->GetOptions()->reproducibleCommandStream),
m_stagingBufferFence(new sync::Fence(0)),
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
m_videoContext(this, Device) {
EmitCs([
@ -956,9 +957,12 @@ namespace dxvk {
EmitCs<false>([
cSubmissionFence = m_submissionFence,
cSubmissionId = submissionId,
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr,
cStagingFence = m_stagingBufferFence,
cStagingMemory = m_staging.getStatistics().allocatedTotal
] (DxvkContext* ctx) {
ctx->signal(cSubmissionFence, cSubmissionId);
ctx->signal(cStagingFence, cStagingMemory);
ctx->flushCommandList(cSubmissionStatus);
});
@ -977,5 +981,25 @@ namespace dxvk {
// end up with a persistent allocation
ResetStagingBuffer();
}
void D3D11ImmediateContext::ThrottleAllocation() {
DxvkStagingBufferStats stats = m_staging.getStatistics();
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingBufferFence->value();
if (stagingMemoryInFlight > stats.allocatedSinceLastReset + D3D11Initializer::MaxMemoryInFlight) {
// Stall calling thread to avoid situation where we keep growing the staging
// buffer indefinitely, but ignore the newly allocated amount so that we don't
// wait for the GPU to go fully idle in case of a large allocation.
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
m_stagingBufferFence->wait(stats.allocatedTotal - stats.allocatedSinceLastReset - D3D11Initializer::MaxMemoryInFlight);
} else if (stats.allocatedSinceLastReset >= D3D11Initializer::MaxMemoryPerSubmission) {
// Flush somewhat aggressively if there's a lot of memory in flight
ExecuteFlush(GpuFlushType::ExplicitFlush, nullptr, false);
}
}
}

View File

@ -126,11 +126,13 @@ namespace dxvk {
uint64_t m_flushSeqNum = 0ull;
GpuFlushTracker m_flushTracker;
Rc<sync::Fence> m_stagingBufferFence;
D3D10Multithread m_multithread;
D3D11VideoContext m_videoContext;
Com<D3D11DeviceContextState, false> m_stateObject;
HRESULT MapBuffer(
D3D11Buffer* pResource,
D3D11_MAP MapType,
@ -195,6 +197,8 @@ namespace dxvk {
HANDLE hEvent,
BOOL Synchronize);
void ThrottleAllocation();
};
}