BsFrameAlloc.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsPrerequisitesUtil.h"
  5. namespace BansheeEngine
  6. {
  7. /** @cond INTERNAL */
  8. /** @addtogroup Memory
  9. * @{
  10. */
  11. /**
  12. * Frame allocator. Performs very fast allocations but can only free all of its memory at once. Perfect for allocations
  13. * that last just a single frame.
  14. *
  15. * @note Not thread safe with an exception. alloc() and clear() methods need to be called from the same thread.
  16. * dealloc() is thread safe and can be called from any thread.
  17. */
  18. class BS_UTILITY_EXPORT FrameAlloc
  19. {
  20. private:
  21. /** A single block of memory within a frame allocator. */
  22. class MemBlock
  23. {
  24. public:
  25. MemBlock(UINT32 size);
  26. ~MemBlock();
  27. /** Allocates a piece of memory within the block. Caller must ensure the block has enough empty space. */
  28. UINT8* alloc(UINT32 amount);
  29. /** Releases all allocations within a block but doesn't actually free the memory. */
  30. void clear();
  31. UINT8* mData;
  32. UINT32 mFreePtr;
  33. UINT32 mSize;
  34. };
  35. public:
  36. FrameAlloc(UINT32 blockSize = 1024 * 1024);
  37. ~FrameAlloc();
  38. /**
  39. * Allocates a new block of memory of the specified size.
  40. *
  41. * @param[in] amount Amount of memory to allocate, in bytes.
  42. *
  43. * @note Not thread safe.
  44. */
  45. UINT8* alloc(UINT32 amount);
  46. /**
  47. * Allocates a new block of memory of the specified size aligned to the specified boundary. If the aligment is less
  48. * or equal to 16 it is more efficient to use the allocAligned16() alternative of this method.
  49. *
  50. * @param[in] amount Amount of memory to allocate, in bytes.
  51. * @param[in] alignment Alignment of the allocated memory. Must be power of two.
  52. *
  53. * @note Not thread safe.
  54. */
  55. UINT8* allocAligned(UINT32 amount, UINT32 alignment);
  56. /**
  57. * Allocates and constructs a new object.
  58. *
  59. * @note Not thread safe.
  60. */
  61. template<class T, class... Args>
  62. T* alloc(Args &&...args)
  63. {
  64. return new ((T*)alloc(sizeof(T))) T(std::forward<Args>(args)...);
  65. }
  66. /**
  67. * Deallocates a previously allocated block of memory.
  68. *
  69. * @note
  70. * No deallocation is actually done here. This method is only used for debug purposes so it is easier to track
  71. * down memory leaks and corruption.
  72. * @note
  73. * Thread safe.
  74. */
  75. void dealloc(UINT8* data);
  76. /**
  77. * Deallocates and destructs a previously allocated object.
  78. *
  79. * @note
  80. * No deallocation is actually done here. This method is only used to call the destructor and for debug purposes
  81. * so it is easier to track down memory leaks and corruption.
  82. * @note
  83. * Thread safe.
  84. */
  85. template<class T>
  86. void dealloc(T* obj)
  87. {
  88. if (obj != nullptr)
  89. obj->~T();
  90. dealloc((UINT8*)obj);
  91. }
  92. /** Starts a new frame. Next call to ::clear will only clear memory allocated past this point. */
  93. void markFrame();
  94. /**
  95. * Deallocates all allocated memory since the last call to markFrame() (or all the memory if there was no call
  96. * to markFrame()).
  97. *
  98. * @note Not thread safe.
  99. */
  100. void clear();
  101. /**
  102. * Changes the frame allocator owner thread. After the owner thread has changed only allocations from that thread
  103. * can be made.
  104. */
  105. void setOwnerThread(BS_THREAD_ID_TYPE thread);
  106. private:
  107. UINT32 mBlockSize;
  108. Vector<MemBlock*> mBlocks;
  109. MemBlock* mFreeBlock;
  110. UINT32 mNextBlockIdx;
  111. std::atomic<UINT32> mTotalAllocBytes;
  112. void* mLastFrame;
  113. #if BS_DEBUG_MODE
  114. BS_THREAD_ID_TYPE mOwnerThread;
  115. #endif
  116. /**
  117. * Allocates a dynamic block of memory of the wanted size. The exact allocation size might be slightly higher in
  118. * order to store block meta data.
  119. */
  120. MemBlock* allocBlock(UINT32 wantedSize);
  121. /** Frees a memory block. */
  122. void deallocBlock(MemBlock* block);
  123. };
  124. /** Allocator for the standard library that internally uses a frame allocator. */
  125. template <class T>
  126. class StdFrameAlloc
  127. {
  128. public:
  129. typedef T value_type;
  130. StdFrameAlloc() noexcept
  131. :mFrameAlloc(nullptr)
  132. { }
  133. StdFrameAlloc(FrameAlloc* alloc) noexcept
  134. :mFrameAlloc(alloc)
  135. { }
  136. template<class T> StdFrameAlloc(const StdFrameAlloc<T>& alloc) noexcept
  137. :mFrameAlloc(alloc.mFrameAlloc)
  138. { }
  139. template<class T> bool operator==(const StdFrameAlloc<T>&) const noexcept { return true; }
  140. template<class T> bool operator!=(const StdFrameAlloc<T>&) const noexcept { return false; }
  141. /** Allocate but don't initialize number elements of type T.*/
  142. T* allocate(const size_t num) const
  143. {
  144. if (num == 0)
  145. return nullptr;
  146. if (num > static_cast<size_t>(-1) / sizeof(T))
  147. throw std::bad_array_new_length();
  148. void* const pv = mFrameAlloc->alloc((UINT32)(num * sizeof(T)));
  149. if (!pv)
  150. throw std::bad_alloc();
  151. return static_cast<T*>(pv);
  152. }
  153. /** Deallocate storage p of deleted elements. */
  154. void deallocate(T* p, size_t num) const noexcept
  155. {
  156. mFrameAlloc->dealloc((UINT8*)p);
  157. }
  158. FrameAlloc* mFrameAlloc;
  159. };
  160. /** Return that all specializations of this allocator are interchangeable. */
  161. template <class T1, class T2>
  162. bool operator== (const StdFrameAlloc<T1>&,
  163. const StdFrameAlloc<T2>&) throw() {
  164. return true;
  165. }
  166. /** Return that all specializations of this allocator are interchangeable. */
  167. template <class T1, class T2>
  168. bool operator!= (const StdFrameAlloc<T1>&,
  169. const StdFrameAlloc<T2>&) throw() {
  170. return false;
  171. }
  172. /** @} */
  173. /** @endcond */
  174. }