BsFrameAlloc.cpp 2.9 KB

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