Example #1
0
        public int Allocate([NativeTypeName("UINT64")] ulong size, [NativeTypeName("UINT64")] ulong alignment, [NativeTypeName("const D3D12MA_ALLOCATION_DESC&")] D3D12MA_ALLOCATION_DESC *allocDesc, [NativeTypeName("size_t")] nuint allocationCount, D3D12MA_Allocation **pAllocations)
        {
            nuint allocIndex;

            HRESULT hr = S_OK;

            using (var @lock = new D3D12MA_MutexLockWrite(ref m_Mutex, m_hAllocator->UseMutex()))
            {
                for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
                {
                    hr = AllocatePage(size, alignment, allocDesc, pAllocations + allocIndex);

                    if (FAILED(hr))
                    {
                        break;
                    }
                }
            }

            if (FAILED(hr))
            {
                // Free all already created allocations.
                while (unchecked (allocIndex-- != 0))
                {
                    Free(pAllocations[allocIndex]);
                }

                ZeroMemory(pAllocations, (nuint)sizeof(D3D12MA_Allocation *) * allocationCount);
            }

            return(hr);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
            }
        }