2021-02-05 20:11:23 -06:00
|
|
|
// Copyright 2021 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <type_traits>
|
2021-02-05 23:38:22 -06:00
|
|
|
#include <utility>
|
2021-02-05 20:11:23 -06:00
|
|
|
|
|
|
|
namespace Shader {
|
|
|
|
|
2021-02-14 21:09:11 -06:00
|
|
|
template <typename T>
|
2021-02-05 20:11:23 -06:00
|
|
|
requires std::is_destructible_v<T> class ObjectPool {
|
|
|
|
public:
|
2021-02-14 21:09:11 -06:00
|
|
|
explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
|
|
|
|
node = &chunks.emplace_back(new_chunk_size);
|
2021-02-05 20:11:23 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... Args>
|
2021-04-10 01:32:55 -05:00
|
|
|
requires std::is_constructible_v<T, Args...>[[nodiscard]] T* Create(Args&&... args) {
|
2021-02-05 20:11:23 -06:00
|
|
|
return std::construct_at(Memory(), std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReleaseContents() {
|
2021-02-14 21:09:11 -06:00
|
|
|
if (chunks.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Chunk& root{chunks.front()};
|
|
|
|
if (root.used_objects == root.num_objects) {
|
|
|
|
// Root chunk has been filled, squash allocations into it
|
|
|
|
const size_t total_objects{root.num_objects + new_chunk_size * (chunks.size() - 1)};
|
|
|
|
chunks.clear();
|
|
|
|
chunks.emplace_back(total_objects);
|
|
|
|
} else {
|
|
|
|
root.Release();
|
|
|
|
chunks.resize(1);
|
2021-02-05 20:11:23 -06:00
|
|
|
}
|
2021-03-23 20:07:14 -05:00
|
|
|
chunks.shrink_to_fit();
|
|
|
|
node = &chunks.front();
|
2021-02-05 20:11:23 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
struct NonTrivialDummy {
|
|
|
|
NonTrivialDummy() noexcept {}
|
|
|
|
};
|
|
|
|
|
|
|
|
union Storage {
|
|
|
|
Storage() noexcept {}
|
|
|
|
~Storage() noexcept {}
|
|
|
|
|
|
|
|
NonTrivialDummy dummy{};
|
|
|
|
T object;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Chunk {
|
2021-02-14 21:09:11 -06:00
|
|
|
explicit Chunk() = default;
|
|
|
|
explicit Chunk(size_t size)
|
|
|
|
: num_objects{size}, storage{std::make_unique<Storage[]>(size)} {}
|
|
|
|
|
|
|
|
Chunk& operator=(Chunk&& rhs) noexcept {
|
|
|
|
Release();
|
|
|
|
used_objects = std::exchange(rhs.used_objects, 0);
|
|
|
|
num_objects = std::exchange(rhs.num_objects, 0);
|
|
|
|
storage = std::move(rhs.storage);
|
|
|
|
}
|
|
|
|
|
|
|
|
Chunk(Chunk&& rhs) noexcept
|
|
|
|
: used_objects{std::exchange(rhs.used_objects, 0)},
|
|
|
|
num_objects{std::exchange(rhs.num_objects, 0)}, storage{std::move(rhs.storage)} {}
|
|
|
|
|
|
|
|
~Chunk() {
|
|
|
|
Release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Release() {
|
|
|
|
std::destroy_n(storage.get(), used_objects);
|
|
|
|
used_objects = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t used_objects{};
|
|
|
|
size_t num_objects{};
|
|
|
|
std::unique_ptr<Storage[]> storage;
|
2021-02-05 20:11:23 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
[[nodiscard]] T* Memory() {
|
|
|
|
Chunk* const chunk{FreeChunk()};
|
2021-02-14 21:09:11 -06:00
|
|
|
return &chunk->storage[chunk->used_objects++].object;
|
2021-02-05 20:11:23 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] Chunk* FreeChunk() {
|
2021-02-14 21:09:11 -06:00
|
|
|
if (node->used_objects != node->num_objects) {
|
2021-02-05 20:11:23 -06:00
|
|
|
return node;
|
|
|
|
}
|
2021-02-14 21:09:11 -06:00
|
|
|
node = &chunks.emplace_back(new_chunk_size);
|
2021-02-05 20:11:23 -06:00
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2021-02-14 21:09:11 -06:00
|
|
|
Chunk* node{};
|
|
|
|
std::vector<Chunk> chunks;
|
|
|
|
size_t new_chunk_size{};
|
2021-02-05 20:11:23 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace Shader
|