1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-31 14:52:11 +01:00

[dxvk] Add option to clear mapped memory regions to zero

This commit is contained in:
Philip Rebohle 2024-10-27 00:43:12 +02:00 committed by Philip Rebohle
parent e9574a4155
commit ed83534970
5 changed files with 43 additions and 1 deletions

View File

@ -267,6 +267,15 @@
# d3d11.zeroWorkgroupMemory = False
# Clears mapped memory to zero when suballocated memory is freed. This will
# drastically increase CPU overhead and should only be used as a last resort
# if a game does not properly initialize mapped buffers on its own.
#
# Supported values: True, False
# dxvk.zeroMappedMemory = False
# Resource size limit for implicit discards, in kilobytes. For small staging
# resources mapped with MAP_WRITE, DXVK will sometimes allocate new backing
# storage in order to avoid GPU synchronization, so setting this too high

View File

@ -2,6 +2,8 @@
#include <iomanip>
#include <sstream>
#include "../util/util_bit.h"
#include "dxvk_device.h"
#include "dxvk_memory.h"
#include "dxvk_sparse.h"
@ -1254,9 +1256,17 @@ namespace dxvk {
allocation->m_address = address;
allocation->m_size = size;
if (chunk.memory.mapPtr)
if (chunk.memory.mapPtr) {
allocation->m_mapPtr = reinterpret_cast<char*>(chunk.memory.mapPtr) + offset;
if (unlikely(m_device->config().zeroMappedMemory)) {
// Some games will not write mapped buffers and will break if
// there is any stale data stored within. Clear when the allocation is
// freed, so that subsequent allocations will receive cleared buffers.
allocation->m_flags.set(DxvkAllocationFlag::ClearOnFree);
}
}
if (chunk.memory.buffer) {
allocation->m_buffer = chunk.memory.buffer;
allocation->m_bufferOffset = offset;
@ -1322,6 +1332,11 @@ namespace dxvk {
void DxvkMemoryAllocator::freeAllocation(
DxvkResourceAllocation* allocation) {
if (allocation->m_flags.test(DxvkAllocationFlag::ClearOnFree)) {
if (allocation->m_mapPtr)
bit::bclear(allocation->m_mapPtr, allocation->m_size);
}
if (allocation->m_flags.test(DxvkAllocationFlag::CanCache)) {
// Return cacheable allocations to the shared cache
allocation->destroyBufferViews();
@ -1523,6 +1538,9 @@ namespace dxvk {
"\n size: ", memory.size, " bytes"));
}
if (m_device->config().zeroMappedMemory)
bit::bclear(memory.mapPtr, memory.size);
Logger::debug(str::format("Mapped memory region 0x", std::hex,
reinterpret_cast<uintptr_t>(memory.mapPtr), " - 0x",
reinterpret_cast<uintptr_t>(memory.mapPtr) + memory.size - 1u));

View File

@ -465,12 +465,23 @@ namespace dxvk {
* \brief Resource allocation flags
*/
enum class DxvkAllocationFlag : uint32_t {
/// Allocation owns the given VkDeviceMemory allocation
/// and is not suballocated from an existing chunk.
OwnsMemory = 0,
/// Allocation owns a dedicated VkBuffer object rather
/// than the global buffer for the parent chunk, if any.
OwnsBuffer = 1,
/// Allocation owns a VkImage object.
OwnsImage = 2,
/// Allocation can use an allocation cache.
CanCache = 3,
/// Allocation can be relocated for defragmentation.
CanMove = 4,
/// Allocation is imported from an external API.
Imported = 5,
/// Memory must be cleared to zero when the allocation
/// is freed. Only used to work around app bugs.
ClearOnFree = 6,
};
using DxvkAllocationFlags = Flags<DxvkAllocationFlag>;

View File

@ -13,6 +13,7 @@ namespace dxvk {
hud = config.getOption<std::string>("dxvk.hud", "");
tearFree = config.getOption<Tristate>("dxvk.tearFree", Tristate::Auto);
hideIntegratedGraphics = config.getOption<bool> ("dxvk.hideIntegratedGraphics", false);
zeroMappedMemory = config.getOption<bool> ("dxvk.zeroMappedMemory", false);
deviceFilter = config.getOption<std::string>("dxvk.deviceFilter", "");
}

View File

@ -42,6 +42,9 @@ namespace dxvk {
// incorrectly assume monitor layouts.
bool hideIntegratedGraphics = false;
/// Clears all mapped memory to zero.
bool zeroMappedMemory = false;
// Device name
std::string deviceFilter;
};