GpuBlockAllocator.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <anki/gr/common/GpuBlockAllocator.h>
  6. namespace anki
  7. {
  8. //==============================================================================
  9. // GpuBlockAllocator::Block =
  10. //==============================================================================
  11. class GpuBlockAllocator::Block
  12. : public IntrusiveListEnabled<GpuBlockAllocator::Block>
  13. {
  14. public:
  15. PtrSize m_offset = 0;
  16. U32 m_allocationCount = 0;
  17. };
  18. //==============================================================================
  19. // GpuBlockAllocator =
  20. //==============================================================================
  21. //==============================================================================
  22. GpuBlockAllocator::~GpuBlockAllocator()
  23. {
  24. if(m_freeBlockCount != m_blocks.getSize())
  25. {
  26. ANKI_LOGW("Forgot to free memory");
  27. }
  28. m_blocks.destroy(m_alloc);
  29. m_freeBlocksStack.destroy(m_alloc);
  30. }
  31. //==============================================================================
  32. void GpuBlockAllocator::init(
  33. GenericMemoryPoolAllocator<U8> alloc, PtrSize totalSize, PtrSize blockSize)
  34. {
  35. ANKI_ASSERT(!isCreated());
  36. ANKI_ASSERT(totalSize > 0 && blockSize > 0);
  37. ANKI_ASSERT(totalSize > blockSize);
  38. ANKI_ASSERT((totalSize % blockSize) == 0);
  39. m_alloc = alloc;
  40. m_size = totalSize;
  41. m_blockSize = blockSize;
  42. m_blocks.create(alloc, totalSize / blockSize);
  43. m_freeBlocksStack.create(alloc, m_blocks.getSize());
  44. m_freeBlockCount = m_blocks.getSize();
  45. m_currentBlock = MAX_U32;
  46. U count = m_freeBlocksStack.getSize();
  47. for(U32& i : m_freeBlocksStack)
  48. {
  49. i = --count;
  50. }
  51. }
  52. //==============================================================================
  53. Bool GpuBlockAllocator::blockHasEnoughSpace(
  54. U blockIdx, PtrSize size, U alignment) const
  55. {
  56. ANKI_ASSERT(size > 0);
  57. const Block& block = m_blocks[blockIdx];
  58. PtrSize allocEnd = getAlignedRoundUp(alignment, block.m_offset) + size;
  59. PtrSize blockEnd = (blockIdx + 1) * m_blockSize;
  60. return allocEnd <= blockEnd;
  61. }
  62. //==============================================================================
  63. Error GpuBlockAllocator::allocate(
  64. PtrSize size, U alignment, DynamicBufferToken& handle, Bool handleOomError)
  65. {
  66. ANKI_ASSERT(isCreated());
  67. ANKI_ASSERT(size < m_blockSize);
  68. Block* block = nullptr;
  69. Error err = ErrorCode::NONE;
  70. LockGuard<Mutex> lock(m_mtx);
  71. if(m_currentBlock == MAX_U32
  72. || !blockHasEnoughSpace(m_currentBlock, size, alignment))
  73. {
  74. // Need new block
  75. if(m_freeBlockCount > 0)
  76. {
  77. // Pop block from free
  78. U blockIdx = --m_freeBlockCount;
  79. block = &m_blocks[blockIdx];
  80. block->m_offset = blockIdx * m_blockSize;
  81. ANKI_ASSERT(block->m_allocationCount == 0);
  82. // Make it in-use
  83. m_currentBlock = blockIdx;
  84. }
  85. }
  86. if(block)
  87. {
  88. PtrSize outOffset = getAlignedRoundUp(alignment, block->m_offset);
  89. block->m_offset = outOffset + size;
  90. ANKI_ASSERT(
  91. block->m_offset <= (block - &m_blocks[0] + 1) * m_blockSize);
  92. ++block->m_allocationCount;
  93. // Update the handle
  94. handle.m_offset = outOffset;
  95. handle.m_range = size;
  96. }
  97. else if(handleOomError)
  98. {
  99. ANKI_LOGF("Out of memory");
  100. }
  101. else
  102. {
  103. err = ErrorCode::OUT_OF_MEMORY;
  104. }
  105. return err;
  106. }
  107. //==============================================================================
  108. void GpuBlockAllocator::free(const DynamicBufferToken& handle)
  109. {
  110. ANKI_ASSERT(isCreated());
  111. ANKI_ASSERT(handle.m_range > 0);
  112. ANKI_ASSERT(handle.m_offset < m_size);
  113. U blockIdx = handle.m_offset / m_blockSize;
  114. LockGuard<Mutex> lock(m_mtx);
  115. ANKI_ASSERT(m_blocks[blockIdx].m_allocationCount > 0);
  116. if((--m_blocks[blockIdx].m_allocationCount) == 0)
  117. {
  118. // Block no longer in use
  119. if(m_currentBlock == blockIdx)
  120. {
  121. m_currentBlock = MAX_U32;
  122. }
  123. m_freeBlocksStack[m_freeBlockCount++] = blockIdx;
  124. }
  125. }
  126. } // end namespace anki