Browse Source
[shader_recompiler] use reusable stable_vector<> instead of object pools
[shader_recompiler] use reusable stable_vector<> instead of object pools
Signed-off-by: lizzie <lizzie@eden-emu.dev>lizzie/stable-shader-pools
17 changed files with 313 additions and 491 deletions
-
5src/shader_recompiler/CMakeLists.txt
-
17src/shader_recompiler/frontend/ir/basic_block.cpp
-
8src/shader_recompiler/frontend/ir/basic_block.h
-
22src/shader_recompiler/frontend/maxwell/control_flow.cpp
-
27src/shader_recompiler/frontend/maxwell/control_flow.h
-
269src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
-
9src/shader_recompiler/frontend/maxwell/structured_control_flow.h
-
19src/shader_recompiler/frontend/maxwell/translate_program.cpp
-
20src/shader_recompiler/frontend/maxwell/translate_program.h
-
106src/shader_recompiler/object_pool.h
-
134src/shader_recompiler/shader_pool.h
-
33src/video_core/renderer_opengl/gl_shader_cache.cpp
-
20src/video_core/renderer_opengl/gl_shader_cache.h
-
23src/video_core/renderer_opengl/gl_shader_context.h
-
62src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
-
25src/video_core/renderer_vulkan/vk_pipeline_cache.h
-
5src/video_core/shader_cache.cpp
@ -1,106 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <type_traits> |
|||
#include <utility> |
|||
|
|||
namespace Shader { |
|||
|
|||
template <typename T> |
|||
requires std::is_destructible_v<T> |
|||
class ObjectPool { |
|||
public: |
|||
explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} { |
|||
node = &chunks.emplace_back(new_chunk_size); |
|||
} |
|||
|
|||
template <typename... Args> |
|||
requires std::is_constructible_v<T, Args...> |
|||
[[nodiscard]] T* Create(Args&&... args) { |
|||
return std::construct_at(Memory(), std::forward<Args>(args)...); |
|||
} |
|||
|
|||
void ReleaseContents() { |
|||
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); |
|||
} |
|||
chunks.shrink_to_fit(); |
|||
node = &chunks.front(); |
|||
} |
|||
|
|||
private: |
|||
struct NonTrivialDummy { |
|||
NonTrivialDummy() noexcept {} |
|||
}; |
|||
|
|||
union Storage { |
|||
Storage() noexcept {} |
|||
~Storage() noexcept {} |
|||
|
|||
NonTrivialDummy dummy{}; |
|||
T object; |
|||
}; |
|||
|
|||
struct Chunk { |
|||
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; |
|||
} |
|||
|
|||
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; |
|||
}; |
|||
|
|||
[[nodiscard]] T* Memory() { |
|||
Chunk* const chunk{FreeChunk()}; |
|||
return &chunk->storage[chunk->used_objects++].object; |
|||
} |
|||
|
|||
[[nodiscard]] Chunk* FreeChunk() { |
|||
if (node->used_objects != node->num_objects) { |
|||
return node; |
|||
} |
|||
node = &chunks.emplace_back(new_chunk_size); |
|||
return node; |
|||
} |
|||
|
|||
Chunk* node{}; |
|||
std::vector<Chunk> chunks; |
|||
size_t new_chunk_size{}; |
|||
}; |
|||
|
|||
} // namespace Shader |
|||
@ -0,0 +1,134 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <boost/container/stable_vector.hpp> |
|||
#include <boost/intrusive/list.hpp> |
|||
#include "shader_recompiler/frontend/maxwell/control_flow.h" |
|||
|
|||
namespace Shader::Maxwell { |
|||
|
|||
struct Statement; |
|||
|
|||
// Use normal_link because we are not guaranteed to destroy the tree in order |
|||
using ListBaseHook = boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>; |
|||
using Tree = boost::intrusive::list<Statement, |
|||
// Allow using Statement without a definition |
|||
boost::intrusive::base_hook<ListBaseHook>, |
|||
// Avoid linear complexity on splice, size is never called |
|||
boost::intrusive::constant_time_size<false>>; |
|||
using Node = Tree::iterator; |
|||
|
|||
enum class StatementType { |
|||
Code, |
|||
Goto, |
|||
Label, |
|||
If, |
|||
Loop, |
|||
Break, |
|||
Return, |
|||
Kill, |
|||
Unreachable, |
|||
Function, |
|||
Identity, |
|||
Not, |
|||
Or, |
|||
SetVariable, |
|||
SetIndirectBranchVariable, |
|||
Variable, |
|||
IndirectBranchCond, |
|||
}; |
|||
|
|||
[[nodiscard]] inline bool HasChildren(StatementType type) { |
|||
switch (type) { |
|||
case StatementType::If: |
|||
case StatementType::Loop: |
|||
case StatementType::Function: |
|||
return true; |
|||
default: |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
struct Goto {}; |
|||
struct Label {}; |
|||
struct If {}; |
|||
struct Loop {}; |
|||
struct Break {}; |
|||
struct Return {}; |
|||
struct Kill {}; |
|||
struct Unreachable {}; |
|||
struct FunctionTag {}; |
|||
struct Identity {}; |
|||
struct Not {}; |
|||
struct Or {}; |
|||
struct SetVariable {}; |
|||
struct SetIndirectBranchVariable {}; |
|||
struct Variable {}; |
|||
struct IndirectBranchCond {}; |
|||
|
|||
#ifdef _MSC_VER |
|||
#pragma warning(push) |
|||
#pragma warning(disable : 26495) // Always initialize a member variable, expected in Statement |
|||
#endif |
|||
struct Statement : ListBaseHook { |
|||
Statement(const Flow::Block* block_, Statement* up_) : block{block_}, up{up_}, type{StatementType::Code} {} |
|||
Statement(Goto, Statement* cond_, Node label_, Statement* up_) : label{label_}, cond{cond_}, up{up_}, type{StatementType::Goto} {} |
|||
Statement(Label, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Label} {} |
|||
Statement(If, Statement* cond_, Tree&& children_, Statement* up_) : children{std::move(children_)}, cond{cond_}, up{up_}, type{StatementType::If} {} |
|||
Statement(Loop, Statement* cond_, Tree&& children_, Statement* up_) : children{std::move(children_)}, cond{cond_}, up{up_}, type{StatementType::Loop} {} |
|||
Statement(Break, Statement* cond_, Statement* up_) : cond{cond_}, up{up_}, type{StatementType::Break} {} |
|||
Statement(Return, Statement* up_) : up{up_}, type{StatementType::Return} {} |
|||
Statement(Kill, Statement* up_) : up{up_}, type{StatementType::Kill} {} |
|||
Statement(Unreachable, Statement* up_) : up{up_}, type{StatementType::Unreachable} {} |
|||
Statement(FunctionTag) : children{}, type{StatementType::Function} {} |
|||
Statement(Identity, IR::Condition cond_, Statement* up_) : guest_cond{cond_}, up{up_}, type{StatementType::Identity} {} |
|||
Statement(Not, Statement* op_, Statement* up_) : op{op_}, up{up_}, type{StatementType::Not} {} |
|||
Statement(Or, Statement* op_a_, Statement* op_b_, Statement* up_) : op_a{op_a_}, op_b{op_b_}, up{up_}, type{StatementType::Or} {} |
|||
Statement(SetVariable, u32 id_, Statement* op_, Statement* up_) : op{op_}, id{id_}, up{up_}, type{StatementType::SetVariable} {} |
|||
Statement(SetIndirectBranchVariable, IR::Reg branch_reg_, s32 branch_offset_, Statement* up_) : branch_offset{branch_offset_}, branch_reg{branch_reg_}, up{up_}, type{StatementType::SetIndirectBranchVariable} {} |
|||
Statement(Variable, u32 id_, Statement* up_) : id{id_}, up{up_}, type{StatementType::Variable} {} |
|||
Statement(IndirectBranchCond, u32 location_, Statement* up_) : location{location_}, up{up_}, type{StatementType::IndirectBranchCond} {} |
|||
~Statement() { |
|||
if (HasChildren(type)) { |
|||
std::destroy_at(&children); |
|||
} |
|||
} |
|||
union { |
|||
const Flow::Block* block; |
|||
Node label; |
|||
Tree children; |
|||
IR::Condition guest_cond; |
|||
Statement* op; |
|||
Statement* op_a; |
|||
u32 location; |
|||
s32 branch_offset; |
|||
}; |
|||
union { |
|||
Statement* cond; |
|||
Statement* op_b; |
|||
u32 id; |
|||
IR::Reg branch_reg; |
|||
}; |
|||
Statement* up{}; |
|||
StatementType type; |
|||
}; |
|||
#ifdef _MSC_VER |
|||
#pragma warning(pop) |
|||
#endif |
|||
|
|||
struct ShaderPools { |
|||
void clear() { |
|||
flow_block.clear(); |
|||
block.clear(); |
|||
inst.clear(); |
|||
stmt.clear(); |
|||
} |
|||
boost::container::stable_vector<Shader::IR::Inst> inst{}; |
|||
boost::container::stable_vector<Shader::IR::Block> block{}; |
|||
boost::container::stable_vector<Shader::Maxwell::Flow::Block> flow_block{}; |
|||
boost::container::stable_vector<Shader::Maxwell::Statement> stmt; |
|||
}; |
|||
|
|||
} |
|||
@ -1,33 +1,26 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <boost/container/stable_vector.hpp> |
|||
#include "core/frontend/emu_window.h" |
|||
#include "core/frontend/graphics_context.h" |
|||
#include "shader_recompiler/frontend/ir/basic_block.h" |
|||
#include "shader_recompiler/frontend/maxwell/control_flow.h" |
|||
#include "shader_recompiler/frontend/maxwell/structured_control_flow.h" |
|||
#include "shader_recompiler/frontend/maxwell/translate_program.h" |
|||
|
|||
namespace OpenGL::ShaderContext { |
|||
struct ShaderPools { |
|||
void ReleaseContents() { |
|||
flow_block.ReleaseContents(); |
|||
block.ReleaseContents(); |
|||
inst.ReleaseContents(); |
|||
} |
|||
|
|||
Shader::ObjectPool<Shader::IR::Inst> inst{8192}; |
|||
Shader::ObjectPool<Shader::IR::Block> block{32}; |
|||
Shader::ObjectPool<Shader::Maxwell::Flow::Block> flow_block{32}; |
|||
}; |
|||
|
|||
struct Context { |
|||
explicit Context(Core::Frontend::EmuWindow& emu_window) |
|||
: gl_context{emu_window.CreateSharedContext()}, scoped{*gl_context} {} |
|||
|
|||
explicit Context(Core::Frontend::EmuWindow& emu_window) : gl_context{emu_window.CreateSharedContext()}, scoped{*gl_context} {} |
|||
std::unique_ptr<Core::Frontend::GraphicsContext> gl_context; |
|||
Core::Frontend::GraphicsContext::Scoped scoped; |
|||
ShaderPools pools; |
|||
Shader::Maxwell::ShaderPools pools; |
|||
}; |
|||
|
|||
} // namespace OpenGL::ShaderContext |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue