BsFrameAlloc.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #include "BsFrameAlloc.h"
  2. #include "BsException.h"
  3. namespace BansheeEngine
  4. {
  5. FrameAlloc::MemBlock::MemBlock(UINT32 size)
  6. :mData(nullptr), mFreePtr(0), mSize(size)
  7. { }
  8. FrameAlloc::MemBlock::~MemBlock()
  9. { }
  10. UINT8* FrameAlloc::MemBlock::alloc(UINT32 amount)
  11. {
  12. UINT8* freePtr = &mData[mFreePtr];
  13. mFreePtr += amount;
  14. return freePtr;
  15. }
  16. void FrameAlloc::MemBlock::clear()
  17. {
  18. mFreePtr = 0;
  19. }
  20. FrameAlloc::FrameAlloc(UINT32 blockSize)
  21. :mTotalAllocBytes(0), mFreeBlock(nullptr), mBlockSize(blockSize)
  22. {
  23. allocBlock(mBlockSize);
  24. }
  25. FrameAlloc::~FrameAlloc()
  26. {
  27. for(auto& block : mBlocks)
  28. deallocBlock(block);
  29. }
  30. UINT8* FrameAlloc::alloc(UINT32 amount)
  31. {
  32. #if BS_DEBUG_MODE
  33. assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
  34. amount += sizeof(UINT32) * 2;
  35. #endif
  36. UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
  37. if(amount > freeMem)
  38. allocBlock(amount);
  39. UINT8* data = mFreeBlock->alloc(amount);
  40. #if BS_DEBUG_MODE
  41. mTotalAllocBytes += amount;
  42. UINT32* storedSize = reinterpret_cast<UINT32*>(data);
  43. *storedSize = amount;
  44. UINT32* storedId = reinterpret_cast<UINT32*>(data + sizeof(UINT32));
  45. *storedId = mAllocId;
  46. mActiveAllocs.insert(mAllocId);
  47. mAllocId++;
  48. return data + sizeof(UINT32) * 2;
  49. #else
  50. return data;
  51. #endif
  52. }
  53. void FrameAlloc::dealloc(UINT8* data)
  54. {
  55. // Dealloc is only used for debug and can be removed if needed. All the actual deallocation
  56. // happens in "clear"
  57. #if BS_DEBUG_MODE
  58. data -= sizeof(UINT32) * 2;
  59. UINT32* storedSize = reinterpret_cast<UINT32*>(data);
  60. UINT32* storedId = reinterpret_cast<UINT32*>(data + sizeof(UINT32));
  61. mTotalAllocBytes -= *storedSize;
  62. mActiveAllocs.erase(*storedId);
  63. #endif
  64. }
  65. void FrameAlloc::clear()
  66. {
  67. #if BS_DEBUG_MODE
  68. assert(mOwnerThread == BS_THREAD_CURRENT_ID && "Frame allocator called from invalid thread.");
  69. if(mTotalAllocBytes.load() > 0)
  70. BS_EXCEPT(InvalidStateException, "Not all frame allocated bytes were properly released.");
  71. mAllocId = 0;
  72. mActiveAllocs.clear();
  73. #endif
  74. // Merge all blocks into one
  75. UINT32 totalBytes = 0;
  76. for(auto& block : mBlocks)
  77. {
  78. totalBytes += block->mSize;
  79. deallocBlock(block);
  80. }
  81. mBlocks.clear();
  82. allocBlock(totalBytes);
  83. }
  84. FrameAlloc::MemBlock* FrameAlloc::allocBlock(UINT32 wantedSize)
  85. {
  86. UINT32 blockSize = mBlockSize;
  87. if(wantedSize > blockSize)
  88. blockSize = wantedSize;
  89. UINT8* data = (UINT8*)reinterpret_cast<UINT8*>(bs_alloc(blockSize + sizeof(MemBlock)));
  90. MemBlock* newBlock = new (data) MemBlock(blockSize);
  91. data += sizeof(MemBlock);
  92. newBlock->mData = data;
  93. mBlocks.push_back(newBlock);
  94. mFreeBlock = newBlock; // If previous block had some empty space it is lost until next "clear"
  95. return newBlock;
  96. }
  97. void FrameAlloc::deallocBlock(MemBlock* block)
  98. {
  99. block->~MemBlock();
  100. bs_free(block);
  101. }
  102. }