BsFrameAlloc.cpp 2.6 KB

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