From a90698c0fe0ddb04db78c5001463f4ca417cf0af Mon Sep 17 00:00:00 2001 From: Ubpa Date: Thu, 12 Nov 2020 00:10:07 +0800 Subject: [PATCH] RandomAccessor --- CMakeLists.txt | 2 +- doc/changelog.md | 8 ++ doc/todo.md | 2 +- include/UECS/.txt | 0 include/UECS/CmptType.h | 7 +- include/UECS/RandomAccessor.h | 12 ++ include/UECS/Schedule.h | 13 +- include/UECS/World.h | 4 +- include/UECS/detail/Schedule.inl | 15 +- include/UECS/detail/SystemFunc.h | 8 +- include/UECS/detail/SystemFunc.inl | 9 +- include/UECS/detail/World.inl | 6 +- src/core/Schedule.cpp | 219 +++++++++++++++++++++++------ src/core/SysFuncGraph.cpp | 8 +- src/core/World.cpp | 194 ++++++++++++++----------- src/test/21_random/CMakeLists.txt | 6 + src/test/21_random/main.cpp | 86 +++++++++++ 17 files changed, 442 insertions(+), 157 deletions(-) create mode 100644 include/UECS/.txt create mode 100644 include/UECS/RandomAccessor.h create mode 100644 src/test/21_random/CMakeLists.txt create mode 100644 src/test/21_random/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c2618a..4bee6b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(UECS VERSION 0.14.1) +project(UECS VERSION 0.14.2) message(STATUS "[Project] ${PROJECT_NAME}") include(cmake/InitUCMake.cmake) diff --git a/doc/changelog.md b/doc/changelog.md index 4a1f0fb..5654a9e 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -1,4 +1,12 @@ # Change Log +- 0.14.2 + - add `RandomAccessor` for random access other entity's component + - `SystemFunc` add the member + - `Schedule::Register*` add the parameter + - feature `None Parallel` is updated to support `RandomAccessor` + - `World::GenUpdateFrameGraph` is updated to support `RandomAccessor` + - `CmptAccessType`'s default `AccessMode` change from `LATEST` to `WRITE` + - `World` command buffer layer's type change from `size_t` to `int` - 0.14.1: `CmptAccessMode` remove singleton - 0.14.0: System Lifecycle \ No newline at end of file diff --git a/doc/todo.md b/doc/todo.md index d8094da..7762b92 100644 --- a/doc/todo.md +++ b/doc/todo.md @@ -29,7 +29,7 @@ - [x] system base -> `System` - [x] singleton - [ ] doxygen -- [ ] lock / random access +- [x] random access - [x] system traits ### maybe support in future diff --git a/include/UECS/.txt b/include/UECS/.txt new file mode 100644 index 0000000..e69de29 diff --git a/include/UECS/CmptType.h b/include/UECS/CmptType.h index 292e417..b5b9100 100644 --- a/include/UECS/CmptType.h +++ b/include/UECS/CmptType.h @@ -42,13 +42,12 @@ namespace Ubpa::UECS { // CmptType with AccessMode class CmptAccessType { public: - constexpr CmptAccessType(size_t id, AccessMode mode) noexcept + constexpr CmptAccessType(size_t id, AccessMode mode = AccessMode::WRITE) noexcept : type{ id }, mode{ mode } {} - constexpr CmptAccessType(std::string_view type_name, AccessMode mode) noexcept + constexpr CmptAccessType(std::string_view type_name, AccessMode mode = AccessMode::WRITE) noexcept : type{ RuntimeTypeID(type_name) }, mode{ mode } {} - constexpr CmptAccessType(CmptType type, AccessMode mode) noexcept + constexpr CmptAccessType(CmptType type, AccessMode mode = AccessMode::WRITE) noexcept : type{ type }, mode{ mode } {} - explicit constexpr CmptAccessType(CmptType type) noexcept : CmptAccessType{ type, AccessMode::LATEST } {} explicit constexpr CmptAccessType() noexcept : CmptAccessType{ Invalid() } {} template diff --git a/include/UECS/RandomAccessor.h b/include/UECS/RandomAccessor.h new file mode 100644 index 0000000..eccbcf2 --- /dev/null +++ b/include/UECS/RandomAccessor.h @@ -0,0 +1,12 @@ +#pragma once + +#include "CmptType.h" + +#include + +namespace Ubpa::UECS { + class RandomAccessor { + public: + CmptAccessTypeSet types; + }; +} diff --git a/include/UECS/Schedule.h b/include/UECS/Schedule.h index 3bb601f..2f00434 100644 --- a/include/UECS/Schedule.h +++ b/include/UECS/Schedule.h @@ -40,7 +40,8 @@ namespace Ubpa::UECS { bool isParallel = true, ArchetypeFilter = {}, CmptLocator = {}, - SingletonLocator = {} + SingletonLocator = {}, + RandomAccessor = {} ); // Func's argument list: @@ -54,7 +55,8 @@ namespace Ubpa::UECS { std::string name, ArchetypeFilter = {}, bool isParallel = true, - SingletonLocator = {} + SingletonLocator = {}, + RandomAccessor = {} ); // Func's argument list: @@ -65,10 +67,11 @@ namespace Ubpa::UECS { const SystemFunc* RegisterJob( Func&&, std::string name, - SingletonLocator = {} + SingletonLocator = {}, + RandomAccessor = {} ); - void RegisterCommand(std::function command, size_t layer = 0) { + void RegisterCommand(std::function command, int layer = 0) { commandBuffer[layer].push_back(std::move(command)); } @@ -109,7 +112,7 @@ namespace Ubpa::UECS { std::unordered_map sysFilterChange; std::unordered_set sysLockFilter; - std::map>> commandBuffer; + std::map>> commandBuffer; Pool sysFuncPool; friend class World; diff --git a/include/UECS/World.h b/include/UECS/World.h index 18b503a..f44f968 100644 --- a/include/UECS/World.h +++ b/include/UECS/World.h @@ -30,7 +30,7 @@ namespace Ubpa::UECS { // 4. run commands in main thread void Update(); - void AddCommand(std::function command, size_t layer = 0); + void AddCommand(std::function command, int layer = 0); // after running Update() // you can use graphviz to vistualize the graph @@ -120,7 +120,7 @@ namespace Ubpa::UECS { Pool jobPool; // command - std::map>> commandBuffer; + std::map>> commandBuffer; std::mutex commandBufferMutex; void RunCommands(); diff --git a/include/UECS/detail/Schedule.inl b/include/UECS/detail/Schedule.inl index dd7225e..de2039e 100644 --- a/include/UECS/detail/Schedule.inl +++ b/include/UECS/detail/Schedule.inl @@ -8,7 +8,8 @@ namespace Ubpa::UECS { bool isParallel, ArchetypeFilter filter, CmptLocator cmptLocator, - SingletonLocator singletonLocator + SingletonLocator singletonLocator, + RandomAccessor randomAccessor ) { return Request( std::forward(func), @@ -16,24 +17,26 @@ namespace Ubpa::UECS { std::move(filter), std::move(cmptLocator), std::move(singletonLocator), + std::move(randomAccessor), isParallel ); } - template const SystemFunc* Schedule::RegisterChunkJob( Func&& func, std::string name, ArchetypeFilter filter, bool isParallel, - SingletonLocator singletonLocator + SingletonLocator singletonLocator, + RandomAccessor randomAccessor ) { return Request( std::forward(func), std::move(name), std::move(filter), std::move(singletonLocator), + std::move(randomAccessor), isParallel ); } @@ -42,12 +45,14 @@ namespace Ubpa::UECS { const SystemFunc* Schedule::RegisterJob( Func&& func, std::string name, - SingletonLocator singletonLocator + SingletonLocator singletonLocator, + RandomAccessor randomAccessor ) { return Request( std::forward(func), std::move(name), - std::move(singletonLocator) + std::move(singletonLocator), + std::move(randomAccessor) ); } diff --git a/include/UECS/detail/SystemFunc.h b/include/UECS/detail/SystemFunc.h index d3e7372..0511d0a 100644 --- a/include/UECS/detail/SystemFunc.h +++ b/include/UECS/detail/SystemFunc.h @@ -2,6 +2,7 @@ #include "../EntityQuery.h" #include "../SingletonLocator.h" +#include "../RandomAccessor.h" #include "../Entity.h" #include "../CmptsView.h" #include "../SingletonsView.h" @@ -37,18 +38,19 @@ namespace Ubpa::UECS { EntityQuery entityQuery; SingletonLocator singletonLocator; + RandomAccessor randomAccessor; // Mode::Entity template - SystemFunc(Func&&, std::string name, ArchetypeFilter, CmptLocator, SingletonLocator, bool isParallel); + SystemFunc(Func&&, std::string name, ArchetypeFilter, CmptLocator, SingletonLocator, RandomAccessor, bool isParallel); // Mode::Chunk template - SystemFunc(Func&&, std::string name, ArchetypeFilter, SingletonLocator, bool isParallel); + SystemFunc(Func&&, std::string name, ArchetypeFilter, SingletonLocator, RandomAccessor, bool isParallel); // Mode::Job template - SystemFunc(Func&&, std::string name, SingletonLocator); + SystemFunc(Func&&, std::string name, SingletonLocator, RandomAccessor); const std::string& Name() const noexcept { return name; } diff --git a/include/UECS/detail/SystemFunc.inl b/include/UECS/detail/SystemFunc.inl index d6c9079..31de399 100644 --- a/include/UECS/detail/SystemFunc.inl +++ b/include/UECS/detail/SystemFunc.inl @@ -16,10 +16,12 @@ namespace Ubpa::UECS { ArchetypeFilter archetypeFilter, CmptLocator cmptLocator, SingletonLocator singletonLocator, + RandomAccessor randomAccessor, bool isParallel ) : entityQuery{ std::move(archetypeFilter), std::move(cmptLocator.Combine()) }, singletonLocator{ std::move(singletonLocator.Combine()) }, + randomAccessor{std::move(randomAccessor)}, mode{ Mode::Entity }, name{ std::move(name) }, hashCode{ HashCode(this->name) }, @@ -44,10 +46,12 @@ namespace Ubpa::UECS { std::string name, ArchetypeFilter archetypeFilter, SingletonLocator singletonLocator, + RandomAccessor randomAccessor, bool isParallel ) : entityQuery{ std::move(archetypeFilter) }, singletonLocator{ std::move(singletonLocator.Combine()) }, + randomAccessor{ std::move(randomAccessor) }, mode{ Mode::Chunk }, name{ std::move(name) }, hashCode{ HashCode(this->name) }, @@ -76,9 +80,10 @@ namespace Ubpa::UECS { // Mode::Job template - SystemFunc::SystemFunc(Func&& func, std::string name, SingletonLocator singletonLocator) + SystemFunc::SystemFunc(Func&& func, std::string name, SingletonLocator singletonLocator, RandomAccessor randomAccessor) : singletonLocator{ std::move(singletonLocator.Combine()) }, + randomAccessor {std::move(randomAccessor)}, mode{ Mode::Job }, name{ std::move(name) }, hashCode{ HashCode(this->name) }, @@ -96,7 +101,7 @@ namespace Ubpa::UECS { && !Contain_v && !Contain_v, "(Mode::Job) SystemFunc's argument list cann't have Entity, indexInQuery CmptsView or ChunkView" - ); + ); } } diff --git a/include/UECS/detail/World.inl b/include/UECS/detail/World.inl index 9b5861d..3b332c6 100644 --- a/include/UECS/detail/World.inl +++ b/include/UECS/detail/World.inl @@ -15,7 +15,8 @@ namespace Ubpa::UECS { std::move(filter), std::move(cmptLocator), std::move(singletonLocator), - std::move(isParallel) + {}, + isParallel }; Run(&sys); } @@ -57,7 +58,8 @@ namespace Ubpa::UECS { "", std::move(filter), std::move(singletonLocator), - std::move(isParallel) + {}, + isParallel }; Run(&sys); } diff --git a/src/core/Schedule.cpp b/src/core/Schedule.cpp index 59743a4..af1ab83 100644 --- a/src/core/Schedule.cpp +++ b/src/core/Schedule.cpp @@ -13,35 +13,138 @@ namespace Ubpa::UECS::detail { NoneGroup(SystemFunc* func) : sysFuncs{ func } { - needTypes = SetUnion(func->entityQuery.filter.all, func->entityQuery.filter.any); - needTypes = SetUnion(needTypes, func->entityQuery.locator.CmptAccessTypes()); + allTypes = SetUnion(func->entityQuery.filter.all, func->entityQuery.locator.CmptAccessTypes()); + anyTypes = func->entityQuery.filter.any; + randomTypes = func->randomAccessor.types; noneTypes = func->entityQuery.filter.none; } static bool Parallelable(const NoneGroup& x, const NoneGroup& y) { - /*return !SetIntersection(x.needTypes, y.noneTypes).empty() - || !SetIntersection(y.needTypes, x.noneTypes).empty();*/ - { - auto x_iter = x.needTypes.begin(); - auto y_iter = y.noneTypes.begin(); - while (x_iter != x.needTypes.end() && y_iter != y.noneTypes.end()) { - if (x_iter->GetCmptType() < *y_iter) - ++x_iter; - else if (x_iter->GetCmptType() > * y_iter) + //{ // subgraph + // const NoneGroup& minG = x.sysFuncs.size() < y.sysFuncs.size() ? x : y; + // const NoneGroup& maxG = x.sysFuncs.size() < y.sysFuncs.size() ? y : x; + // bool flag = true; + // for(auto* f : minG.sysFuncs) { + // if(maxG.sysFuncs.find(f) == maxG.sysFuncs.end()) { + // flag = false; + // break; + // } + // } + // if (flag) + // return true; + //} + if (y.randomTypes.empty()) { // y.none + bool allFlag = false; + bool anyFlag = true; + bool randomFlag = true; + + { // all + auto x_iter = x.allTypes.begin(); + auto y_iter = y.noneTypes.begin(); + while (x_iter != x.allTypes.end() && y_iter != y.noneTypes.end()) { + if (x_iter->GetCmptType() < *y_iter) + ++x_iter; + else if (x_iter->GetCmptType() > * y_iter) + ++y_iter; + else { // == + allFlag = true; + break; + } + } + } + if (!allFlag) { + if (x.anyTypes.empty()) + anyFlag = false; + else { + // any + auto x_iter = x.anyTypes.begin(); + auto y_iter = y.noneTypes.begin(); + while (x_iter != x.anyTypes.end() && y_iter != y.noneTypes.end()) { + if (x_iter->GetCmptType() < *y_iter) { + anyFlag = false; + break; + } + + if (x_iter->GetCmptType() == *y_iter) + ++x_iter; + + ++y_iter; + } + } + } + if (allFlag || anyFlag) { + // random + auto x_iter = x.randomTypes.begin(); + auto y_iter = y.noneTypes.begin(); + while (x_iter != x.randomTypes.end() && y_iter != y.noneTypes.end()) { + if (x_iter->GetCmptType() < *y_iter) { + randomFlag = false; + break; + } + + if (x_iter->GetCmptType() == *y_iter) + ++x_iter; + ++y_iter; - else // == + } + if (randomFlag) return true; } } - { - auto x_iter = x.noneTypes.begin(); - auto y_iter = y.needTypes.begin(); - while (x_iter != x.noneTypes.end() && y_iter != y.needTypes.end()) { - if (*x_iter < y_iter->GetCmptType()) + if (x.randomTypes.empty()) { // x.none + bool allFlag = false; + bool anyFlag = true; + bool randomFlag = true; + { // all + auto x_iter = x.noneTypes.begin(); + auto y_iter = y.allTypes.begin(); + while (x_iter != x.noneTypes.end() && y_iter != y.allTypes.end()) { + if (*x_iter < y_iter->GetCmptType()) + ++x_iter; + else if (*x_iter > y_iter->GetCmptType()) + ++y_iter; + else { // == + allFlag = true; + break; + } + } + } + if (!allFlag) { + // any + if (y.anyTypes.empty()) + anyFlag = false; + else { + auto x_iter = x.noneTypes.begin(); + auto y_iter = y.anyTypes.begin(); + while (x_iter != x.noneTypes.end() && y_iter != y.anyTypes.end()) { + if (y_iter->GetCmptType() < *x_iter) { + anyFlag = false; + break; + } + + if (y_iter->GetCmptType() == *x_iter) + ++y_iter; + + ++x_iter; + } + } + } + if (allFlag || anyFlag) { + // random + auto x_iter = x.noneTypes.begin(); + auto y_iter = y.randomTypes.begin(); + while (x_iter != x.noneTypes.end() && y_iter != y.randomTypes.end()) { + if (y_iter->GetCmptType() < *x_iter) { + randomFlag = false; + break; + } + + if (y_iter->GetCmptType() == *x_iter) + ++y_iter; + ++x_iter; - else if (*x_iter > y_iter->GetCmptType()) - ++y_iter; - else // == + } + if (randomFlag) return true; } } @@ -49,13 +152,18 @@ namespace Ubpa::UECS::detail { } NoneGroup& operator+=(const NoneGroup& y) { - needTypes = SetIntersection(needTypes, y.needTypes); + allTypes = SetIntersection(allTypes, y.allTypes); + anyTypes = SetUnion(anyTypes, y.anyTypes); + anyTypes = SetUnion(anyTypes, SetSymmetricDifference(allTypes, y.allTypes)); + randomTypes = SetUnion(randomTypes, y.randomTypes); noneTypes = SetIntersection(noneTypes, y.noneTypes); sysFuncs = SetUnion(sysFuncs, y.sysFuncs); return *this; } - set> needTypes; + CmptAccessTypeSet allTypes; + CmptAccessTypeSet anyTypes; + CmptAccessTypeSet randomTypes; set noneTypes; set sysFuncs; }; @@ -69,6 +177,9 @@ namespace Ubpa::UECS::detail { const auto& writers = cmptFuncs.writeSysFuncs; const auto& postReaders = cmptFuncs.latestSysFuncs; + if (writers.empty()) + return; + if (!preReaders.empty()) { NoneGroup preGroup{ gMap.at(preReaders.front()) }; for (size_t i = 1; i < preReaders.size(); i++) @@ -77,7 +188,7 @@ namespace Ubpa::UECS::detail { for (const auto& w : writers) { if (NoneGroup::Parallelable(preGroup, gMap.at(w))) continue; - for (auto preReader : preReaders) + for (auto* preReader : preReaders) graph.AddEdge(preReader, w); } } @@ -90,13 +201,14 @@ namespace Ubpa::UECS::detail { for (const auto& w : writers) { if (NoneGroup::Parallelable(postGroup, gMap.at(w))) continue; - for (auto postReader : postReaders) + for (auto* postReader : postReaders) graph.AddEdge(w, postReader); } } } - static vector GenSortNoneGroup(SysFuncGraph graph, + static vector GenSortNoneGroup( + const SysFuncGraph& graph, const Schedule::CmptSysFuncs& cmptFuncs, const unordered_map& gMap) { @@ -123,7 +235,7 @@ namespace Ubpa::UECS::detail { funcs.push_back(*preGroup.sysFuncs.begin()); if (!postGroup.sysFuncs.empty()) funcs.push_back(*postGroup.sysFuncs.begin()); - for (auto w : writers) + for (auto* w : writers) funcs.push_back(w); auto subgraph = graph.SubGraph(funcs); @@ -132,7 +244,7 @@ namespace Ubpa::UECS::detail { vector rst; - for (auto func : sortedFuncs) { + for (auto* func : sortedFuncs) { if (!preGroup.sysFuncs.empty() && func == *preGroup.sysFuncs.begin()) rst.push_back(move(preGroup)); else if (!postGroup.sysFuncs.empty() && func == *postGroup.sysFuncs.begin()) @@ -149,8 +261,8 @@ namespace Ubpa::UECS::detail { continue; bool haveOrder = false; - for (auto ifunc : gi.sysFuncs) { - for (auto jfunc : gj.sysFuncs) { + for (auto* ifunc : gi.sysFuncs) { + for (auto* jfunc : gj.sysFuncs) { if (subgraph.HavePath(ifunc, jfunc) || subgraph.HavePath(jfunc, ifunc)) { haveOrder = true; @@ -204,18 +316,18 @@ void Schedule::Clear() { } unordered_map Schedule::GenCmptSysFuncsMap() const { - unordered_map rst; + unordered_map rst; for (const auto& [hashcode, sysFunc] : sysFuncs) { for (const auto& type : sysFunc->entityQuery.locator.CmptAccessTypes()) { switch (type.GetAccessMode()) { - case Ubpa::UECS::AccessMode::LAST_FRAME: + case AccessMode::LAST_FRAME: rst[type].lastFrameSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::WRITE: + case AccessMode::WRITE: rst[type].writeSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::LATEST: + case AccessMode::LATEST: rst[type].latestSysFuncs.push_back(sysFunc); break; default: @@ -226,13 +338,30 @@ unordered_map Schedule::GenCmptSysFuncsMap() c for (const auto& type : sysFunc->singletonLocator.SingletonTypes()) { switch (type.GetAccessMode()) { - case Ubpa::UECS::AccessMode::LAST_FRAME: + case AccessMode::LAST_FRAME: + rst[type].lastFrameSysFuncs.push_back(sysFunc); + break; + case AccessMode::WRITE: + rst[type].writeSysFuncs.push_back(sysFunc); + break; + case AccessMode::LATEST: + rst[type].latestSysFuncs.push_back(sysFunc); + break; + default: + assert(false); + break; + } + } + for (const auto& type : sysFunc->randomAccessor.types) { + switch (type.GetAccessMode()) + { + case AccessMode::LAST_FRAME: rst[type].lastFrameSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::WRITE: + case AccessMode::WRITE: rst[type].writeSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::LATEST: + case AccessMode::LATEST: rst[type].latestSysFuncs.push_back(sysFunc); break; default: @@ -247,13 +376,13 @@ unordered_map Schedule::GenCmptSysFuncsMap() c auto& cmptSysFuncs = rst[type]; switch (type.GetAccessMode()) { - case Ubpa::UECS::AccessMode::LAST_FRAME: + case AccessMode::LAST_FRAME: cmptSysFuncs.lastFrameSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::WRITE: + case AccessMode::WRITE: cmptSysFuncs.writeSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::LATEST: + case AccessMode::LATEST: cmptSysFuncs.latestSysFuncs.push_back(sysFunc); break; default: @@ -266,13 +395,13 @@ unordered_map Schedule::GenCmptSysFuncsMap() c auto& cmptSysFuncs = rst[type]; switch (type.GetAccessMode()) { - case Ubpa::UECS::AccessMode::LAST_FRAME: + case AccessMode::LAST_FRAME: cmptSysFuncs.lastFrameSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::WRITE: + case AccessMode::WRITE: cmptSysFuncs.writeSysFuncs.push_back(sysFunc); break; - case Ubpa::UECS::AccessMode::LATEST: + case AccessMode::LATEST: cmptSysFuncs.latestSysFuncs.push_back(sysFunc); break; default: @@ -295,7 +424,7 @@ SysFuncGraph Schedule::GenSysFuncGraph() const { if (target == sysFuncs.end()) continue; - auto func = target->second; + auto* func = target->second; for (const auto& type : change.insertNones) func->entityQuery.filter.none.insert(type); @@ -326,8 +455,8 @@ SysFuncGraph Schedule::GenSysFuncGraph() const { if (target_y == sysFuncs.end()) continue; - auto sysFunc_x = target_x->second; - auto sysFunc_y = target_y->second; + auto* sysFunc_x = target_x->second; + auto* sysFunc_y = target_y->second; graph.AddEdge(sysFunc_x, sysFunc_y); } diff --git a/src/core/SysFuncGraph.cpp b/src/core/SysFuncGraph.cpp index 7295752..1ad3caf 100644 --- a/src/core/SysFuncGraph.cpp +++ b/src/core/SysFuncGraph.cpp @@ -31,7 +31,8 @@ bool SysFuncGraph::HaveEdge(SystemFunc* x, SystemFunc* y) const { bool SysFuncGraph::HavePath(SystemFunc* x, SystemFunc* y) const { assert(HaveVertex(x) && HaveVertex(y)); - assert(x != y); + //if (x == y) + // return false; // acyclic unordered_set visited; queue q; @@ -52,12 +53,15 @@ bool SysFuncGraph::HavePath(SystemFunc* x, SystemFunc* y) const { } void SysFuncGraph::AddVertex(SystemFunc* x) { - assert(!HaveVertex(x)); + if (HaveVertex(x)) + return; adjList.emplace(x, unordered_set{}); } void SysFuncGraph::AddEdge(SystemFunc* x, SystemFunc* y) { assert(HaveVertex(x) && HaveVertex(y)); + if (x == y) + return; adjList[x].insert(y); } diff --git a/src/core/World.cpp b/src/core/World.cpp index 835cd68..c258bf7 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -99,15 +99,29 @@ UGraphviz::Graph World::GenUpdateFrameGraph() const { auto& subgraph_singleton = graph.GenSubgraph("Singleton Nodes"); auto& subgraph_sys = graph.GenSubgraph("System Function Nodes"); + auto& subgraph_basic = graph.GenSubgraph("Basic Edges"); auto& subgraph_lastframe = graph.GenSubgraph("LastFrame Edges"); auto& subgraph_write = graph.GenSubgraph("Write Edges"); auto& subgraph_latest = graph.GenSubgraph("Latest Edges"); - auto& subgraph_order = graph.GenSubgraph("Order Edges"); - auto& subgraph_all = graph.GenSubgraph("All Edges"); - auto& subgraph_any = graph.GenSubgraph("Any Edges"); - auto& subgraph_none = graph.GenSubgraph("None Edges"); + auto& subgraph_basic_all = subgraph_basic.GenSubgraph("Basic All Edges"); + auto& subgraph_basic_any = subgraph_basic.GenSubgraph("Basic Any Edges"); + + auto& subgraph_lastframe_all = subgraph_lastframe.GenSubgraph("LastFrame All Edges"); + auto& subgraph_lastframe_any = subgraph_lastframe.GenSubgraph("LastFrame Any Edges"); + + auto& subgraph_write_all = subgraph_write.GenSubgraph("Write All Edges"); + auto& subgraph_write_any = subgraph_write.GenSubgraph("Write Any Edges"); + + auto& subgraph_latest_all = subgraph_latest.GenSubgraph("Latest All Edges"); + auto& subgraph_latest_any = subgraph_latest.GenSubgraph("Latest Any Edges"); + + auto& subgraph_none = subgraph_basic.GenSubgraph("None Edges"); + + auto& subgraph_lastframe_random = subgraph_lastframe.GenSubgraph("LastFrame Random Edges"); + auto& subgraph_write_random = subgraph_write.GenSubgraph("Write Random Edges"); + auto& subgraph_latest_random = subgraph_latest.GenSubgraph("Latest Random Edges"); subgraph_cmpt .RegisterGraphNodeAttr("shape", "ellipse") @@ -121,26 +135,57 @@ UGraphviz::Graph World::GenUpdateFrameGraph() const { .RegisterGraphNodeAttr("shape", "box") .RegisterGraphNodeAttr("color", "#F79646"); + subgraph_basic.RegisterGraphEdgeAttr("color", "#C785C8"); subgraph_lastframe.RegisterGraphEdgeAttr("color", "#60C5F1"); subgraph_write.RegisterGraphEdgeAttr("color", "#F47378"); subgraph_latest.RegisterGraphEdgeAttr("color", "#6BD089"); - subgraph_order.RegisterGraphEdgeAttr("color", "#00A2E8"); - subgraph_all + subgraph_basic_all + .RegisterGraphEdgeAttr("style", "dashed") + .RegisterGraphEdgeAttr("arrowhead", "box"); + subgraph_lastframe_all + .RegisterGraphEdgeAttr("style", "dashed") + .RegisterGraphEdgeAttr("arrowhead", "box"); + subgraph_write_all .RegisterGraphEdgeAttr("style", "dashed") - .RegisterGraphEdgeAttr("color", "#C785C8") - .RegisterGraphEdgeAttr("arrowhead", "crow"); + .RegisterGraphEdgeAttr("arrowhead", "box"); + subgraph_latest_all + .RegisterGraphEdgeAttr("style", "dashed") + .RegisterGraphEdgeAttr("arrowhead", "box"); - subgraph_any + subgraph_basic_any + .RegisterGraphEdgeAttr("style", "dashed") + .RegisterGraphEdgeAttr("arrowhead", "diamond"); + subgraph_lastframe_any + .RegisterGraphEdgeAttr("style", "dashed") + .RegisterGraphEdgeAttr("arrowhead", "diamond"); + subgraph_write_any + .RegisterGraphEdgeAttr("style", "dashed") + .RegisterGraphEdgeAttr("arrowhead", "diamond"); + subgraph_latest_any .RegisterGraphEdgeAttr("style", "dashed") - .RegisterGraphEdgeAttr("color", "#C785C8") .RegisterGraphEdgeAttr("arrowhead", "diamond"); subgraph_none .RegisterGraphEdgeAttr("style", "dashed") - .RegisterGraphEdgeAttr("color", "#C785C8") .RegisterGraphEdgeAttr("arrowhead", "odot"); + + subgraph_lastframe_random + .RegisterGraphEdgeAttr("style", "dotted") + .RegisterGraphEdgeAttr("dir", "both") + .RegisterGraphEdgeAttr("arrowhead", "curve") + .RegisterGraphEdgeAttr("arrowtail", "tee"); + subgraph_write_random + .RegisterGraphEdgeAttr("style", "dotted") + .RegisterGraphEdgeAttr("dir", "both") + .RegisterGraphEdgeAttr("arrowhead", "curve") + .RegisterGraphEdgeAttr("arrowtail", "tee"); + subgraph_latest_random + .RegisterGraphEdgeAttr("style", "dotted") + .RegisterGraphEdgeAttr("dir", "both") + .RegisterGraphEdgeAttr("arrowhead", "curve") + .RegisterGraphEdgeAttr("arrowtail", "tee"); unordered_set cmptTypes; unordered_set singletonTypes; @@ -205,93 +250,72 @@ UGraphviz::Graph World::GenUpdateFrameGraph() const { } } - const auto& filter = sysFunc->entityQuery.filter; - if (sysFunc->GetMode() == SystemFunc::Mode::Chunk) { - // filter's and components are treat as r/w - for (const auto& cmptType : filter.all) { - auto cmptIdx = cmptType2idx.at(cmptType); - size_t edgeIdx; - switch (cmptType.GetAccessMode()) - { - case AccessMode::LAST_FRAME: - edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); - subgraph_lastframe.AddEdge(edgeIdx); - break; - case AccessMode::WRITE: - edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); - subgraph_write.AddEdge(edgeIdx); - break; - case AccessMode::LATEST: - edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); - subgraph_latest.AddEdge(edgeIdx); - break; - default: - assert(false); - break; - } - } - for (const auto& cmptType : filter.any) { - auto cmptIdx = cmptType2idx.at(cmptType); - size_t edgeIdx; - switch (cmptType.GetAccessMode()) - { - case AccessMode::LAST_FRAME: - edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); - subgraph_lastframe.AddEdge(edgeIdx); - break; - case AccessMode::WRITE: - edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); - subgraph_write.AddEdge(edgeIdx); - break; - case AccessMode::LATEST: - edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); - subgraph_latest.AddEdge(edgeIdx); - break; - default: - assert(false); - break; - } + const bool isChunk = sysFunc->GetMode() == SystemFunc::Mode::Chunk; + + for (const auto& cmptType : sysFunc->entityQuery.filter.all) { + size_t edgeIdx; + switch (cmptType.GetAccessMode()) + { + case AccessMode::LAST_FRAME: + edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); + (isChunk ? subgraph_lastframe_all : subgraph_basic_all).AddEdge(edgeIdx); + break; + case AccessMode::WRITE: + edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); + (isChunk ? subgraph_write_all : subgraph_basic_all).AddEdge(edgeIdx); + break; + case AccessMode::LATEST: + edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); + (isChunk ? subgraph_latest_all : subgraph_basic_all).AddEdge(edgeIdx); + break; + default: + assert(false); + break; } } - else { - for (const auto& cmptType : filter.all) { - auto cmptIdx = cmptType2idx.at(cmptType); - if (registry.IsRegisteredEdge(sysIdx, cmptIdx)) - continue; - auto edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); - subgraph_all.AddEdge(edgeIdx); - } - for (const auto& cmptType : filter.any) { - auto cmptIdx = cmptType2idx.at(cmptType); - if (registry.IsRegisteredEdge(sysIdx, cmptIdx)) - continue; - auto edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); - subgraph_any.AddEdge(edgeIdx); + + for (const auto& cmptType : sysFunc->entityQuery.filter.any) { + size_t edgeIdx; + switch (cmptType.GetAccessMode()) + { + case AccessMode::LAST_FRAME: + edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); + (isChunk ? subgraph_lastframe_any : subgraph_basic_any).AddEdge(edgeIdx); + break; + case AccessMode::WRITE: + edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); + (isChunk ? subgraph_write_any : subgraph_basic_any).AddEdge(edgeIdx); + break; + case AccessMode::LATEST: + edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); + (isChunk ? subgraph_latest_any : subgraph_basic_any).AddEdge(edgeIdx); + break; + default: + assert(false); + break; } } - for (const auto& cmptType : filter.none) { - auto cmptIdx = cmptType2idx.at(cmptType); - if (registry.IsRegisteredEdge(sysIdx, cmptIdx)) - continue; - auto edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); + + for (const auto& cmptType : sysFunc->entityQuery.filter.none) { + size_t edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); subgraph_none.AddEdge(edgeIdx); } - for (const auto& singleton : sysFunc->singletonLocator.SingletonTypes()) { + for (const auto& cmptType : sysFunc->randomAccessor.types) { size_t edgeIdx; - switch (singleton.GetAccessMode()) + switch (cmptType.GetAccessMode()) { case AccessMode::LAST_FRAME: - edgeIdx = registry.RegisterEdge(cmptType2idx.at(singleton), sysIdx); - subgraph_lastframe.AddEdge(edgeIdx); + edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); + subgraph_lastframe_random.AddEdge(edgeIdx); break; case AccessMode::WRITE: - edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(singleton)); - subgraph_write.AddEdge(edgeIdx); + edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx.at(cmptType)); + subgraph_write_random.AddEdge(edgeIdx); break; case AccessMode::LATEST: - edgeIdx = registry.RegisterEdge(cmptType2idx.at(singleton), sysIdx); - subgraph_latest.AddEdge(edgeIdx); + edgeIdx = registry.RegisterEdge(cmptType2idx.at(cmptType), sysIdx); + subgraph_latest_random.AddEdge(edgeIdx); break; default: assert(false); @@ -316,7 +340,7 @@ void World::Accept(IListener* listener) const { listener->ExistWorld(this); } -void World::AddCommand(std::function command, size_t layer) { +void World::AddCommand(std::function command, int layer) { assert(inRunningJobGraph); std::lock_guard guard(commandBufferMutex); commandBuffer[layer].push_back(std::move(command)); diff --git a/src/test/21_random/CMakeLists.txt b/src/test/21_random/CMakeLists.txt new file mode 100644 index 0000000..ec4a795 --- /dev/null +++ b/src/test/21_random/CMakeLists.txt @@ -0,0 +1,6 @@ +Ubpa_GetTargetName(core "${PROJECT_SOURCE_DIR}/src/core") +Ubpa_AddTarget( + TEST + MODE EXE + LIB ${core} +) diff --git a/src/test/21_random/main.cpp b/src/test/21_random/main.cpp new file mode 100644 index 0000000..52d3307 --- /dev/null +++ b/src/test/21_random/main.cpp @@ -0,0 +1,86 @@ +#include + +using namespace Ubpa::UECS; + +struct Translation { float value{ 0.f }; }; +struct LocalToParent { float value{ 0.f }; }; +struct LocalToWorld { float value{ 0.f }; }; +struct Children { std::vector value; }; +struct Parent { Entity value; }; + +struct TranslationSystem { + static void SetTreeL2W(World* w, const Entity& entity, const LocalToWorld* l2w) { + if(!w->entityMngr.Have(entity) || !w->entityMngr.Have(entity)) + return; + auto* el2p = w->entityMngr.Get(entity); + auto* el2w = w->entityMngr.Get(entity); + el2w->value = l2w->value + el2p->value; + + if(w->entityMngr.Have(entity)) { + auto* children = w->entityMngr.Get(entity); + for (const auto& child : children->value) + SetTreeL2W(w, child, el2w); + } + } + + static void OnUpdate(Schedule& schedule) { + { + ArchetypeFilter filter; + filter.all.insert(CmptType::Of); + schedule.RegisterEntityJob([](LocalToParent* l2p, const Translation* t) { + l2p->value = t->value; + }, "T2LocalToParent", true, filter); + } + { + ArchetypeFilter filter; + filter.none.insert(CmptType::Of); + schedule.RegisterEntityJob([](LocalToWorld* l2w, const Translation* t) { + l2w->value = t->value; + }, "T2LocalToWorld", true, filter); + } + { + ArchetypeFilter filter; + RandomAccessor randomAccessor; + randomAccessor.types = { + CmptAccessType::Of>, + CmptAccessType::Of>, + CmptAccessType::Of> + }; + filter.none.insert(CmptType::Of); + schedule.RegisterEntityJob([](World* w, Children* children, const LocalToWorld* l2w) { + for(const auto& child : children->value) + SetTreeL2W(w, child, l2w); + }, "LocalToWorld", true, filter, {}, {}, randomAccessor); + } + { + schedule.RegisterEntityJob([](const LocalToWorld* l2w) { + std::cout << l2w->value << std::endl; + }, "PrintL2W"); + } + schedule.Order("T2LocalToWorld", "LocalToWorld"); + } +}; + +int main() { + World w; + w.entityMngr.cmptTraits.Register(); + auto [sys] = w.systemMngr.systemTraits.Register(); + auto [e1, c, t1, l2w1] = w.entityMngr.Create(); + auto [e2, p2, t2, l2p2, l2w2] = w.entityMngr.Create(); + auto [e3, p3, t3, l2p3, l2w3] = w.entityMngr.Create(); + + c->value = { e2, e3 }; + p2->value = e1; + p3->value = e1; + + t1->value = 1.f; + t2->value = 2.f; + t3->value = 3.f; + + w.systemMngr.Activate(sys); + w.Update(); + + std::cout << w.GenUpdateFrameGraph().Dump() << std::endl; + std::cout << w.DumpUpdateJobGraph() << std::endl; + return 0; +}