BsFrameAlloc.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #pragma once
  2. #include "BsPrerequisitesUtil.h"
  3. namespace BansheeEngine
  4. {
  5. /**
  6. * @brief Frame allocator. Performs very fast allocations but can only free all of its memory at once.
  7. * Perfect for allocations that last just a single frame.
  8. *
  9. * @note Not thread safe with an exception. "alloc" and "clear" methods need to be called from the same thread.
  10. * "dealloc" is thread safe and can be called from any thread.
  11. */
  12. class BS_UTILITY_EXPORT FrameAlloc
  13. {
  14. private:
  15. /**
  16. * @brief A single block of memory within a frame allocator.
  17. */
  18. class MemBlock
  19. {
  20. public:
  21. MemBlock(UINT32 size);
  22. ~MemBlock();
  23. /**
  24. * @brief Allocates a piece of memory within the block. Caller must ensure
  25. * the block has enough empty space.
  26. */
  27. UINT8* alloc(UINT32 amount);
  28. /**
  29. * @brief Releases all allocations within a block but doesn't actually free the memory.
  30. */
  31. void clear();
  32. UINT8* mData;
  33. UINT32 mFreePtr;
  34. UINT32 mSize;
  35. };
  36. public:
  37. FrameAlloc(UINT32 blockSize = 1024 * 1024);
  38. ~FrameAlloc();
  39. /**
  40. * @brief Allocates a new block of memory of the specified size.
  41. *
  42. * @param amount Amount of memory to allocate, in bytes.
  43. *
  44. * @note Not thread safe.
  45. */
  46. UINT8* alloc(UINT32 amount);
  47. /**
  48. * @brief Allocates and constructs a new object.
  49. *
  50. * @note Not thread safe.
  51. */
  52. template<class T, class... Args>
  53. T* alloc(Args &&...args)
  54. {
  55. return new ((T*)alloc(sizeof(T))) T(std::forward<Args>(args)...);
  56. }
  57. /**
  58. * @brief Deallocates a previously allocated block of memory.
  59. *
  60. * @note No deallocation is actually done here. This method is only used for debug purposes
  61. * so it is easier to track down memory leaks and corruption.
  62. *
  63. * Thread safe.
  64. */
  65. void dealloc(UINT8* data);
  66. /**
  67. * @brief Deallocates and destructs a previously allocated object.
  68. *
  69. * @note No deallocation is actually done here. This method is only used to call the destructor
  70. * and for debug purposes so it is easier to track down memory leaks and corruption.
  71. *
  72. * Thread safe.
  73. */
  74. template<class T>
  75. void dealloc(T* obj)
  76. {
  77. if (obj != nullptr)
  78. obj->~T();
  79. dealloc((UINT8*)obj);
  80. }
  81. /**
  82. * @brief Starts a new frame. Next call to ::clear will only clear memory
  83. * allocated past this point.
  84. */
  85. void markFrame();
  86. /**
  87. * @brief Deallocates all allocated memory since the last call to ::markFrame
  88. * (or all the memory if there was no call to ::markFrame).
  89. *
  90. * @note Not thread safe.
  91. */
  92. void clear();
  93. /**
  94. * @brief Changes the frame allocator owner thread. After the owner
  95. * thread has changed only allocations from that thread can be made.
  96. */
  97. void setOwnerThread(BS_THREAD_ID_TYPE thread);
  98. private:
  99. UINT32 mBlockSize;
  100. Vector<MemBlock*> mBlocks;
  101. MemBlock* mFreeBlock;
  102. UINT32 mNextBlockIdx;
  103. std::atomic<UINT32> mTotalAllocBytes;
  104. void* mLastFrame;
  105. #if BS_DEBUG_MODE
  106. BS_THREAD_ID_TYPE mOwnerThread;
  107. #endif
  108. /**
  109. * @brief Allocates a dynamic block of memory of the wanted size. The exact allocation size
  110. * might be slightly higher in order to store block meta data.
  111. */
  112. MemBlock* allocBlock(UINT32 wantedSize);
  113. /**
  114. * @brief Frees a memory block.
  115. */
  116. void deallocBlock(MemBlock* block);
  117. };
  118. /**
  119. * @brief Allocator for the standard library that internally uses a
  120. * frame allocator.
  121. */
  122. template <class T>
  123. class StdFrameAlloc
  124. {
  125. public:
  126. // Type definitions
  127. typedef T value_type;
  128. typedef T* pointer;
  129. typedef const T* const_pointer;
  130. typedef T& reference;
  131. typedef const T& const_reference;
  132. typedef std::size_t size_type;
  133. typedef std::ptrdiff_t difference_type;
  134. /**
  135. * @brief Rebind allocator to type U
  136. */
  137. template <class U>
  138. struct rebind
  139. {
  140. typedef StdFrameAlloc<U> other;
  141. };
  142. StdFrameAlloc() throw()
  143. :mFrameAlloc(nullptr)
  144. { }
  145. StdFrameAlloc(FrameAlloc* frameAlloc) throw()
  146. :mFrameAlloc(frameAlloc)
  147. { }
  148. StdFrameAlloc(const StdFrameAlloc& alloc) throw()
  149. :mFrameAlloc(alloc.mFrameAlloc)
  150. { }
  151. template <class U>
  152. StdFrameAlloc(const StdFrameAlloc<U>& alloc) throw()
  153. :mFrameAlloc(alloc.mFrameAlloc)
  154. { }
  155. ~StdFrameAlloc() throw()
  156. { }
  157. /**
  158. * @brief Return address of value.
  159. */
  160. pointer address(reference value) const
  161. {
  162. return &value;
  163. }
  164. /**
  165. * @brief Return address of value.
  166. */
  167. const_pointer address(const_reference value) const
  168. {
  169. return &value;
  170. }
  171. /**
  172. * @brief Return maximum number of elements that can be allocated.
  173. */
  174. size_type max_size() const throw()
  175. {
  176. return std::numeric_limits<std::size_t>::max() / sizeof(T);
  177. }
  178. /**
  179. * @brief Allocate but don't initialize number elements of type T.
  180. */
  181. pointer allocate(size_type num, const void* = 0)
  182. {
  183. pointer ret = (pointer)(mFrameAlloc->alloc((UINT32)num*sizeof(T)));
  184. return ret;
  185. }
  186. /**
  187. * @brief Initialize elements of allocated storage p with value "value".
  188. */
  189. void construct(pointer p, const T& value)
  190. {
  191. new((void*)p)T(value);
  192. }
  193. /**
  194. * @brief Destroy elements of initialized storage p.
  195. */
  196. void destroy(pointer p)
  197. {
  198. p->~T();
  199. }
  200. /**
  201. * @brief Deallocate storage p of deleted elements.
  202. */
  203. void deallocate(pointer p, size_type num)
  204. {
  205. mFrameAlloc->dealloc((UINT8*)p);
  206. }
  207. FrameAlloc* mFrameAlloc;
  208. };
  209. /**
  210. * @brief Return that all specializations of this allocator are interchangeable.
  211. */
  212. template <class T1, class T2>
  213. bool operator== (const StdFrameAlloc<T1>&,
  214. const StdFrameAlloc<T2>&) throw() {
  215. return true;
  216. }
  217. /**
  218. * @brief Return that all specializations of this allocator are interchangeable.
  219. */
  220. template <class T1, class T2>
  221. bool operator!= (const StdFrameAlloc<T1>&,
  222. const StdFrameAlloc<T2>&) throw() {
  223. return false;
  224. }
  225. }