mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-03 13:24:20 +01:00
[dxvk] Implement dynamically growing chunk size
May reduce memory footprint for launchers.
This commit is contained in:
parent
63506ee1ff
commit
619b9b12c2
@ -183,8 +183,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxvkMemoryAllocator::DxvkMemoryAllocator(DxvkDevice* device)
|
DxvkMemoryAllocator::DxvkMemoryAllocator(DxvkDevice* device)
|
||||||
: m_device (device),
|
: m_device (device),
|
||||||
m_memProps (device->adapter()->memoryProperties()),
|
m_memProps (device->adapter()->memoryProperties()) {
|
||||||
m_maxChunkSize (determineMaxChunkSize(device)) {
|
|
||||||
for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
|
for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
|
||||||
m_memHeaps[i].properties = m_memProps.memoryHeaps[i];
|
m_memHeaps[i].properties = m_memProps.memoryHeaps[i];
|
||||||
m_memHeaps[i].stats = DxvkMemoryStats { 0, 0 };
|
m_memHeaps[i].stats = DxvkMemoryStats { 0, 0 };
|
||||||
@ -195,6 +194,7 @@ namespace dxvk {
|
|||||||
m_memTypes[i].heapId = m_memProps.memoryTypes[i].heapIndex;
|
m_memTypes[i].heapId = m_memProps.memoryTypes[i].heapIndex;
|
||||||
m_memTypes[i].memType = m_memProps.memoryTypes[i];
|
m_memTypes[i].memType = m_memProps.memoryTypes[i];
|
||||||
m_memTypes[i].memTypeId = i;
|
m_memTypes[i].memTypeId = i;
|
||||||
|
m_memTypes[i].chunkSize = MinChunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->features().core.features.sparseBinding)
|
if (device->features().core.features.sparseBinding)
|
||||||
@ -313,7 +313,7 @@ namespace dxvk {
|
|||||||
VkDeviceSize align,
|
VkDeviceSize align,
|
||||||
const DxvkMemoryProperties& info,
|
const DxvkMemoryProperties& info,
|
||||||
DxvkMemoryFlags hints) {
|
DxvkMemoryFlags hints) {
|
||||||
VkDeviceSize chunkSize = pickChunkSize(type->memTypeId, hints);
|
VkDeviceSize chunkSize = pickChunkSize(type->memTypeId, size, hints);
|
||||||
|
|
||||||
DxvkMemory memory;
|
DxvkMemory memory;
|
||||||
|
|
||||||
@ -349,6 +349,8 @@ namespace dxvk {
|
|||||||
memory = chunk->alloc(info.flags, size, align, hints);
|
memory = chunk->alloc(info.flags, size, align, hints);
|
||||||
|
|
||||||
type->chunks.push_back(std::move(chunk));
|
type->chunks.push_back(std::move(chunk));
|
||||||
|
|
||||||
|
adjustChunkSize(type->memTypeId, devMem.memSize, hints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,12 +491,14 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkDeviceSize DxvkMemoryAllocator::pickChunkSize(uint32_t memTypeId, DxvkMemoryFlags hints) const {
|
VkDeviceSize DxvkMemoryAllocator::pickChunkSize(uint32_t memTypeId, VkDeviceSize requiredSize, DxvkMemoryFlags hints) const {
|
||||||
VkMemoryType type = m_memProps.memoryTypes[memTypeId];
|
VkMemoryType type = m_memProps.memoryTypes[memTypeId];
|
||||||
VkMemoryHeap heap = m_memProps.memoryHeaps[type.heapIndex];
|
VkMemoryHeap heap = m_memProps.memoryHeaps[type.heapIndex];
|
||||||
|
|
||||||
// Default to a chunk size of 256 MiB
|
VkDeviceSize chunkSize = m_memTypes[memTypeId].chunkSize;
|
||||||
VkDeviceSize chunkSize = m_maxChunkSize;
|
|
||||||
|
while (chunkSize < requiredSize)
|
||||||
|
chunkSize <<= 1u;
|
||||||
|
|
||||||
if (hints.test(DxvkMemoryFlag::Small))
|
if (hints.test(DxvkMemoryFlag::Small))
|
||||||
chunkSize = std::min<VkDeviceSize>(chunkSize, 16 << 20);
|
chunkSize = std::min<VkDeviceSize>(chunkSize, 16 << 20);
|
||||||
@ -513,6 +517,20 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkMemoryAllocator::adjustChunkSize(
|
||||||
|
uint32_t memTypeId,
|
||||||
|
VkDeviceSize allocatedSize,
|
||||||
|
DxvkMemoryFlags hints) {
|
||||||
|
VkDeviceSize chunkSize = m_memTypes[memTypeId].chunkSize;
|
||||||
|
|
||||||
|
// Don't bump chunk size if we reached the maximum or if
|
||||||
|
// we already were unable to allocate a full chunk.
|
||||||
|
if (chunkSize < MaxChunkSize && chunkSize <= allocatedSize
|
||||||
|
&& chunkSize <= m_memTypes[memTypeId].heap->stats.memoryAllocated)
|
||||||
|
m_memTypes[memTypeId].chunkSize <<= 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DxvkMemoryAllocator::shouldFreeChunk(
|
bool DxvkMemoryAllocator::shouldFreeChunk(
|
||||||
const DxvkMemoryType* type,
|
const DxvkMemoryType* type,
|
||||||
const Rc<DxvkMemoryChunk>& chunk) const {
|
const Rc<DxvkMemoryChunk>& chunk) const {
|
||||||
@ -520,6 +538,11 @@ namespace dxvk {
|
|||||||
if (this->shouldFreeEmptyChunks(type->heap, 0))
|
if (this->shouldFreeEmptyChunks(type->heap, 0))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// Free chunks that are below the current chunk size since it probably
|
||||||
|
// not going to be able to serve enough allocations to be useful.
|
||||||
|
if (chunk->size() < type->chunkSize)
|
||||||
|
return true;
|
||||||
|
|
||||||
// Only keep a small number of chunks of each type around to save memory.
|
// Only keep a small number of chunks of each type around to save memory.
|
||||||
uint32_t numEmptyChunks = 0;
|
uint32_t numEmptyChunks = 0;
|
||||||
|
|
||||||
@ -635,17 +658,6 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkDeviceSize DxvkMemoryAllocator::determineMaxChunkSize(
|
|
||||||
DxvkDevice* device) const {
|
|
||||||
int32_t option = device->config().maxChunkSize;
|
|
||||||
|
|
||||||
if (option <= 0)
|
|
||||||
option = 256;
|
|
||||||
|
|
||||||
return VkDeviceSize(option) << 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DxvkMemoryAllocator::logMemoryError(const VkMemoryRequirements& req) const {
|
void DxvkMemoryAllocator::logMemoryError(const VkMemoryRequirements& req) const {
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
sstr << "DxvkMemoryAllocator: Memory allocation failed" << std::endl
|
sstr << "DxvkMemoryAllocator: Memory allocation failed" << std::endl
|
||||||
|
@ -83,6 +83,8 @@ namespace dxvk {
|
|||||||
VkMemoryType memType;
|
VkMemoryType memType;
|
||||||
uint32_t memTypeId;
|
uint32_t memTypeId;
|
||||||
|
|
||||||
|
VkDeviceSize chunkSize;
|
||||||
|
|
||||||
std::vector<Rc<DxvkMemoryChunk>> chunks;
|
std::vector<Rc<DxvkMemoryChunk>> chunks;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -211,6 +213,14 @@ namespace dxvk {
|
|||||||
|
|
||||||
~DxvkMemoryChunk();
|
~DxvkMemoryChunk();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Queries chunk size
|
||||||
|
* \returns Chunk size
|
||||||
|
*/
|
||||||
|
VkDeviceSize size() const {
|
||||||
|
return m_memory.memSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Allocates memory from the chunk
|
* \brief Allocates memory from the chunk
|
||||||
*
|
*
|
||||||
@ -304,6 +314,9 @@ namespace dxvk {
|
|||||||
friend class DxvkMemoryChunk;
|
friend class DxvkMemoryChunk;
|
||||||
|
|
||||||
constexpr static VkDeviceSize SmallAllocationThreshold = 256 << 10;
|
constexpr static VkDeviceSize SmallAllocationThreshold = 256 << 10;
|
||||||
|
|
||||||
|
constexpr static VkDeviceSize MinChunkSize = 4ull << 20;
|
||||||
|
constexpr static VkDeviceSize MaxChunkSize = 256ull << 20;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkMemoryAllocator(DxvkDevice* device);
|
DxvkMemoryAllocator(DxvkDevice* device);
|
||||||
@ -348,10 +361,8 @@ namespace dxvk {
|
|||||||
VkPhysicalDeviceMemoryProperties m_memProps;
|
VkPhysicalDeviceMemoryProperties m_memProps;
|
||||||
|
|
||||||
dxvk::mutex m_mutex;
|
dxvk::mutex m_mutex;
|
||||||
std::array<DxvkMemoryHeap, VK_MAX_MEMORY_HEAPS> m_memHeaps;
|
std::array<DxvkMemoryHeap, VK_MAX_MEMORY_HEAPS> m_memHeaps = { };
|
||||||
std::array<DxvkMemoryType, VK_MAX_MEMORY_TYPES> m_memTypes;
|
std::array<DxvkMemoryType, VK_MAX_MEMORY_TYPES> m_memTypes = { };
|
||||||
|
|
||||||
VkDeviceSize m_maxChunkSize;
|
|
||||||
|
|
||||||
uint32_t m_sparseMemoryTypes = 0u;
|
uint32_t m_sparseMemoryTypes = 0u;
|
||||||
|
|
||||||
@ -388,8 +399,14 @@ namespace dxvk {
|
|||||||
|
|
||||||
VkDeviceSize pickChunkSize(
|
VkDeviceSize pickChunkSize(
|
||||||
uint32_t memTypeId,
|
uint32_t memTypeId,
|
||||||
|
VkDeviceSize requiredSize,
|
||||||
DxvkMemoryFlags hints) const;
|
DxvkMemoryFlags hints) const;
|
||||||
|
|
||||||
|
void adjustChunkSize(
|
||||||
|
uint32_t memTypeId,
|
||||||
|
VkDeviceSize allocatedSize,
|
||||||
|
DxvkMemoryFlags hints);
|
||||||
|
|
||||||
bool shouldFreeChunk(
|
bool shouldFreeChunk(
|
||||||
const DxvkMemoryType* type,
|
const DxvkMemoryType* type,
|
||||||
const Rc<DxvkMemoryChunk>& chunk) const;
|
const Rc<DxvkMemoryChunk>& chunk) const;
|
||||||
@ -404,9 +421,6 @@ namespace dxvk {
|
|||||||
uint32_t determineSparseMemoryTypes(
|
uint32_t determineSparseMemoryTypes(
|
||||||
DxvkDevice* device) const;
|
DxvkDevice* device) const;
|
||||||
|
|
||||||
VkDeviceSize determineMaxChunkSize(
|
|
||||||
DxvkDevice* device) const;
|
|
||||||
|
|
||||||
void logMemoryError(
|
void logMemoryError(
|
||||||
const VkMemoryRequirements& req) const;
|
const VkMemoryRequirements& req) const;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user