public void AddStats([NativeTypeName("StatInfo&")] D3D12MA_StatInfo *outStats) { using var @lock = new D3D12MA_MutexLockRead(ref m_Mutex, m_hAllocator->UseMutex()); for (nuint i = 0; i < m_Blocks.size(); ++i) { D3D12MA_NormalBlock *pBlock = m_Blocks[i]->Value; D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (pBlock != null)); D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && pBlock->Validate()); D3D12MA_StatInfo blockStatInfo; pBlock->m_pMetadata->CalcAllocationStatInfo(&blockStatInfo); AddStatInfo(ref *outStats, ref blockStatInfo); } }
public int SetMinBytes([NativeTypeName("UINT64")] ulong minBytes) { using var @lock = new D3D12MA_MutexLockWrite(ref m_Mutex, m_hAllocator->UseMutex()); if (minBytes == m_MinBytes) { return(S_OK); } HRESULT hr = S_OK; ulong sumBlockSize = CalcSumBlockSize(); nuint blockCount = m_Blocks.size(); // New minBytes is smaller - may be able to free some blocks. if (minBytes < m_MinBytes) { m_HasEmptyBlock = false; // Will recalculate this value from scratch. for (nuint blockIndex = blockCount; unchecked (blockIndex-- != 0);) { D3D12MA_NormalBlock *block = m_Blocks[blockIndex]->Value; ulong size = block->m_pMetadata->GetSize(); bool isEmpty = block->m_pMetadata->IsEmpty(); if (isEmpty && ((sumBlockSize - size) >= minBytes) && ((blockCount - 1) >= m_MinBlockCount)) { D3D12MA_DELETE(m_hAllocator->GetAllocs(), block); m_Blocks.remove(blockIndex); sumBlockSize -= size; --blockCount; } else { if (isEmpty) { m_HasEmptyBlock = true; } } } } else { // New minBytes is larger - may need to allocate some blocks. ulong minBlockSize = m_PreferredBlockSize >> (int)NEW_BLOCK_SIZE_SHIFT_MAX; while (SUCCEEDED(hr) && sumBlockSize < minBytes) { if (blockCount < m_MaxBlockCount) { ulong newBlockSize = m_PreferredBlockSize; if (!m_ExplicitBlockSize) { if (sumBlockSize + newBlockSize > minBytes) { newBlockSize = minBytes - sumBlockSize; } else if (((blockCount + 1) < m_MaxBlockCount) && ((sumBlockSize + newBlockSize + minBlockSize) > minBytes)) { // Next one would be the last block to create and its size would be smaller than // the smallest block size we want to use here, so make this one smaller. newBlockSize -= minBlockSize + sumBlockSize + m_PreferredBlockSize - minBytes; } } hr = CreateBlock(newBlockSize, null); if (SUCCEEDED(hr)) { m_HasEmptyBlock = true; sumBlockSize += newBlockSize; ++blockCount; } } else { hr = E_INVALIDARG; } } } m_MinBytes = minBytes; return(hr); }
public void Free(D3D12MA_Allocation *hAllocation) { D3D12MA_NormalBlock *pBlockToDelete = null; bool budgetExceeded = false; { D3D12MA_Budget budget = default; m_hAllocator->GetBudgetForHeapType(&budget, m_HeapType); budgetExceeded = budget.UsageBytes >= budget.BudgetBytes; } using (var @lock = new D3D12MA_MutexLockWrite(ref m_Mutex, m_hAllocator->UseMutex())) { D3D12MA_NormalBlock *pBlock = hAllocation->m_Placed.block; pBlock->m_pMetadata->FreeAtOffset(hAllocation->GetOffset()); D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && pBlock->Validate()); nuint blockCount = m_Blocks.size(); ulong sumBlockSize = CalcSumBlockSize(); // pBlock became empty after this deallocation. if (pBlock->m_pMetadata->IsEmpty()) { // Already has empty Allocation. We don't want to have two, so delete this one. if ((m_HasEmptyBlock || budgetExceeded) && (blockCount > m_MinBlockCount) && ((sumBlockSize - pBlock->m_pMetadata->GetSize()) >= m_MinBytes)) { pBlockToDelete = pBlock; Remove(pBlock); } else { // We now have first empty block. m_HasEmptyBlock = true; } } else if (m_HasEmptyBlock && blockCount > m_MinBlockCount) { // pBlock didn't become empty, but we have another empty block - find and free that one. // (This is optional, heuristics.) D3D12MA_NormalBlock *pLastBlock = m_Blocks.back()->Value; if (pLastBlock->m_pMetadata->IsEmpty() && ((sumBlockSize - pLastBlock->m_pMetadata->GetSize()) >= m_MinBytes)) { pBlockToDelete = pLastBlock; m_Blocks.pop_back(); m_HasEmptyBlock = false; } } IncrementallySortBlocks(); } // Destruction of a free Allocation. Deferred until this point, outside of mutex // lock, for performance reason. if (pBlockToDelete != null) { D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlockToDelete); } }