diff --git a/include/D3D12MemAlloc.h b/include/D3D12MemAlloc.h index 4131032..ff989cb 100644 --- a/include/D3D12MemAlloc.h +++ b/include/D3D12MemAlloc.h @@ -543,26 +543,6 @@ public: */ LPCWSTR GetName() const { return m_Name; } - /** \brief Returns `TRUE` if the memory of the allocation was filled with zeros when the allocation was created. - - Returns `TRUE` only if the allocator is sure that the entire memory where the - allocation was created was filled with zeros at the moment the allocation was made. - - Returns `FALSE` if the memory could potentially contain garbage data. - If it's a render-target or depth-stencil texture, it then needs proper - initialization with `ClearRenderTargetView`, `ClearDepthStencilView`, `DiscardResource`, - or a copy operation, as described on page - "ID3D12Device::CreatePlacedResource method - Notes on the required resource initialization" in Microsoft documentation. - Please note that rendering a fullscreen triangle or quad to the texture as - a render target is not a proper way of initialization! - - See also articles: - - - "Coming to DirectX 12: More control over memory allocation" on DirectX Developer Blog - - ["Initializing DX12 Textures After Allocation and Aliasing"](https://asawicki.info/news_1724_initializing_dx12_textures_after_allocation_and_aliasing). - */ - BOOL WasZeroInitialized() const { return m_PackedData.WasZeroInitialized(); } - protected: void ReleaseThis() override; @@ -621,29 +601,26 @@ private: { public: PackedData() : - m_Type(0), m_ResourceDimension(0), m_ResourceFlags(0), m_TextureLayout(0), m_WasZeroInitialized(0) { } + m_Type(0), m_ResourceDimension(0), m_ResourceFlags(0), m_TextureLayout(0) { } Type GetType() const { return (Type)m_Type; } D3D12_RESOURCE_DIMENSION GetResourceDimension() const { return (D3D12_RESOURCE_DIMENSION)m_ResourceDimension; } D3D12_RESOURCE_FLAGS GetResourceFlags() const { return (D3D12_RESOURCE_FLAGS)m_ResourceFlags; } D3D12_TEXTURE_LAYOUT GetTextureLayout() const { return (D3D12_TEXTURE_LAYOUT)m_TextureLayout; } - BOOL WasZeroInitialized() const { return (BOOL)m_WasZeroInitialized; } void SetType(Type type); void SetResourceDimension(D3D12_RESOURCE_DIMENSION resourceDimension); void SetResourceFlags(D3D12_RESOURCE_FLAGS resourceFlags); void SetTextureLayout(D3D12_TEXTURE_LAYOUT textureLayout); - void SetWasZeroInitialized(BOOL wasZeroInitialized) { m_WasZeroInitialized = wasZeroInitialized ? 1 : 0; } private: UINT m_Type : 2; // enum Type UINT m_ResourceDimension : 3; // enum D3D12_RESOURCE_DIMENSION UINT m_ResourceFlags : 24; // flags D3D12_RESOURCE_FLAGS UINT m_TextureLayout : 9; // enum D3D12_TEXTURE_LAYOUT - UINT m_WasZeroInitialized : 1; // BOOL } m_PackedData; - Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment, BOOL wasZeroInitialized); + Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment); // Nothing here, everything already done in Release. virtual ~Allocation() = default; diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp index bc4af5c..706c78a 100644 --- a/src/D3D12MemAlloc.cpp +++ b/src/D3D12MemAlloc.cpp @@ -2874,75 +2874,9 @@ struct AllocationRequest UINT64 sumFreeSize; // Sum size of free items that overlap with proposed allocation. UINT64 sumItemSize; // Sum size of items to make lost that overlap with proposed allocation. SuballocationList::iterator item; - BOOL zeroInitialized = FALSE; // TODO Implement proper handling in TLSF and Linear, using ZeroInitializedRange class. }; #endif // _D3D12MA_ALLOCATION_REQUEST -#ifndef _D3D12MA_ZERO_INITIALIZED_RANGE -/* -Keeps track of the range of bytes that are surely initialized with zeros. -Everything outside of it is considered uninitialized memory that may contain -garbage data. - -The range is left-inclusive. -*/ -class ZeroInitializedRange -{ -public: - void Reset(UINT64 size); - BOOL IsRangeZeroInitialized(UINT64 beg, UINT64 end) const; - void MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd); - -private: - UINT64 m_ZeroBeg = 0, m_ZeroEnd = 0; -}; - -#ifndef _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS -void ZeroInitializedRange::Reset(UINT64 size) -{ - D3D12MA_ASSERT(size > 0); - m_ZeroBeg = 0; - m_ZeroEnd = size; -} - -BOOL ZeroInitializedRange::IsRangeZeroInitialized(UINT64 beg, UINT64 end) const -{ - D3D12MA_ASSERT(beg < end); - return m_ZeroBeg <= beg && end <= m_ZeroEnd; -} - -void ZeroInitializedRange::MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd) -{ - D3D12MA_ASSERT(usedBeg < usedEnd); - // No new bytes marked. - if (usedEnd <= m_ZeroBeg || m_ZeroEnd <= usedBeg) - { - return; - } - // All bytes marked. - if (usedBeg <= m_ZeroBeg && m_ZeroEnd <= usedEnd) - { - m_ZeroBeg = m_ZeroEnd = 0; - } - // Some bytes marked. - else - { - const UINT64 remainingZeroBefore = usedBeg > m_ZeroBeg ? usedBeg - m_ZeroBeg : 0; - const UINT64 remainingZeroAfter = usedEnd < m_ZeroEnd ? m_ZeroEnd - usedEnd : 0; - D3D12MA_ASSERT(remainingZeroBefore > 0 || remainingZeroAfter > 0); - if (remainingZeroBefore > remainingZeroAfter) - { - m_ZeroEnd = usedBeg; - } - else - { - m_ZeroBeg = usedEnd; - } - } -} -#endif // _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS -#endif // _D3D12MA_ZERO_INITIALIZED_RANGE - #ifndef _D3D12MA_BLOCK_METADATA /* Data structure used for bookkeeping of allocations and unused ranges of memory @@ -3121,610 +3055,6 @@ void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const #endif // _D3D12MA_BLOCK_METADATA_FUNCTIONS #endif // _D3D12MA_BLOCK_METADATA -#if 0 -#ifndef _D3D12MA_BLOCK_METADATA_GENERIC -class BlockMetadata_Generic : public BlockMetadata -{ -public: - BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual); - virtual ~BlockMetadata_Generic() = default; - - size_t GetAllocationCount() const override { return m_Suballocations.size() - m_FreeCount; } - UINT64 GetSumFreeSize() const override { return m_SumFreeSize; } - UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return (UINT64)allocHandle - 1; } - - void Init(UINT64 size) override; - bool Validate() const override; - bool IsEmpty() const override; - void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override; - - bool CreateAllocationRequest( - UINT64 allocSize, - UINT64 allocAlignment, - bool upperAddress, - AllocationRequest* pAllocationRequest) override; - - void Alloc( - const AllocationRequest& request, - UINT64 allocSize, - void* privateData) override; - - void Free(AllocHandle allocHandle) override; - void Clear() override; - - void SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) override; - - void AddStatistics(Statistics& inoutStats) const override; - void AddDetailedStatistics(DetailedStatistics& inoutStats) const override; - void WriteAllocationInfoToJson(JsonWriter& json) const override; - -private: - UINT m_FreeCount; - UINT64 m_SumFreeSize; - SuballocationList m_Suballocations; - // Suballocations that are free and have size greater than certain threshold. - // Sorted by size, ascending. - Vector m_FreeSuballocationsBySize; - ZeroInitializedRange m_ZeroInitializedRange; - - SuballocationList::const_iterator FindAtOffset(UINT64 offset) const; - bool ValidateFreeSuballocationList() const; - - // Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem. - // If yes, fills pOffset and returns true. If no, returns false. - bool CheckAllocation( - UINT64 allocSize, - UINT64 allocAlignment, - SuballocationList::const_iterator suballocItem, - AllocHandle* pAllocHandle, - UINT64* pSumFreeSize, - UINT64* pSumItemSize, - BOOL *pZeroInitialized) const; - // Given free suballocation, it merges it with following one, which must also be free. - void MergeFreeWithNext(SuballocationList::iterator item); - // Releases given suballocation, making it free. - // Merges it with adjacent free suballocations if applicable. - // Returns iterator to new free suballocation at this place. - SuballocationList::iterator FreeSuballocation(SuballocationList::iterator suballocItem); - // Given free suballocation, it inserts it into sorted list of - // m_FreeSuballocationsBySize if it's suitable. - void RegisterFreeSuballocation(SuballocationList::iterator item); - // Given free suballocation, it removes it from sorted list of - // m_FreeSuballocationsBySize if it's suitable. - void UnregisterFreeSuballocation(SuballocationList::iterator item); - - D3D12MA_CLASS_NO_COPY(BlockMetadata_Generic) -}; - -#ifndef _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS -BlockMetadata_Generic::BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual) - : BlockMetadata(allocationCallbacks, isVirtual), - m_FreeCount(0), - m_SumFreeSize(0), - m_Suballocations(*allocationCallbacks), - m_FreeSuballocationsBySize(*allocationCallbacks) -{ - D3D12MA_ASSERT(allocationCallbacks); -} - -void BlockMetadata_Generic::Init(UINT64 size) -{ - BlockMetadata::Init(size); - m_ZeroInitializedRange.Reset(size); - - m_FreeCount = 1; - m_SumFreeSize = size; - - Suballocation suballoc = {}; - suballoc.offset = 0; - suballoc.size = size; - suballoc.type = SUBALLOCATION_TYPE_FREE; - suballoc.privateData = NULL; - - D3D12MA_ASSERT(size > MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER); - m_Suballocations.push_back(suballoc); - SuballocationList::iterator suballocItem = m_Suballocations.end(); - --suballocItem; - m_FreeSuballocationsBySize.push_back(suballocItem); -} - -bool BlockMetadata_Generic::Validate() const -{ - D3D12MA_VALIDATE(!m_Suballocations.empty()); - - // Expected offset of new suballocation as calculated from previous ones. - UINT64 calculatedOffset = 0; - // Expected number of free suballocations as calculated from traversing their list. - UINT calculatedFreeCount = 0; - // Expected sum size of free suballocations as calculated from traversing their list. - UINT64 calculatedSumFreeSize = 0; - // Expected number of free suballocations that should be registered in - // m_FreeSuballocationsBySize calculated from traversing their list. - size_t freeSuballocationsToRegister = 0; - // True if previous visited suballocation was free. - bool prevFree = false; - - for (const auto& subAlloc : m_Suballocations) - { - // Actual offset of this suballocation doesn't match expected one. - D3D12MA_VALIDATE(subAlloc.offset == calculatedOffset); - - const bool currFree = (subAlloc.type == SUBALLOCATION_TYPE_FREE); - // Two adjacent free suballocations are invalid. They should be merged. - D3D12MA_VALIDATE(!prevFree || !currFree); - - const Allocation* const alloc = (Allocation*)subAlloc.privateData; - if (!IsVirtual()) - { - D3D12MA_VALIDATE(currFree == (alloc == NULL)); - } - - if (currFree) - { - calculatedSumFreeSize += subAlloc.size; - ++calculatedFreeCount; - if (subAlloc.size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - ++freeSuballocationsToRegister; - } - - // Margin required between allocations - every free space must be at least that large. - D3D12MA_VALIDATE(subAlloc.size >= GetDebugMargin()); - } - else - { - if (!IsVirtual()) - { - D3D12MA_VALIDATE(alloc->GetOffset() == subAlloc.offset); - D3D12MA_VALIDATE(alloc->GetSize() == subAlloc.size); - } - - // Margin required between allocations - previous allocation must be free. - D3D12MA_VALIDATE(GetDebugMargin() == 0 || prevFree); - } - - calculatedOffset += subAlloc.size; - prevFree = currFree; - } - - // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't - // match expected one. - D3D12MA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister); - - UINT64 lastSize = 0; - for (size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i) - { - SuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i]; - - // Only free suballocations can be registered in m_FreeSuballocationsBySize. - D3D12MA_VALIDATE(suballocItem->type == SUBALLOCATION_TYPE_FREE); - // They must be sorted by size ascending. - D3D12MA_VALIDATE(suballocItem->size >= lastSize); - - lastSize = suballocItem->size; - } - - // Check if totals match calculacted values. - D3D12MA_VALIDATE(ValidateFreeSuballocationList()); - D3D12MA_VALIDATE(calculatedOffset == GetSize()); - D3D12MA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize); - D3D12MA_VALIDATE(calculatedFreeCount == m_FreeCount); - - return true; -} - -bool BlockMetadata_Generic::IsEmpty() const -{ - return (m_Suballocations.size() == 1) && (m_FreeCount == 1); -} - -void BlockMetadata_Generic::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const -{ - Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst(); - outInfo.Offset = suballoc.offset; - outInfo.Size = suballoc.size; - outInfo.pPrivateData = suballoc.privateData; -} - -bool BlockMetadata_Generic::CreateAllocationRequest( - UINT64 allocSize, - UINT64 allocAlignment, - bool upperAddress, - AllocationRequest* pAllocationRequest) -{ - D3D12MA_ASSERT(allocSize > 0); - D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm."); - D3D12MA_ASSERT(pAllocationRequest != NULL); - D3D12MA_HEAVY_ASSERT(Validate()); - - // There is not enough total free space in this block to fullfill the request: Early return. - if (m_SumFreeSize < allocSize + GetDebugMargin()) - { - return false; - } - - // New algorithm, efficiently searching freeSuballocationsBySize. - const size_t freeSuballocCount = m_FreeSuballocationsBySize.size(); - if (freeSuballocCount > 0) - { - // Find first free suballocation with size not less than allocSize + GetDebugMargin(). - SuballocationList::iterator* const it = BinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + freeSuballocCount, - allocSize + GetDebugMargin(), - SuballocationItemSizeLess()); - size_t index = it - m_FreeSuballocationsBySize.data(); - for (; index < freeSuballocCount; ++index) - { - if (CheckAllocation( - allocSize, - allocAlignment, - m_FreeSuballocationsBySize[index], - &pAllocationRequest->allocHandle, - &pAllocationRequest->sumFreeSize, - &pAllocationRequest->sumItemSize, - &pAllocationRequest->zeroInitialized)) - { - pAllocationRequest->item = m_FreeSuballocationsBySize[index]; - return true; - } - } - } - - return false; -} - -void BlockMetadata_Generic::Alloc( - const AllocationRequest& request, - UINT64 allocSize, - void* privateData) -{ - D3D12MA_ASSERT(request.item != m_Suballocations.end()); - Suballocation& suballoc = *request.item; - // Given suballocation is a free block. - D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE); - // Given offset is inside this suballocation. - UINT64 offset = (UINT64)request.allocHandle - 1; - D3D12MA_ASSERT(offset >= suballoc.offset); - const UINT64 paddingBegin = offset - suballoc.offset; - D3D12MA_ASSERT(suballoc.size >= paddingBegin + allocSize); - const UINT64 paddingEnd = suballoc.size - paddingBegin - allocSize; - - // Unregister this free suballocation from m_FreeSuballocationsBySize and update - // it to become used. - UnregisterFreeSuballocation(request.item); - - suballoc.offset = offset; - suballoc.size = allocSize; - suballoc.type = SUBALLOCATION_TYPE_ALLOCATION; - suballoc.privateData = privateData; - - // If there are any free bytes remaining at the end, insert new free suballocation after current one. - if (paddingEnd) - { - Suballocation paddingSuballoc = {}; - paddingSuballoc.offset = offset + allocSize; - paddingSuballoc.size = paddingEnd; - paddingSuballoc.type = SUBALLOCATION_TYPE_FREE; - SuballocationList::iterator next = request.item; - ++next; - const SuballocationList::iterator paddingEndItem = - m_Suballocations.insert(next, paddingSuballoc); - RegisterFreeSuballocation(paddingEndItem); - } - - // If there are any free bytes remaining at the beginning, insert new free suballocation before current one. - if (paddingBegin) - { - Suballocation paddingSuballoc = {}; - paddingSuballoc.offset = offset - paddingBegin; - paddingSuballoc.size = paddingBegin; - paddingSuballoc.type = SUBALLOCATION_TYPE_FREE; - const SuballocationList::iterator paddingBeginItem = - m_Suballocations.insert(request.item, paddingSuballoc); - RegisterFreeSuballocation(paddingBeginItem); - } - - // Update totals. - m_FreeCount = m_FreeCount - 1; - if (paddingBegin > 0) - { - ++m_FreeCount; - } - if (paddingEnd > 0) - { - ++m_FreeCount; - } - m_SumFreeSize -= allocSize; - - m_ZeroInitializedRange.MarkRangeAsUsed(offset, offset + allocSize); -} - -void BlockMetadata_Generic::Free(AllocHandle allocHandle) -{ - FreeSuballocation(FindAtOffset((UINT64)allocHandle - 1).dropConst()); -} - -void BlockMetadata_Generic::Clear() -{ - m_FreeCount = 1; - m_SumFreeSize = GetSize(); - - m_Suballocations.clear(); - Suballocation suballoc = {}; - suballoc.offset = 0; - suballoc.size = GetSize(); - suballoc.type = SUBALLOCATION_TYPE_FREE; - m_Suballocations.push_back(suballoc); - - m_FreeSuballocationsBySize.clear(); - m_FreeSuballocationsBySize.push_back(m_Suballocations.begin()); -} - -SuballocationList::const_iterator BlockMetadata_Generic::FindAtOffset(UINT64 offset) const -{ - const UINT64 last = m_Suballocations.crbegin()->offset; - if (last == offset) - return m_Suballocations.crbegin(); - const UINT64 first = m_Suballocations.cbegin()->offset; - if (first == offset) - return m_Suballocations.cbegin(); - - const size_t suballocCount = m_Suballocations.size(); - const UINT64 step = (last - first + m_Suballocations.cbegin()->size) / suballocCount; - auto findSuballocation = [&](auto begin, auto end) -> SuballocationList::const_iterator - { - for (auto suballocItem = begin; - suballocItem != end; - ++suballocItem) - { - const Suballocation& suballoc = *suballocItem; - if (suballoc.offset == offset) - return suballocItem; - } - D3D12MA_ASSERT(false && "Not found!"); - return m_Suballocations.end(); - }; - // If requested offset is closer to the end of range, search from the end - if ((offset - first) > suballocCount * step / 2) - { - return findSuballocation(m_Suballocations.crbegin(), m_Suballocations.crend()); - } - return findSuballocation(m_Suballocations.cbegin(), m_Suballocations.cend()); -} - -bool BlockMetadata_Generic::ValidateFreeSuballocationList() const -{ - UINT64 lastSize = 0; - for (size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i) - { - const SuballocationList::iterator it = m_FreeSuballocationsBySize[i]; - - D3D12MA_VALIDATE(it->type == SUBALLOCATION_TYPE_FREE); - D3D12MA_VALIDATE(it->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER); - D3D12MA_VALIDATE(it->size >= lastSize); - lastSize = it->size; - } - return true; -} - -bool BlockMetadata_Generic::CheckAllocation( - UINT64 allocSize, - UINT64 allocAlignment, - SuballocationList::const_iterator suballocItem, - AllocHandle* pAllocHandle, - UINT64* pSumFreeSize, - UINT64* pSumItemSize, - BOOL* pZeroInitialized) const -{ - D3D12MA_ASSERT(allocSize > 0); - D3D12MA_ASSERT(suballocItem != m_Suballocations.cend()); - D3D12MA_ASSERT(pAllocHandle != NULL && pZeroInitialized != NULL); - - *pSumFreeSize = 0; - *pSumItemSize = 0; - *pZeroInitialized = FALSE; - - const Suballocation& suballoc = *suballocItem; - D3D12MA_ASSERT(suballoc.type == 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 and debug margin of previous allocation if present. - UINT64 offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin()); - - // Apply alignment. - offset = AlignUp(offset, allocAlignment); - - // Calculate padding at the beginning based on current offset. - const UINT64 paddingBegin = offset - suballoc.offset; - - // Fail if requested size plus margin after is bigger than size of this suballocation. - if (paddingBegin + allocSize + GetDebugMargin() > suballoc.size) - { - return false; - } - - // All tests passed: Success. Offset is already filled. - *pZeroInitialized = m_ZeroInitializedRange.IsRangeZeroInitialized(offset, offset + allocSize); - *pAllocHandle = (AllocHandle)(offset + 1); - return true; -} - -void BlockMetadata_Generic::MergeFreeWithNext(SuballocationList::iterator item) -{ - D3D12MA_ASSERT(item != m_Suballocations.end()); - D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE); - - SuballocationList::iterator nextItem = item; - ++nextItem; - D3D12MA_ASSERT(nextItem != m_Suballocations.end()); - D3D12MA_ASSERT(nextItem->type == SUBALLOCATION_TYPE_FREE); - - item->size += nextItem->size; - --m_FreeCount; - m_Suballocations.erase(nextItem); -} - -SuballocationList::iterator BlockMetadata_Generic::FreeSuballocation(SuballocationList::iterator suballocItem) -{ - // Change this suballocation to be marked as free. - Suballocation& suballoc = *suballocItem; - suballoc.type = SUBALLOCATION_TYPE_FREE; - suballoc.privateData = 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; - - SuballocationList::iterator nextItem = suballocItem; - ++nextItem; - if ((nextItem != m_Suballocations.end()) && (nextItem->type == SUBALLOCATION_TYPE_FREE)) - { - mergeWithNext = true; - } - - SuballocationList::iterator prevItem = suballocItem; - if (suballocItem != m_Suballocations.begin()) - { - --prevItem; - if (prevItem->type == 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; - } -} - -void BlockMetadata_Generic::RegisterFreeSuballocation(SuballocationList::iterator item) -{ - D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE); - D3D12MA_ASSERT(item->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(ValidateFreeSuballocationList()); - - if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - if (m_FreeSuballocationsBySize.empty()) - { - m_FreeSuballocationsBySize.push_back(item); - } - else - { - m_FreeSuballocationsBySize.InsertSorted(item, SuballocationItemSizeLess()); - } - } - - //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList()); -} - -void BlockMetadata_Generic::UnregisterFreeSuballocation(SuballocationList::iterator item) -{ - D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE); - D3D12MA_ASSERT(item->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(ValidateFreeSuballocationList()); - - if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER) - { - SuballocationList::iterator* const it = BinaryFindFirstNotLess( - m_FreeSuballocationsBySize.data(), - m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(), - item, - SuballocationItemSizeLess()); - for (size_t index = it - m_FreeSuballocationsBySize.data(); - index < m_FreeSuballocationsBySize.size(); - ++index) - { - if (m_FreeSuballocationsBySize[index] == item) - { - m_FreeSuballocationsBySize.remove(index); - return; - } - D3D12MA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found."); - } - D3D12MA_ASSERT(0 && "Not found."); - } - - //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList()); -} - -void BlockMetadata_Generic::SetAllocationPrivateData(AllocHandle allocHandle, void* privateData) -{ - Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst(); - suballoc.privateData = privateData; -} - -void BlockMetadata_Generic::AddStatistics(Statistics& inoutStats) const -{ - inoutStats.BlockCount++; - inoutStats.AllocationCount += (UINT)m_Suballocations.size() - m_FreeCount; - inoutStats.BlockBytes += GetSize(); - inoutStats.AllocationBytes += GetSize() - m_SumFreeSize; -} - -void BlockMetadata_Generic::AddDetailedStatistics(DetailedStatistics& inoutStats) const -{ - inoutStats.Stats.BlockCount++; - inoutStats.Stats.BlockBytes += GetSize(); - - for (const auto& suballoc : m_Suballocations) - { - if (suballoc.type == SUBALLOCATION_TYPE_FREE) - AddDetailedStatisticsUnusedRange(inoutStats, suballoc.size); - else - AddDetailedStatisticsAllocation(inoutStats, suballoc.size); - } -} - -void BlockMetadata_Generic::WriteAllocationInfoToJson(JsonWriter& json) const -{ - PrintDetailedMap_Begin(json, GetSumFreeSize(), GetAllocationCount(), m_FreeCount); - for (const auto& suballoc : m_Suballocations) - { - if (suballoc.type == SUBALLOCATION_TYPE_FREE) - PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size); - else - PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.privateData); - } - PrintDetailedMap_End(json); -} -#endif // _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS -#endif // _D3D12MA_BLOCK_METADATA_GENERIC -#endif // #if 0 - #ifndef _D3D12MA_BLOCK_METADATA_LINEAR class BlockMetadata_Linear : public BlockMetadata { @@ -7983,16 +7313,8 @@ HRESULT AllocatorPimpl::AllocateCommittedResource( } if (SUCCEEDED(hr)) { - BOOL wasZeroInitialized = TRUE; -#if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE - if((committedAllocParams.m_HeapFlags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) != 0) - { - wasZeroInitialized = FALSE; - } -#endif - Allocation* alloc = m_AllocationObjectAllocator.Allocate( - this, resourceSize, createParams.GetBaseResourceDesc()->Alignment, wasZeroInitialized); + this, resourceSize, createParams.GetBaseResourceDesc()->Alignment); alloc->InitCommitted(committedAllocParams.m_List); alloc->SetResourcePointer(res, createParams.GetBaseResourceDesc()); alloc->SetPrivateData(pPrivateData); @@ -8051,16 +7373,7 @@ HRESULT AllocatorPimpl::AllocateHeap( if (SUCCEEDED(hr)) { SetResidencyPriority(heap, committedAllocParams.m_ResidencyPriority); - - BOOL wasZeroInitialized = TRUE; -#if D3D12MA_CREATE_NOT_ZEROED_AVAILABLE - if((heapDesc.Flags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED) != 0) - { - wasZeroInitialized = FALSE; - } -#endif - - (*ppAllocation) = m_AllocationObjectAllocator.Allocate(this, allocInfo.SizeInBytes, allocInfo.Alignment, wasZeroInitialized); + (*ppAllocation) = m_AllocationObjectAllocator.Allocate(this, allocInfo.SizeInBytes, allocInfo.Alignment); (*ppAllocation)->InitHeap(committedAllocParams.m_List, heap); (*ppAllocation)->SetPrivateData(pPrivateData); committedAllocParams.m_List->Register(*ppAllocation); @@ -9085,7 +8398,7 @@ HRESULT BlockVector::CommitAllocationRequest( if (pBlock->m_pMetadata->IsEmpty()) m_HasEmptyBlock = false; - *pAllocation = m_hAllocator->GetAllocationObjectAllocator().Allocate(m_hAllocator, size, alignment, allocRequest.zeroInitialized); + *pAllocation = m_hAllocator->GetAllocationObjectAllocator().Allocate(m_hAllocator, size, alignment); pBlock->m_pMetadata->Alloc(allocRequest, size, *pAllocation); (*pAllocation)->InitPlaced(allocRequest.allocHandle, pBlock); @@ -10023,7 +9336,7 @@ void Allocation::ReleaseThis() m_Allocator->GetAllocationObjectAllocator().Free(this); } -Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment, BOOL wasZeroInitialized) +Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment) : m_Allocator{ allocator }, m_Size{ size }, m_Alignment{ alignment }, @@ -10037,7 +9350,6 @@ Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment, m_PackedData.SetResourceDimension(D3D12_RESOURCE_DIMENSION_UNKNOWN); m_PackedData.SetResourceFlags(D3D12_RESOURCE_FLAG_NONE); m_PackedData.SetTextureLayout(D3D12_TEXTURE_LAYOUT_UNKNOWN); - m_PackedData.SetWasZeroInitialized(wasZeroInitialized); } void Allocation::InitCommitted(CommittedAllocationList* list) @@ -10071,7 +9383,6 @@ void Allocation::SwapBlockAllocation(Allocation* allocation) D3D12MA_ASSERT(allocation->m_PackedData.GetType() == TYPE_PLACED); D3D12MA_SWAP(m_Resource, allocation->m_Resource); - m_PackedData.SetWasZeroInitialized(allocation->m_PackedData.WasZeroInitialized()); m_Placed.block->m_pMetadata->SetAllocationPrivateData(m_Placed.allocHandle, allocation); D3D12MA_SWAP(m_Placed, allocation->m_Placed); m_Placed.block->m_pMetadata->SetAllocationPrivateData(m_Placed.allocHandle, this); diff --git a/src/Tests.cpp b/src/Tests.cpp index 63c077b..cb474ff 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -1834,145 +1834,6 @@ static void TestTransfer(const TestContext& ctx) } } -static void TestZeroInitialized(const TestContext& ctx) -{ - wprintf(L"Test zero initialized\n"); - - const UINT64 bufSize = 128ull * 1024; - - D3D12_RESOURCE_DESC resourceDesc; - FillResourceDescForBuffer(resourceDesc, bufSize); - - // # Create upload buffer and fill it with data. - - D3D12MA::ALLOCATION_DESC allocDescUpload = {}; - allocDescUpload.HeapType = D3D12_HEAP_TYPE_UPLOAD; - - ResourceWithAllocation bufUpload; - CHECK_HR( ctx.allocator->CreateResource( - &allocDescUpload, - &resourceDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - NULL, - &bufUpload.allocation, - IID_PPV_ARGS(&bufUpload.resource)) ); - - { - void* mappedPtr = nullptr; - CHECK_HR( bufUpload.resource->Map(0, &EMPTY_RANGE, &mappedPtr) ); - FillData(mappedPtr, bufSize, 5236245); - bufUpload.resource->Unmap(0, NULL); - } - - // # Create readback buffer - - D3D12MA::ALLOCATION_DESC allocDescReadback = {}; - allocDescReadback.HeapType = D3D12_HEAP_TYPE_READBACK; - - ResourceWithAllocation bufReadback; - CHECK_HR( ctx.allocator->CreateResource( - &allocDescReadback, - &resourceDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - NULL, - &bufReadback.allocation, - IID_PPV_ARGS(&bufReadback.resource)) ); - - auto CheckBufferData = [&](const ResourceWithAllocation& buf) - { - const bool shouldBeZero = buf.allocation->WasZeroInitialized() != FALSE; - - { - ID3D12GraphicsCommandList* cmdList = BeginCommandList(); - cmdList->CopyBufferRegion(bufReadback.resource.Get(), 0, buf.resource.Get(), 0, bufSize); - EndCommandList(cmdList); - } - - bool isZero = false; - { - const D3D12_RANGE readRange{0, bufSize}; // I could pass pReadRange = NULL but it generates D3D Debug layer warning: EXECUTION WARNING #930: MAP_INVALID_NULLRANGE - void* mappedPtr = nullptr; - CHECK_HR( bufReadback.resource->Map(0, &readRange, &mappedPtr) ); - isZero = ValidateDataZero(mappedPtr, bufSize); - bufReadback.resource->Unmap(0, &EMPTY_RANGE); - } - - wprintf(L"Should be zero: %u, is zero: %u\n", shouldBeZero ? 1 : 0, isZero ? 1 : 0); - - if(shouldBeZero) - { - CHECK_BOOL(isZero); - } - }; - - // # Test 1: Committed resource. Should always be zero initialized. - - { - D3D12MA::ALLOCATION_DESC allocDescDefault = {}; - allocDescDefault.HeapType = D3D12_HEAP_TYPE_DEFAULT; - allocDescDefault.Flags = D3D12MA::ALLOCATION_FLAG_COMMITTED; - - ResourceWithAllocation bufDefault; - CHECK_HR( ctx.allocator->CreateResource( - &allocDescDefault, - &resourceDesc, - D3D12_RESOURCE_STATE_COPY_SOURCE, - NULL, - &bufDefault.allocation, - IID_PPV_ARGS(&bufDefault.resource)) ); - - wprintf(L" Committed: "); - CheckBufferData(bufDefault); - CHECK_BOOL( bufDefault.allocation->WasZeroInitialized() ); - } - - // # Test 2: (Probably) placed resource. - - ResourceWithAllocation bufDefault; - for(uint32_t i = 0; i < 2; ++i) - { - // 1. Create buffer - - D3D12MA::ALLOCATION_DESC allocDescDefault = {}; - allocDescDefault.HeapType = D3D12_HEAP_TYPE_DEFAULT; - - CHECK_HR( ctx.allocator->CreateResource( - &allocDescDefault, - &resourceDesc, - D3D12_RESOURCE_STATE_COPY_SOURCE, - NULL, - &bufDefault.allocation, - IID_PPV_ARGS(&bufDefault.resource)) ); - - // 2. Check it - - wprintf(L" Normal #%u: ", i); - CheckBufferData(bufDefault); - - // 3. Upload some data to it - - { - ID3D12GraphicsCommandList* cmdList = BeginCommandList(); - - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = bufDefault.resource.Get(); - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - cmdList->ResourceBarrier(1, &barrier); - - cmdList->CopyBufferRegion(bufDefault.resource.Get(), 0, bufUpload.resource.Get(), 0, bufSize); - - EndCommandList(cmdList); - } - - // 4. Delete it - - bufDefault.Reset(); - } -} - static void TestMultithreading(const TestContext& ctx) { wprintf(L"Test multithreading\n"); @@ -4381,7 +4242,6 @@ static void TestGroupBasics(const TestContext& ctx) TestMapping(ctx); TestStats(ctx); TestTransfer(ctx); - TestZeroInitialized(ctx); TestMultithreading(ctx); TestLinearAllocator(ctx); TestLinearAllocatorMultiBlock(ctx);