diff options
| -rw-r--r-- | src/shader_recompiler/frontend/ir/structured_control_flow.cpp | 10 | ||||
| -rw-r--r-- | src/shader_recompiler/main.cpp | 22 | ||||
| -rw-r--r-- | src/shader_recompiler/object_pool.h | 84 |
3 files changed, 66 insertions, 50 deletions
diff --git a/src/shader_recompiler/frontend/ir/structured_control_flow.cpp b/src/shader_recompiler/frontend/ir/structured_control_flow.cpp index 2e9ce2525..d145095d1 100644 --- a/src/shader_recompiler/frontend/ir/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/ir/structured_control_flow.cpp | |||
| @@ -269,7 +269,7 @@ bool SearchNode(const Tree& tree, ConstNode stmt, size_t& offset) { | |||
| 269 | 269 | ||
| 270 | class GotoPass { | 270 | class GotoPass { |
| 271 | public: | 271 | public: |
| 272 | explicit GotoPass(std::span<Block* const> blocks, ObjectPool<Statement, 64>& stmt_pool) | 272 | explicit GotoPass(std::span<Block* const> blocks, ObjectPool<Statement>& stmt_pool) |
| 273 | : pool{stmt_pool} { | 273 | : pool{stmt_pool} { |
| 274 | std::vector gotos{BuildUnorderedTreeGetGotos(blocks)}; | 274 | std::vector gotos{BuildUnorderedTreeGetGotos(blocks)}; |
| 275 | fmt::print(stdout, "BEFORE\n{}\n", DumpTree(root_stmt.children)); | 275 | fmt::print(stdout, "BEFORE\n{}\n", DumpTree(root_stmt.children)); |
| @@ -554,7 +554,7 @@ private: | |||
| 554 | return offset; | 554 | return offset; |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | ObjectPool<Statement, 64>& pool; | 557 | ObjectPool<Statement>& pool; |
| 558 | Statement root_stmt{FunctionTag{}}; | 558 | Statement root_stmt{FunctionTag{}}; |
| 559 | }; | 559 | }; |
| 560 | 560 | ||
| @@ -589,7 +589,7 @@ Block* TryFindForwardBlock(const Statement& stmt) { | |||
| 589 | class TranslatePass { | 589 | class TranslatePass { |
| 590 | public: | 590 | public: |
| 591 | TranslatePass(ObjectPool<Inst>& inst_pool_, ObjectPool<Block>& block_pool_, | 591 | TranslatePass(ObjectPool<Inst>& inst_pool_, ObjectPool<Block>& block_pool_, |
| 592 | ObjectPool<Statement, 64>& stmt_pool_, Statement& root_stmt, | 592 | ObjectPool<Statement>& stmt_pool_, Statement& root_stmt, |
| 593 | const std::function<void(IR::Block*)>& func_, BlockList& block_list_) | 593 | const std::function<void(IR::Block*)>& func_, BlockList& block_list_) |
| 594 | : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, func{func_}, | 594 | : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, func{func_}, |
| 595 | block_list{block_list_} { | 595 | block_list{block_list_} { |
| @@ -720,7 +720,7 @@ private: | |||
| 720 | return block; | 720 | return block; |
| 721 | } | 721 | } |
| 722 | 722 | ||
| 723 | ObjectPool<Statement, 64>& stmt_pool; | 723 | ObjectPool<Statement>& stmt_pool; |
| 724 | ObjectPool<Inst>& inst_pool; | 724 | ObjectPool<Inst>& inst_pool; |
| 725 | ObjectPool<Block>& block_pool; | 725 | ObjectPool<Block>& block_pool; |
| 726 | const std::function<void(IR::Block*)>& func; | 726 | const std::function<void(IR::Block*)>& func; |
| @@ -731,7 +731,7 @@ private: | |||
| 731 | BlockList VisitAST(ObjectPool<Inst>& inst_pool, ObjectPool<Block>& block_pool, | 731 | BlockList VisitAST(ObjectPool<Inst>& inst_pool, ObjectPool<Block>& block_pool, |
| 732 | std::span<Block* const> unordered_blocks, | 732 | std::span<Block* const> unordered_blocks, |
| 733 | const std::function<void(Block*)>& func) { | 733 | const std::function<void(Block*)>& func) { |
| 734 | ObjectPool<Statement, 64> stmt_pool; | 734 | ObjectPool<Statement> stmt_pool{64}; |
| 735 | GotoPass goto_pass{unordered_blocks, stmt_pool}; | 735 | GotoPass goto_pass{unordered_blocks, stmt_pool}; |
| 736 | BlockList block_list; | 736 | BlockList block_list; |
| 737 | TranslatePass translate_pass{inst_pool, block_pool, stmt_pool, goto_pass.RootStatement(), | 737 | TranslatePass translate_pass{inst_pool, block_pool, stmt_pool, goto_pass.RootStatement(), |
diff --git a/src/shader_recompiler/main.cpp b/src/shader_recompiler/main.cpp index 3b110af61..216345e91 100644 --- a/src/shader_recompiler/main.cpp +++ b/src/shader_recompiler/main.cpp | |||
| @@ -37,7 +37,7 @@ void RunDatabase() { | |||
| 37 | ForEachFile("D:\\Shaders\\Database", [&](const std::filesystem::path& path) { | 37 | ForEachFile("D:\\Shaders\\Database", [&](const std::filesystem::path& path) { |
| 38 | map.emplace_back(std::make_unique<FileEnvironment>(path.string().c_str())); | 38 | map.emplace_back(std::make_unique<FileEnvironment>(path.string().c_str())); |
| 39 | }); | 39 | }); |
| 40 | auto block_pool{std::make_unique<ObjectPool<Flow::Block>>()}; | 40 | ObjectPool<Flow::Block> block_pool; |
| 41 | using namespace std::chrono; | 41 | using namespace std::chrono; |
| 42 | auto t0 = high_resolution_clock::now(); | 42 | auto t0 = high_resolution_clock::now(); |
| 43 | int N = 1; | 43 | int N = 1; |
| @@ -48,8 +48,8 @@ void RunDatabase() { | |||
| 48 | // fmt::print(stdout, "Decoding {}\n", path.string()); | 48 | // fmt::print(stdout, "Decoding {}\n", path.string()); |
| 49 | 49 | ||
| 50 | const Location start_address{0}; | 50 | const Location start_address{0}; |
| 51 | block_pool->ReleaseContents(); | 51 | block_pool.ReleaseContents(); |
| 52 | Flow::CFG cfg{*env, *block_pool, start_address}; | 52 | Flow::CFG cfg{*env, block_pool, start_address}; |
| 53 | // fmt::print(stdout, "{}\n", cfg->Dot()); | 53 | // fmt::print(stdout, "{}\n", cfg->Dot()); |
| 54 | // IR::Program program{env, cfg}; | 54 | // IR::Program program{env, cfg}; |
| 55 | // Optimize(program); | 55 | // Optimize(program); |
| @@ -63,18 +63,18 @@ void RunDatabase() { | |||
| 63 | int main() { | 63 | int main() { |
| 64 | // RunDatabase(); | 64 | // RunDatabase(); |
| 65 | 65 | ||
| 66 | auto flow_block_pool{std::make_unique<ObjectPool<Flow::Block>>()}; | 66 | ObjectPool<Flow::Block> flow_block_pool; |
| 67 | auto inst_pool{std::make_unique<ObjectPool<IR::Inst>>()}; | 67 | ObjectPool<IR::Inst> inst_pool; |
| 68 | auto block_pool{std::make_unique<ObjectPool<IR::Block>>()}; | 68 | ObjectPool<IR::Block> block_pool; |
| 69 | 69 | ||
| 70 | // FileEnvironment env{"D:\\Shaders\\Database\\Oninaki\\CS8F146B41DB6BD826.bin"}; | 70 | // FileEnvironment env{"D:\\Shaders\\Database\\Oninaki\\CS8F146B41DB6BD826.bin"}; |
| 71 | FileEnvironment env{"D:\\Shaders\\shader.bin"}; | 71 | FileEnvironment env{"D:\\Shaders\\shader.bin"}; |
| 72 | block_pool->ReleaseContents(); | 72 | block_pool.ReleaseContents(); |
| 73 | inst_pool->ReleaseContents(); | 73 | inst_pool.ReleaseContents(); |
| 74 | flow_block_pool->ReleaseContents(); | 74 | flow_block_pool.ReleaseContents(); |
| 75 | Flow::CFG cfg{env, *flow_block_pool, 0}; | 75 | Flow::CFG cfg{env, flow_block_pool, 0}; |
| 76 | fmt::print(stdout, "{}\n", cfg.Dot()); | 76 | fmt::print(stdout, "{}\n", cfg.Dot()); |
| 77 | IR::Program program{TranslateProgram(*inst_pool, *block_pool, env, cfg)}; | 77 | IR::Program program{TranslateProgram(inst_pool, block_pool, env, cfg)}; |
| 78 | fmt::print(stdout, "{}\n", IR::DumpProgram(program)); | 78 | fmt::print(stdout, "{}\n", IR::DumpProgram(program)); |
| 79 | Backend::SPIRV::EmitSPIRV spirv{program}; | 79 | Backend::SPIRV::EmitSPIRV spirv{program}; |
| 80 | } | 80 | } |
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 |