/// <summary>Given free suballocation, it removes it from sorted list of <see cref="m_FreeSuballocationsBySize"/> if it's suitable.</summary> public void UnregisterFreeSuballocation(D3D12MA_List <D3D12MA_Suballocation> .iterator item) { D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE)); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->size > 0)); // You may want to enable this validation at the beginning or at the end of // this function, depending on what do you want to check. D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocationList()); if (item.Get()->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) { D3D12MA_List <D3D12MA_Suballocation> .iterator *it = BinaryFindFirstNotLess( m_FreeSuballocationsBySize.data(), m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(), in item, new D3D12MA_SuballocationItemSizeLess() ); for (nuint index = (nuint)(it - m_FreeSuballocationsBySize.data()); index < m_FreeSuballocationsBySize.size(); ++index) { if (*m_FreeSuballocationsBySize[index] == item) { m_FreeSuballocationsBySize.remove(index); return; } D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (m_FreeSuballocationsBySize[index]->Get()->size == item.Get()->size)); // "Not found!" } D3D12MA_ASSERT(false); // "Not found!" } // D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocationList()); }
/// <summary>Given free suballocation, it merges it with following one, which must also be free.</summary> public void MergeFreeWithNext(D3D12MA_List <D3D12MA_Suballocation> .iterator item) { D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item != m_Suballocations.end())); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE)); D3D12MA_List <D3D12MA_Suballocation> .iterator nextItem = item; nextItem = nextItem.MoveNext(); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (nextItem != m_Suballocations.end())); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (nextItem.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE)); item.Get()->size += nextItem.Get()->size; --m_FreeCount; m_Suballocations.erase(nextItem); }
public readonly bool ValidateFreeSuballocationList() { ulong lastSize = 0; for (nuint i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i) { D3D12MA_List <D3D12MA_Suballocation> .iterator it = *m_FreeSuballocationsBySize[i]; _ = D3D12MA_VALIDATE(it.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE); _ = D3D12MA_VALIDATE(it.Get()->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER); _ = D3D12MA_VALIDATE(it.Get()->size >= lastSize); lastSize = it.Get()->size; } return(true); }
/// <summary>Releases given suballocation, making it free. Merges it with adjacent free suballocations if applicable. Returns iterator to new free suballocation at this place.</summary> public D3D12MA_List <D3D12MA_Suballocation> .iterator FreeSuballocation(D3D12MA_List <D3D12MA_Suballocation> .iterator suballocItem) { // Change this suballocation to be marked as free. D3D12MA_Suballocation *suballoc = suballocItem.Get(); suballoc->type = D3D12MA_SUBALLOCATION_TYPE_FREE; suballoc->userData = null; // Update totals. ++m_FreeCount; m_SumFreeSize += suballoc->size; // Merge with previous and/or next suballocation if it's also free. bool mergeWithNext = false; bool mergeWithPrev = false; D3D12MA_List <D3D12MA_Suballocation> .iterator nextItem = suballocItem; nextItem = nextItem.MoveNext(); if ((nextItem != m_Suballocations.end()) && (nextItem.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE)) { mergeWithNext = true; } D3D12MA_List <D3D12MA_Suballocation> .iterator prevItem = suballocItem; if (suballocItem != m_Suballocations.begin()) { prevItem = prevItem.MoveBack(); if (prevItem.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE) { mergeWithPrev = true; } } if (mergeWithNext) { UnregisterFreeSuballocation(nextItem); MergeFreeWithNext(suballocItem); } if (mergeWithPrev) { UnregisterFreeSuballocation(prevItem); MergeFreeWithNext(prevItem); RegisterFreeSuballocation(prevItem); return(prevItem); } else { RegisterFreeSuballocation(suballocItem); return(suballocItem); } }
/// <summary>Given free suballocation, it inserts it into sorted list of <see cref="m_FreeSuballocationsBySize"/> if it's suitable.</summary> public void RegisterFreeSuballocation(D3D12MA_List <D3D12MA_Suballocation> .iterator item) { D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE)); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->size > 0)); // You may want to enable this validation at the beginning or at the end of // this function, depending on what do you want to check. D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocationList()); if (item.Get()->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) { if (m_FreeSuballocationsBySize.empty()) { m_FreeSuballocationsBySize.push_back(in item); } else { _ = m_FreeSuballocationsBySize.InsertSorted(in item, new D3D12MA_SuballocationItemSizeLess()); } } // D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocatioNList()); }
/// <summary>Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem. If yes, fills pOffset and returns true. If no, returns false.</summary> public readonly bool CheckAllocation([NativeTypeName("UINT64")] ulong allocSize, [NativeTypeName("UINT64")] ulong allocAlignment, D3D12MA_List <D3D12MA_Suballocation> .iterator suballocItem, [NativeTypeName("UINT64*")] ulong *pOffset, [NativeTypeName("UINT64*")] ulong *pSumFreeSize, [NativeTypeName("UINT64*")] ulong *pSumItemSize, [NativeTypeName("BOOL")] int *pZeroInitialized) { D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (allocSize > 0)); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (suballocItem != m_Suballocations.end())); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (pOffset != null) && (pZeroInitialized != null)); *pSumFreeSize = 0; *pSumItemSize = 0; *pZeroInitialized = FALSE; D3D12MA_Suballocation *suballoc = suballocItem.Get(); D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (suballoc->type == D3D12MA_SUBALLOCATION_TYPE_FREE)); *pSumFreeSize = suballoc->size; // Size of this suballocation is too small for this request: Early return. if (suballoc->size < allocSize) { return(false); } // Start from offset equal to beginning of this suballocation. *pOffset = suballoc->offset; // Apply D3D12MA_DEBUG_MARGIN at the beginning. if (D3D12MA_DEBUG_MARGIN > 0) { *pOffset += D3D12MA_DEBUG_MARGIN; } // Apply alignment. *pOffset = AlignUp(*pOffset, allocAlignment); // Calculate padding at the beginning based on current offset. ulong paddingBegin = *pOffset - suballoc->offset; // Calculate required margin at the end. ulong requiredEndMargin = D3D12MA_DEBUG_MARGIN; // Fail if requested size plus margin before and after is bigger than size of this suballocation. if (paddingBegin + allocSize + requiredEndMargin > suballoc->size) { return(false); } // All tests passed: Success. pOffset is already filled. *pZeroInitialized = m_ZeroInitializedRange.IsRangeZeroInitialized(*pOffset, *pOffset + allocSize); return(true); }