diff options
| author | 2021-02-15 00:09:11 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:22 -0400 | |
| commit | d5d468cf2cbe235ee149dbd37951389d2a7e61da (patch) | |
| tree | e99fe0e09c130d6171add858f6e9520d6b3948d5 /src/shader_recompiler/object_pool.h | |
| parent | shader: Fix tracking (diff) | |
| download | yuzu-d5d468cf2cbe235ee149dbd37951389d2a7e61da.tar.gz yuzu-d5d468cf2cbe235ee149dbd37951389d2a7e61da.tar.xz yuzu-d5d468cf2cbe235ee149dbd37951389d2a7e61da.zip | |
shader: Improve object pool
Diffstat (limited to 'src/shader_recompiler/object_pool.h')
| -rw-r--r-- | src/shader_recompiler/object_pool.h | 84 |
1 files changed, 50 insertions, 34 deletions
diff --git a/src/shader_recompiler/object_pool.h b/src/shader_recompiler/object_pool.h index a573add32..f78813b5f 100644 --- a/src/shader_recompiler/object_pool.h +++ b/src/shader_recompiler/object_pool.h | |||
| @@ -10,19 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | namespace Shader { | 11 | namespace Shader { |
| 12 | 12 | ||
| 13 | template <typename T, size_t chunk_size = 8192> | 13 | template <typename T> |
| 14 | requires std::is_destructible_v<T> class ObjectPool { | 14 | requires std::is_destructible_v<T> class ObjectPool { |
| 15 | public: | 15 | public: |
| 16 | ~ObjectPool() { | 16 | explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} { |
| 17 | std::unique_ptr<Chunk> tree_owner; | 17 | node = &chunks.emplace_back(new_chunk_size); |
| 18 | Chunk* chunk{&root}; | ||
| 19 | while (chunk) { | ||
| 20 | for (size_t obj_id = chunk->free_objects; obj_id < chunk_size; ++obj_id) { | ||
| 21 | chunk->storage[obj_id].object.~T(); | ||
| 22 | } | ||
| 23 | tree_owner = std::move(chunk->next); | ||
| 24 | chunk = tree_owner.get(); | ||
| 25 | } | ||
| 26 | } | 18 | } |
| 27 | 19 | ||
| 28 | template <typename... Args> | 20 | template <typename... Args> |
| @@ -31,17 +23,21 @@ public: | |||
| 31 | } | 23 | } |
| 32 | 24 | ||
| 33 | void ReleaseContents() { | 25 | void ReleaseContents() { |
| 34 | Chunk* chunk{&root}; | 26 | if (chunks.empty()) { |
| 35 | while (chunk) { | 27 | return; |
| 36 | if (chunk->free_objects == chunk_size) { | 28 | } |
| 37 | break; | 29 | Chunk& root{chunks.front()}; |
| 38 | } | 30 | if (root.used_objects == root.num_objects) { |
| 39 | for (; chunk->free_objects < chunk_size; ++chunk->free_objects) { | 31 | // Root chunk has been filled, squash allocations into it |
| 40 | chunk->storage[chunk->free_objects].object.~T(); | 32 | const size_t total_objects{root.num_objects + new_chunk_size * (chunks.size() - 1)}; |
| 41 | } | 33 | chunks.clear(); |
| 42 | chunk = chunk->next.get(); | 34 | chunks.emplace_back(total_objects); |
| 35 | chunks.shrink_to_fit(); | ||
| 36 | } else { | ||
| 37 | root.Release(); | ||
| 38 | chunks.resize(1); | ||
| 39 | chunks.shrink_to_fit(); | ||
| 43 | } | 40 | } |
| 44 | node = &root; | ||
| 45 | } | 41 | } |
| 46 | 42 | ||
| 47 | private: | 43 | private: |
| @@ -58,31 +54,51 @@ private: | |||
| 58 | }; | 54 | }; |
| 59 | 55 | ||
| 60 | struct Chunk { | 56 | struct Chunk { |
| 61 | size_t free_objects = chunk_size; | 57 | explicit Chunk() = default; |
| 62 | std::array<Storage, chunk_size> storage; | 58 | explicit Chunk(size_t size) |
| 63 | std::unique_ptr<Chunk> next; | 59 | : num_objects{size}, storage{std::make_unique<Storage[]>(size)} {} |
| 60 | |||
| 61 | Chunk& operator=(Chunk&& rhs) noexcept { | ||
| 62 | Release(); | ||
| 63 | used_objects = std::exchange(rhs.used_objects, 0); | ||
| 64 | num_objects = std::exchange(rhs.num_objects, 0); | ||
| 65 | storage = std::move(rhs.storage); | ||
| 66 | } | ||
| 67 | |||
| 68 | Chunk(Chunk&& rhs) noexcept | ||
| 69 | : used_objects{std::exchange(rhs.used_objects, 0)}, | ||
| 70 | num_objects{std::exchange(rhs.num_objects, 0)}, storage{std::move(rhs.storage)} {} | ||
| 71 | |||
| 72 | ~Chunk() { | ||
| 73 | Release(); | ||
| 74 | } | ||
| 75 | |||
| 76 | void Release() { | ||
| 77 | std::destroy_n(storage.get(), used_objects); | ||
| 78 | used_objects = 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | size_t used_objects{}; | ||
| 82 | size_t num_objects{}; | ||
| 83 | std::unique_ptr<Storage[]> storage; | ||
| 64 | }; | 84 | }; |
| 65 | 85 | ||
| 66 | [[nodiscard]] T* Memory() { | 86 | [[nodiscard]] T* Memory() { |
| 67 | Chunk* const chunk{FreeChunk()}; | 87 | Chunk* const chunk{FreeChunk()}; |
| 68 | return &chunk->storage[--chunk->free_objects].object; | 88 | return &chunk->storage[chunk->used_objects++].object; |
| 69 | } | 89 | } |
| 70 | 90 | ||
| 71 | [[nodiscard]] Chunk* FreeChunk() { | 91 | [[nodiscard]] Chunk* FreeChunk() { |
| 72 | if (node->free_objects > 0) { | 92 | if (node->used_objects != node->num_objects) { |
| 73 | return node; | ||
| 74 | } | ||
| 75 | if (node->next) { | ||
| 76 | node = node->next.get(); | ||
| 77 | return node; | 93 | return node; |
| 78 | } | 94 | } |
| 79 | node->next = std::make_unique<Chunk>(); | 95 | node = &chunks.emplace_back(new_chunk_size); |
| 80 | node = node->next.get(); | ||
| 81 | return node; | 96 | return node; |
| 82 | } | 97 | } |
| 83 | 98 | ||
| 84 | Chunk* node{&root}; | 99 | Chunk* node{}; |
| 85 | Chunk root; | 100 | std::vector<Chunk> chunks; |
| 101 | size_t new_chunk_size{}; | ||
| 86 | }; | 102 | }; |
| 87 | 103 | ||
| 88 | } // namespace Shader | 104 | } // namespace Shader |