mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-01 08:52:11 +01:00
[dxvk] Adjust chunk size logic for mapped memory types
Total War Warhammer III discards a 48MB image every frame, so hitting the dedicated allocation path pretty much at random leads to issues.
This commit is contained in:
parent
ff78112271
commit
3c389ae06b
@ -661,16 +661,31 @@ namespace dxvk {
|
||||
// If the allocation is very large, use a dedicated allocation instead
|
||||
// of creating a new chunk. This way we avoid excessive fragmentation,
|
||||
// especially when a multiple such resources are created at once.
|
||||
uint32_t minResourcesPerChunk = (allocationInfo.properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? 1u : 4u;
|
||||
VkDeviceSize maxChunkSize = selectedPool.maxChunkSize;
|
||||
uint32_t minResourcesPerChunk = 4u;
|
||||
|
||||
// If we're on a mapped memory type and we're about to lose an entire chunk
|
||||
// worth of memory to huge resources causing fragmentation, use dedicated
|
||||
// allocations anyway and hope that the app doesn't do this every frame.
|
||||
if (minResourcesPerChunk == 1u && size > selectedPool.maxChunkSize / 2u
|
||||
&& type.stats.memoryAllocated - type.stats.memoryUsed + selectedPool.maxChunkSize - size >= selectedPool.maxChunkSize)
|
||||
minResourcesPerChunk = 2u;
|
||||
if (allocationInfo.properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
|
||||
if (allocationInfo.properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
|
||||
// For HVV allocations, it may be beneficial to ignore the chunk size
|
||||
// limit if the resource is large. HVV is usually slow to allocate
|
||||
// from and may be very limited in size, so we should avoid dedicated
|
||||
// allocations as well as fragmentation as much as possible.
|
||||
maxChunkSize = DxvkPageAllocator::MaxChunkSize / (env::is32BitHostPlatform() ? 4u : 1u);
|
||||
maxChunkSize = std::min(maxChunkSize, type.heap->properties.size / MinAllocationsPerHeap);
|
||||
maxChunkSize = std::max(maxChunkSize, selectedPool.maxChunkSize);
|
||||
|
||||
if (size * minResourcesPerChunk > selectedPool.maxChunkSize) {
|
||||
// Unlike on system memory heaps, we want to try and fit in multiple
|
||||
// allocations into one chunk because these tend to get discarded often.
|
||||
minResourcesPerChunk = std::clamp(uint32_t(maxChunkSize / size), 1u, 3u);
|
||||
} else {
|
||||
// System memory allocations tend to be more volatile, just be lenient
|
||||
// here and allow a single resource to fill an entire chunk. We will
|
||||
// generally keep multiple chunks of these types around anyway.
|
||||
minResourcesPerChunk = 1u;
|
||||
}
|
||||
}
|
||||
|
||||
if (size * minResourcesPerChunk > maxChunkSize) {
|
||||
DxvkDeviceMemory memory = allocateDeviceMemory(type, requirements.size, nullptr);
|
||||
|
||||
if (!memory.memory)
|
||||
@ -1686,7 +1701,7 @@ namespace dxvk {
|
||||
|
||||
// Ensure that we can at least do 7 allocations to fill
|
||||
// the heap. Might be useful on systems with small BAR.
|
||||
while (7u * size > type.heap->properties.size)
|
||||
while (MinAllocationsPerHeap * size > type.heap->properties.size)
|
||||
size /= 2u;
|
||||
|
||||
// Always use at least the minimum chunk size
|
||||
|
@ -1077,6 +1077,9 @@ namespace dxvk {
|
||||
// Assume an alignment of 256 bytes. This is enough to satisfy all
|
||||
// buffer use cases, and matches our minimum allocation size.
|
||||
constexpr static VkDeviceSize GlobalBufferAlignment = 256u;
|
||||
|
||||
// Minimum number of allocations we want to be able to fit into a heap
|
||||
constexpr static uint32_t MinAllocationsPerHeap = 7u;
|
||||
public:
|
||||
|
||||
DxvkMemoryAllocator(DxvkDevice* device);
|
||||
|
Loading…
x
Reference in New Issue
Block a user