Growable command buffers

This commit is contained in:
NSDeathman 2026-03-15 21:08:20 +03:00
parent 2e9731a97c
commit b46f39bd06
4 changed files with 93 additions and 1 deletions

View file

@ -170,6 +170,23 @@ private:
void DeleteInternalBuffer(int index);
Renderer::Context &getContext();
void GrowCommandBufferArrays();
private:
void ShrinkCommandBufferArrays();
static constexpr int kMinCommandBuffers = MAX_COMMAND_BUFFERS; // íèæíÿÿ ãðàíèöà, íèêîãäà íå óìåíüøàåì íèæå
static constexpr int kShrinkCooldownTicks = 300; // ~5 ñåêóíä ïðè 60 òèê/ñ
static constexpr float kShrinkThreshold = 0.75f; // ñæèìàåì åñëè çàíÿòî < kShrinkThreshold% ñëîòîâ
static constexpr float kShrinkTarget = kShrinkThreshold; // ñæèìàåì äî kShrinkThreshold òåêóùåãî ðàçìåðà
int m_shrinkCooldown; // îáðàòíûé ñ÷¸ò÷èê — ñêîëüêî òèêîâ îñòàëîñü äî ñëåäóþùåé ïðîâåðêè
int m_peakUsageSinceLastShrinkCheck; // ïèê èñïîëüçîâàíèÿ çà ïåðèîä cooldown
#ifdef _DEBUG
DWORD m_peakCommandBuffers;
DWORD m_peakHandles;
#endif
public:
enum eTextureSamplerFlags

View file

@ -418,9 +418,9 @@ void Renderer::CBuffTick()
{
EnterCriticalSection(&m_commandBufferCS);
// --- Óäàëåíèå îäíîãî óñòàðåâøåãî áóôåðà çà òèê ---
if (m_numBuffersToDeallocate > 0)
{
// Удаляем ровно один буфер за тик — чтобы не спайкать кадр
const int totalSlots = static_cast<int>(m_commandBuffers.size());
const int deleteIdx = totalSlots - static_cast<int>(m_numBuffersToDeallocate);
@ -436,6 +436,30 @@ void Renderer::CBuffTick()
--m_numBuffersToDeallocate;
}
// --- Îòñëåæèâàåì ïèê èñïîëüçîâàíèÿ çà ïåðèîä ---
const int currentUsage = static_cast<int>(m_currentCommandBuffer);
if (currentUsage > m_peakUsageSinceLastShrinkCheck)
m_peakUsageSinceLastShrinkCheck = currentUsage;
#ifdef _DEBUG
m_peakCommandBuffers = std::max(m_peakCommandBuffers, (DWORD)m_commandBuffers.size());
m_peakHandles = std::max(m_peakHandles, (DWORD)m_vertexIdxToBufferIdx.size());
#endif
// --- Ïðîâåðêà íà ñæàòèå ðàç â kShrinkCooldownTicks òèêîâ ---
if (--m_shrinkCooldown <= 0)
{
m_shrinkCooldown = kShrinkCooldownTicks;
// Èñïîëüçóåì ïèê çà âåñü ïåðèîä, à íå ìîìåíòàëüíîå çíà÷åíèå —
// çàùèòà îò ñëó÷àéíûõ ïðîâàëîâ àêòèâíîñòè
const int capacityToCheck = static_cast<int>(m_commandBuffers.size());
if (m_peakUsageSinceLastShrinkCheck < static_cast<int>(capacityToCheck * kShrinkThreshold))
ShrinkCommandBufferArrays();
m_peakUsageSinceLastShrinkCheck = 0;
}
LeaveCriticalSection(&m_commandBufferCS);
}

View file

@ -833,6 +833,14 @@ void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain)
m_pDevice->CreateBuffer(&fanIndexDesc, &fanIndexData, &fanIndexBuffer);
delete[] fanIndices;
m_shrinkCooldown = kShrinkCooldownTicks;
m_peakUsageSinceLastShrinkCheck = 0;
#ifdef _DEBUG
m_peakCommandBuffers = 0;
m_peakHandles = 0;
#endif
InitializeCriticalSection(&Renderer::totalAllocCS);
}
@ -1075,3 +1083,46 @@ void Renderer::GrowCommandBufferArrays()
}
}
}
void Renderer::ShrinkCommandBufferArrays()
{
// Íåëüçÿ ñæèìàòü ïîêà åñòü îæèäàþùèå óäàëåíèÿ — îíè â õâîñòå,
// è ïðè èçìåíåíèè ðàçìåðà íàðóøèòñÿ èõ ðàñïîëîæåíèå
if (m_numBuffersToDeallocate > 0)
return;
const int currentSize = static_cast<int>(m_commandBuffers.size());
const int activeCount = static_cast<int>(m_currentCommandBuffer);
// Íèêîãäà íå óìåíüøàåìñÿ íèæå ìèíèìóìà
if (currentSize <= kMinCommandBuffers)
return;
// Ïðîâåðÿåì ïîðîã: åñëè çàíÿòî >= 25% — íå òðîãàåì
if (activeCount >= static_cast<int>(currentSize * kShrinkThreshold))
return;
// Íîâûé ðàçìåð: 50% îò òåêóùåãî, íî íå ìåíüøå kMinCommandBuffers
// è íå ìåíüøå ÷åì íóæíî äëÿ àêòèâíûõ áóôåðîâ ñ çàïàñîì x2
const int newSize = max(kMinCommandBuffers, max(static_cast<int>(currentSize * kShrinkTarget), activeCount * 2));
// Åñëè ðàçíèöà íåçíà÷èòåëüíà — íå òðîãàåì
if (newSize >= currentSize)
return;
// Àêòèâíûå áóôåðû óæå â çîíå [0, m_currentCommandBuffer) —
// îíè âñå âëåçàþò â newSize, ïðîñòî óñåêàåì õâîñò
m_commandBuffers.resize(newSize);
m_commandMatrices.resize(newSize);
m_bufferIdxToVertexIdx.resize(newSize, 0);
m_commandPrimitiveTypes.resize(newSize, 0);
m_commandVertexTypes.resize(newSize, 0);
#ifdef _DEBUG
OutputDebugStringA(
("Renderer: shrunk command buffer pool " +
std::to_string(currentSize) + " -> " +
std::to_string(newSize) + "\n").c_str()
);
#endif
}