mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-21 22:54:16 +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:
parent
ec18dd7846
commit
df60a061a4
@ -3010,6 +3010,9 @@ namespace dxvk {
|
|||||||
CopyTiledResourceData(pDestTiledResource,
|
CopyTiledResourceData(pDestTiledResource,
|
||||||
pDestTileRegionStartCoordinate,
|
pDestTileRegionStartCoordinate,
|
||||||
pDestTileRegionSize, slice, Flags);
|
pDestTileRegionSize, slice, Flags);
|
||||||
|
|
||||||
|
if constexpr (!IsDeferred)
|
||||||
|
static_cast<ContextType*>(this)->ThrottleAllocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -5099,6 +5102,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
if (pDstBuffer->HasSequenceNumber())
|
if (pDstBuffer->HasSequenceNumber())
|
||||||
GetTypedContext()->TrackBufferSequenceNumber(pDstBuffer);
|
GetTypedContext()->TrackBufferSequenceNumber(pDstBuffer);
|
||||||
|
|
||||||
|
if constexpr (!IsDeferred)
|
||||||
|
static_cast<ContextType*>(this)->ThrottleAllocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -5151,6 +5157,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
UpdateImage(pDstTexture, &subresource,
|
UpdateImage(pDstTexture, &subresource,
|
||||||
offset, extent, std::move(stagingSlice));
|
offset, extent, std::move(stagingSlice));
|
||||||
|
|
||||||
|
if constexpr (!IsDeferred)
|
||||||
|
static_cast<ContextType*>(this)->ThrottleAllocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ namespace dxvk {
|
|||||||
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
|
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
|
||||||
m_submissionFence(new sync::CallbackFence()),
|
m_submissionFence(new sync::CallbackFence()),
|
||||||
m_flushTracker(pParent->GetOptions()->reproducibleCommandStream),
|
m_flushTracker(pParent->GetOptions()->reproducibleCommandStream),
|
||||||
|
m_stagingBufferFence(new sync::Fence(0)),
|
||||||
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
|
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
|
||||||
m_videoContext(this, Device) {
|
m_videoContext(this, Device) {
|
||||||
EmitCs([
|
EmitCs([
|
||||||
@ -956,9 +957,12 @@ namespace dxvk {
|
|||||||
EmitCs<false>([
|
EmitCs<false>([
|
||||||
cSubmissionFence = m_submissionFence,
|
cSubmissionFence = m_submissionFence,
|
||||||
cSubmissionId = submissionId,
|
cSubmissionId = submissionId,
|
||||||
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr
|
cSubmissionStatus = synchronizeSubmission ? &m_submitStatus : nullptr,
|
||||||
|
cStagingFence = m_stagingBufferFence,
|
||||||
|
cStagingMemory = m_staging.getStatistics().allocatedTotal
|
||||||
] (DxvkContext* ctx) {
|
] (DxvkContext* ctx) {
|
||||||
ctx->signal(cSubmissionFence, cSubmissionId);
|
ctx->signal(cSubmissionFence, cSubmissionId);
|
||||||
|
ctx->signal(cStagingFence, cStagingMemory);
|
||||||
ctx->flushCommandList(cSubmissionStatus);
|
ctx->flushCommandList(cSubmissionStatus);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -977,5 +981,25 @@ namespace dxvk {
|
|||||||
// end up with a persistent allocation
|
// end up with a persistent allocation
|
||||||
ResetStagingBuffer();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -126,11 +126,13 @@ namespace dxvk {
|
|||||||
uint64_t m_flushSeqNum = 0ull;
|
uint64_t m_flushSeqNum = 0ull;
|
||||||
GpuFlushTracker m_flushTracker;
|
GpuFlushTracker m_flushTracker;
|
||||||
|
|
||||||
|
Rc<sync::Fence> m_stagingBufferFence;
|
||||||
|
|
||||||
D3D10Multithread m_multithread;
|
D3D10Multithread m_multithread;
|
||||||
D3D11VideoContext m_videoContext;
|
D3D11VideoContext m_videoContext;
|
||||||
|
|
||||||
Com<D3D11DeviceContextState, false> m_stateObject;
|
Com<D3D11DeviceContextState, false> m_stateObject;
|
||||||
|
|
||||||
HRESULT MapBuffer(
|
HRESULT MapBuffer(
|
||||||
D3D11Buffer* pResource,
|
D3D11Buffer* pResource,
|
||||||
D3D11_MAP MapType,
|
D3D11_MAP MapType,
|
||||||
@ -195,6 +197,8 @@ namespace dxvk {
|
|||||||
HANDLE hEvent,
|
HANDLE hEvent,
|
||||||
BOOL Synchronize);
|
BOOL Synchronize);
|
||||||
|
|
||||||
|
void ThrottleAllocation();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user