[dxvk] Adjust desciptor pool reset heuristic

Drastically limits the amount of descriptor memory we allocate in situations
where an application renders without presenting anything to a swap chain.

The new limit is a bit tight for some real-world use cases (e.g. Ashes of the Singularity),
but at worst we will start calling vkAllocateDescriptorSets once per set and draw.
This commit is contained in:
Philip Rebohle 2024-04-08 15:40:25 +02:00
parent 49e9ea5f5a
commit 44695f9311
2 changed files with 10 additions and 17 deletions

View File

@ -72,7 +72,7 @@ namespace dxvk {
// memory bloat. This may be necessary for off-screen // memory bloat. This may be necessary for off-screen
// rendering applications, or in situations where games // rendering applications, or in situations where games
// pre-render a lot of images without presenting in between. // pre-render a lot of images without presenting in between.
return m_descriptorPools.size() >= 8; return m_descriptorPools.size() > MaxDesiredPoolCount;
} }
@ -100,29 +100,25 @@ namespace dxvk {
void DxvkDescriptorPool::reset() { void DxvkDescriptorPool::reset() {
// As a heuristic to save memory, check how many descriptors // As a heuristic to save memory, check how many descriptor
// have actively been used in the past couple of submissions. // sets were actually being used in past submissions.
bool isLowUsageFrame = false;
size_t poolCount = m_descriptorPools.size(); size_t poolCount = m_descriptorPools.size();
bool needsReset = poolCount > MaxDesiredPoolCount;
if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) { if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) {
double factor = std::max(11.0 / 3.0 - double(poolCount) / 3.0, 1.0); double factor = std::max(11.0 / 3.0 - double(poolCount) / 3.0, 1.0);
isLowUsageFrame = double(m_setsUsed) * factor < double(m_setsAllocated); needsReset = double(m_setsUsed) * factor < double(m_setsAllocated);
} }
m_lowUsageFrames = isLowUsageFrame
? m_lowUsageFrames + 1
: 0;
m_setsUsed = 0; m_setsUsed = 0;
if (m_lowUsageFrames < 16) { if (!needsReset) {
for (auto& entry : m_setLists) for (auto& entry : m_setLists)
entry.second.reset(); entry.second.reset();
} else { } else {
// If most sets are no longer being used, reset and destroy // If most sets are no longer needed, reset and destroy
// descriptor pools and reset all lookup tables in order to // descriptor pools and reset all lookup tables in order
// accomodate more descriptors of different layouts. // to accomodate more descriptors of different layouts.
for (auto pool : m_descriptorPools) for (auto pool : m_descriptorPools)
m_manager->recycleVulkanDescriptorPool(pool); m_manager->recycleVulkanDescriptorPool(pool);
@ -131,7 +127,6 @@ namespace dxvk {
m_setMaps.clear(); m_setMaps.clear();
m_setsAllocated = 0; m_setsAllocated = 0;
m_lowUsageFrames = 0;
} }
m_cachedEntry = { nullptr, nullptr }; m_cachedEntry = { nullptr, nullptr };

View File

@ -80,7 +80,7 @@ namespace dxvk {
* to be updated. * to be updated.
*/ */
class DxvkDescriptorPool : public RcObject { class DxvkDescriptorPool : public RcObject {
constexpr static uint32_t MaxDesiredPoolCount = 2;
public: public:
DxvkDescriptorPool( DxvkDescriptorPool(
@ -155,8 +155,6 @@ namespace dxvk {
uint32_t m_prevSetsAllocated = 0; uint32_t m_prevSetsAllocated = 0;
uint32_t m_lowUsageFrames = 0;
DxvkDescriptorSetMap* getSetMapCached( DxvkDescriptorSetMap* getSetMapCached(
const DxvkBindingLayoutObjects* layout); const DxvkBindingLayoutObjects* layout);