Skip to content

Commit

Permalink
[d3d11] Always use fast MAP_WRITE_DISCARD path on deferred contexts
Browse files Browse the repository at this point in the history
... but keep the SingleUse option as-is anyway because games do not release
their command lists after submission and end up wasting massive amounts of
memory.
  • Loading branch information
doitsujin committed Sep 26, 2024
1 parent 39f5099 commit 5e5c283
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 35 deletions.
8 changes: 5 additions & 3 deletions dxvk.conf
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,11 @@
# dxvk.tearFree = Auto


# Assume single-use mode for command lists created on deferred contexts.
# This may need to be disabled for some applications to avoid rendering
# issues, which may come at a significant performance cost.
# Assume that command lists created from deferred contexts are only used
# once. This is extremely common and may improve performance while reducing
# the amount of memory wasted if games keep their command list objects alive
# for too long, but may also lead to rendering issues if command lists are
# submitted multiple times.
#
# Supported values: True, False

Expand Down
44 changes: 12 additions & 32 deletions src/d3d11/d3d11_context_def.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,44 +265,24 @@ namespace dxvk {
ID3D11Resource* pResource,
D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
D3D11Buffer* pBuffer = static_cast<D3D11Buffer*>(pResource);

if (unlikely(pBuffer->GetMapMode() == D3D11_COMMON_BUFFER_MAP_MODE_NONE)) {
Logger::err("D3D11: Cannot map a device-local buffer");
return E_INVALIDARG;
}


auto bufferSlice = pBuffer->AllocSlice(&m_allocationCache);
pMappedResource->pData = bufferSlice->mapPtr();
pMappedResource->RowPitch = pBuffer->Desc()->ByteWidth;
pMappedResource->DepthPitch = pBuffer->Desc()->ByteWidth;

if (likely(m_csFlags.test(DxvkCsChunkFlag::SingleUse))) {
// For resources that cannot be written by the GPU,
// we may write to the buffer resource directly and
// just swap in the buffer slice as needed.
auto bufferSlice = pBuffer->AllocSlice(&m_allocationCache);
pMappedResource->pData = bufferSlice->mapPtr();

EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cDstSlice = std::move(bufferSlice)
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cDstBuffer, Rc<DxvkResourceAllocation>(cDstSlice));
});
} else {
// For GPU-writable resources, we need a data slice
// to perform the update operation at execution time.
auto dataSlice = AllocUpdateBufferSlice(pBuffer->Desc()->ByteWidth);
pMappedResource->pData = dataSlice.ptr();

EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cDataSlice = dataSlice
] (DxvkContext* ctx) {
Rc<DxvkResourceAllocation> slice = cDstBuffer->allocateSlice();
std::memcpy(slice->mapPtr(), cDataSlice.ptr(), cDataSlice.length());
ctx->invalidateBuffer(cDstBuffer, std::move(slice));
});
}


EmitCs([
cDstBuffer = pBuffer->GetBuffer(),
cDstSlice = std::move(bufferSlice)
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cDstBuffer, Rc<DxvkResourceAllocation>(cDstSlice));
});

return S_OK;
}

Expand Down

0 comments on commit 5e5c283

Please sign in to comment.