yuzu/src/shader_recompiler/object_pool.h

107 lines
2.8 KiB
C++
Raw Normal View History

// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
2021-02-05 18:11:23 -08:00
#pragma once
#include <memory>
#include <type_traits>
2021-02-05 21:38:22 -08:00
#include <utility>
2021-02-05 18:11:23 -08:00
namespace Shader {
2021-02-14 19:09:11 -08:00
template <typename T>
requires std::is_destructible_v<T>
class ObjectPool {
2021-02-05 18:11:23 -08:00
public:
2021-02-14 19:09:11 -08:00
explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
node = &chunks.emplace_back(new_chunk_size);
2021-02-05 18:11:23 -08:00
}
template <typename... Args>
requires std::is_constructible_v<T, Args...>
[[nodiscard]] T* Create(Args&&... args) {
2021-02-05 18:11:23 -08:00
return std::construct_at(Memory(), std::forward<Args>(args)...);
}
void ReleaseContents() {
2021-02-14 19:09:11 -08: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 18:11:23 -08:00
}
chunks.shrink_to_fit();
node = &chunks.front();
2021-02-05 18:11:23 -08:00
}
private:
struct NonTrivialDummy {
NonTrivialDummy() noexcept {}
};
union Storage {
Storage() noexcept {}
~Storage() noexcept {}
NonTrivialDummy dummy{};
T object;
};
struct Chunk {
2021-02-14 19:09:11 -08: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);
return *this;
2021-02-14 19:09:11 -08:00
}
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 18:11:23 -08:00
};
[[nodiscard]] T* Memory() {
Chunk* const chunk{FreeChunk()};
2021-02-14 19:09:11 -08:00
return &chunk->storage[chunk->used_objects++].object;
2021-02-05 18:11:23 -08:00
}
[[nodiscard]] Chunk* FreeChunk() {
2021-02-14 19:09:11 -08:00
if (node->used_objects != node->num_objects) {
2021-02-05 18:11:23 -08:00
return node;
}
2021-02-14 19:09:11 -08:00
node = &chunks.emplace_back(new_chunk_size);
2021-02-05 18:11:23 -08:00
return node;
}
2021-02-14 19:09:11 -08:00
Chunk* node{};
std::vector<Chunk> chunks;
size_t new_chunk_size{};
2021-02-05 18:11:23 -08:00
};
} // namespace Shader