BsFrameAlloc.h 5.6 KB

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