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-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
||||
// SPDX-License-Identifier: GPL-2.0-or-later |
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
#pragma once |
#pragma once |
||||
|
|
||||
|
#include <boost/container/stable_vector.hpp> |
||||
#include "core/frontend/emu_window.h" |
#include "core/frontend/emu_window.h" |
||||
#include "core/frontend/graphics_context.h" |
#include "core/frontend/graphics_context.h" |
||||
#include "shader_recompiler/frontend/ir/basic_block.h" |
#include "shader_recompiler/frontend/ir/basic_block.h" |
||||
#include "shader_recompiler/frontend/maxwell/control_flow.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 { |
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 { |
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; |
std::unique_ptr<Core::Frontend::GraphicsContext> gl_context; |
||||
Core::Frontend::GraphicsContext::Scoped scoped; |
Core::Frontend::GraphicsContext::Scoped scoped; |
||||
ShaderPools pools; |
|
||||
|
Shader::Maxwell::ShaderPools pools; |
||||
}; |
}; |
||||
|
|
||||
} // namespace OpenGL::ShaderContext |
} // namespace OpenGL::ShaderContext |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue