From 9fb76af1caa699e680f43f0b16d63c40812fabf2 Mon Sep 17 00:00:00 2001 From: Ubpa <641614112@qq.com> Date: Fri, 31 Jul 2020 17:34:03 +0800 Subject: [PATCH] chunk job --- CMakeLists.txt | 6 +-- README.md | 1 + doc/todo.md | 7 +-- include/UECS/ChunkView.h | 29 ++++++++++++ include/UECS/CmptTag.h | 11 ++++- include/UECS/CmptType.h | 17 ++++--- include/UECS/EntityLocator.h | 9 ++-- include/UECS/EntityMngr.h | 3 +- include/UECS/RTDCmptsView.h | 14 +++--- include/UECS/Schedule.h | 2 +- include/UECS/SystemFunc.h | 50 +++++++++++++++++---- include/UECS/World.h | 2 +- include/UECS/detail/Archetype.h | 5 +++ include/UECS/detail/ChunkView.inl | 5 +++ include/UECS/detail/CmptTag.inl | 2 +- include/UECS/detail/Schedule.inl | 7 --- include/UECS/detail/SystemFunc.inl | 33 +++++++++++--- src/core/Archetype.cpp | 14 ++++++ src/core/ChunkView.cpp | 17 +++++++ src/core/EntityLocator.cpp | 8 ++-- src/core/EntityMngr.cpp | 18 +++++++- src/core/Schedule.cpp | 57 +++++++++++++++++++++++ src/core/World.cpp | 55 ++++++++++++++--------- src/test/15_chunk_job/CMakeLists.txt | 6 +++ src/test/15_chunk_job/main.cpp | 67 ++++++++++++++++++++++++++++ 25 files changed, 368 insertions(+), 77 deletions(-) create mode 100644 include/UECS/ChunkView.h create mode 100644 include/UECS/detail/ChunkView.inl create mode 100644 src/core/ChunkView.cpp create mode 100644 src/test/15_chunk_job/CMakeLists.txt create mode 100644 src/test/15_chunk_job/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 65d1144..28aa46e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(UECS VERSION 0.9.8) +project(UECS VERSION 0.10.0) message(STATUS "[Project] ${PROJECT_NAME}") include(cmake/InitUCMake.cmake) @@ -9,8 +9,8 @@ Ubpa_InitUCMake() Ubpa_InitProject() Ubpa_AddDep(UContainer 0.0.6) -Ubpa_AddDep(UTemplate 0.4.6) -Ubpa_AddDep(UGraphviz 0.1.1) +Ubpa_AddDep(UTemplate 0.4.6) +Ubpa_AddDep(UGraphviz 0.1.4) Ubpa_AddSubDirsRec(include) Ubpa_AddSubDirsRec(src) diff --git a/README.md b/README.md index 525772b..6180c39 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ int main() { - [generate **frame graph** in **Graphviz**](src/test/12_framegraph/main.cpp) - [performance test](src/test/13_performance/main.cpp) - [serialize](src/test/14_serialize/main.cpp) +- [chunk job](src/test/15_chunk_job/main.cpp) ## Licensing diff --git a/doc/todo.md b/doc/todo.md index fcb442d..d84f393 100644 --- a/doc/todo.md +++ b/doc/todo.md @@ -24,6 +24,8 @@ - [x] `RTDCmptTraits` : **R**un-**T**ime **D**ynamic **C**omponent **T**raits - [x] run-time dynamic `SystemFunc` - [x] C-style API +- [x] chunk job +- [x] serialize (`IListner`) ### unimportant @@ -39,11 +41,6 @@ - [ ] shared component - [ ] system group -### not sure - -- [ ] ChunkJob -- [ ] serialize - ## tool - [x] SysFuncGraph dump diff --git a/include/UECS/ChunkView.h b/include/UECS/ChunkView.h new file mode 100644 index 0000000..e75a795 --- /dev/null +++ b/include/UECS/ChunkView.h @@ -0,0 +1,29 @@ +#pragma once + +#include "CmptType.h" + +namespace Ubpa::UECS { + class Archetype; + struct Chunk; + + class ChunkView { + public: + ChunkView(Archetype* archetype, size_t chunkIdx, Chunk* chunk) + : archetype{ archetype }, chunkIdx{ chunkIdx }, chunk{ chunk } {} + + bool Contains(CmptType) const; + template + bool Contains() const { return Contains(CmptType::Of); } + + // if not contain, return nullptr + void* GetCmptArray(CmptType) const; + template + Cmpt* GetCmptArray() const { return reinterpret_cast(GetCmptArray(CmptType::Of)); } + size_t EntityNum() const; + + private: + Archetype* archetype; + size_t chunkIdx; + Chunk* chunk; + }; +} diff --git a/include/UECS/CmptTag.h b/include/UECS/CmptTag.h index fd73fc5..cb39ca8 100644 --- a/include/UECS/CmptTag.h +++ b/include/UECS/CmptTag.h @@ -6,7 +6,7 @@ namespace Ubpa::UECS { // LastFrame -> Write -> Latest - enum class Mode { + enum class AccessMode { LAST_FRAME, WRITE, LATEST @@ -62,6 +62,15 @@ namespace Ubpa::UECS { struct IsTaggedCmpt : IValue || IsWrite_v || IsLatest_v> {}; template static constexpr bool IsTaggedCmpt_v = IsTaggedCmpt::value; + + template + static constexpr AccessMode AccessModeOf = + IsLastFrame_v ? AccessMode::LAST_FRAME : ( + IsWrite_v ? AccessMode::WRITE : ( + IsLatest_v ? AccessMode::LAST_FRAME + : AccessMode::WRITE // default + ) + ); } #include "detail/CmptTag.inl" diff --git a/include/UECS/CmptType.h b/include/UECS/CmptType.h index f2c15d9..9b6b8af 100644 --- a/include/UECS/CmptType.h +++ b/include/UECS/CmptType.h @@ -1,5 +1,7 @@ #pragma once +#include "CmptTag.h" + #include namespace Ubpa::UECS { @@ -7,17 +9,21 @@ namespace Ubpa::UECS { // use a hashcode to distinguish different type class CmptType { public: - explicit constexpr CmptType(size_t id) : hashcode{ id } {} - explicit constexpr CmptType(std::string_view type_name) : hashcode{ RuntimeTypeID(type_name) } {} + explicit constexpr CmptType(size_t id, AccessMode mode = AccessMode::WRITE) + : hashcode{ id }, mode{ mode } {} + explicit constexpr CmptType(std::string_view type_name, AccessMode mode = AccessMode::WRITE) + : hashcode{ RuntimeTypeID(type_name) }, mode{ mode } {} - template - static constexpr CmptType Of = CmptType{ TypeID }; + template // non-tagged component's access mode is AccessMode::WRITE + static constexpr CmptType Of = CmptType{ TypeID>, AccessModeOf }; constexpr size_t HashCode() const noexcept { return hashcode; } + constexpr AccessMode GetAccessMode() const noexcept { return mode; } + static constexpr CmptType Invalid() noexcept { return CmptType{ static_cast(-1) }; } - template + template // non-tagged constexpr bool Is() const noexcept { return hashcode == TypeID; } constexpr bool operator<(const CmptType& rhs) const noexcept { return hashcode < rhs.hashcode; } @@ -25,6 +31,7 @@ namespace Ubpa::UECS { constexpr bool operator!=(const CmptType& rhs) const noexcept { return hashcode != rhs.hashcode; } private: size_t hashcode; + AccessMode mode; }; } diff --git a/include/UECS/EntityLocator.h b/include/UECS/EntityLocator.h index 60a589a..ab26e1a 100644 --- a/include/UECS/EntityLocator.h +++ b/include/UECS/EntityLocator.h @@ -8,6 +8,7 @@ namespace Ubpa::UECS { // locate components in function's argument list for Archetype + // TODO: combine with a system function's locator class EntityLocator { public: template @@ -16,9 +17,11 @@ namespace Ubpa::UECS { template EntityLocator(TypeList, TypeList, TypeList); - EntityLocator(std::set lastFrameCmpts = {}, + EntityLocator( + std::set lastFrameCmpts = {}, std::set writeFrameCmpts = {}, - std::set latestCmpts = {}); + std::set latestCmpts = {} + ); size_t HashCode() const noexcept { return hashCode; } @@ -27,7 +30,7 @@ namespace Ubpa::UECS { const std::set& LatestCmptTypes() const noexcept { return latestCmptTypes; } const std::set& CmptTypes() const noexcept { return cmptTypes; } - Mode GetCmptTagMode(CmptType type) const; + AccessMode GetCmptTagMode(CmptType type) const; bool operator==(const EntityLocator& locator) const noexcept; private: diff --git a/include/UECS/EntityMngr.h b/include/UECS/EntityMngr.h index 0784736..ec2be19 100644 --- a/include/UECS/EntityMngr.h +++ b/include/UECS/EntityMngr.h @@ -113,7 +113,8 @@ namespace Ubpa::UECS { typename = std::enable_if_t<(std::is_same_v&&...)>> void AttachWithoutInit(Entity, CmptTypes...); - void GenJob(Job* job, SystemFunc* sys) const; + void GenEntityJob(Job* job, SystemFunc* sys) const; + void GenChunkJob(Job* job, SystemFunc* sys) const; struct EntityInfo { Archetype* archetype{ nullptr }; diff --git a/include/UECS/RTDCmptsView.h b/include/UECS/RTDCmptsView.h index 2d61b9b..8cb9258 100644 --- a/include/UECS/RTDCmptsView.h +++ b/include/UECS/RTDCmptsView.h @@ -17,28 +17,28 @@ namespace Ubpa::UECS { // for read/write control class CmptHandle { public: - CmptHandle(CmptType type, void* cmpt, Mode mode) + CmptHandle(CmptType type, void* cmpt, AccessMode mode) : type{ type }, cmpt{ cmpt }, mode{ mode }{} CmptType GetCmptType() const noexcept { return type; } - Mode GetMode() const noexcept { return mode; } + AccessMode GetMode() const noexcept { return mode; } CmptCPtr AsLastFrame() const noexcept { - assert(mode == Mode::LAST_FRAME); + assert(mode == AccessMode::LAST_FRAME); return { type, cmpt }; } CmptPtr AsWrite() const noexcept { - assert(mode == Mode::WRITE); + assert(mode == AccessMode::WRITE); return { type, cmpt }; } CmptCPtr AsLatest() const noexcept { - assert(mode == Mode::LATEST); + assert(mode == AccessMode::LATEST); return { type, cmpt }; } private: CmptType type; void* cmpt; - Mode mode; + AccessMode mode; }; // forward @@ -69,7 +69,7 @@ namespace Ubpa::UECS { EntityLocator* locator; std::set::iterator typeIter; void* const* ptr_cmpt; - mutable CmptHandle handle{ CmptType::Invalid(), nullptr, Mode{} }; + mutable CmptHandle handle{ CmptType::Invalid(), nullptr, AccessMode{} }; }; RTDCmptsView(EntityLocator* locator, void** cmpts) diff --git a/include/UECS/Schedule.h b/include/UECS/Schedule.h index c0ba265..6c64e92 100644 --- a/include/UECS/Schedule.h +++ b/include/UECS/Schedule.h @@ -69,7 +69,7 @@ namespace Ubpa::UECS { std::vector latestSysFuncs; }; friend struct detail::Schedule_::Compiler; - std::unordered_map cmptSysFuncsMap; + std::unordered_map GenCmptSysFuncsMap() const; SysFuncGraph GenSysFuncGraph() const; diff --git a/include/UECS/SystemFunc.h b/include/UECS/SystemFunc.h index ae5939d..335fe7c 100644 --- a/include/UECS/SystemFunc.h +++ b/include/UECS/SystemFunc.h @@ -3,6 +3,7 @@ #include "EntityQuery.h" #include "Entity.h" #include "RTDCmptsView.h" +#include "ChunkView.h" #include @@ -13,12 +14,18 @@ namespace Ubpa::UECS { // name must be unique in global // query.filter can be change dynamically by other with Schedule // [system function kind] (distinguish by argument list) - // 1. per entity function: [[const] Entity e, ] [size_t indexInQuery, ] ... - // - - tagged component: {LastFrame|Write|Latest} - // 2. job: empty argument list - // 3. runtime dynamic function: RTDCmptsView + // 1. per entity function: [[const] Entity e] [size_t indexInQuery] [RTDCmptsView] ... + // * : {LastFrame|Write|Latest} + // 2. chunk: ChunkView + // 3. job: empty argument list class SystemFunc { public: + enum class Mode { + Entity, + Chunk, + Job, + }; + EntityQuery query; template @@ -35,21 +42,46 @@ namespace Ubpa::UECS { size_t HashCode() const noexcept { return hashCode; } void operator()(Entity e, size_t entityIndexInQuery, RTDCmptsView rtdcmpts) { - return func(e, entityIndexInQuery, rtdcmpts); + assert(mode == Mode::Entity); + return func( + e, + entityIndexInQuery, + rtdcmpts, + ChunkView{nullptr, size_t_invalid, nullptr} + ); + } + + void operator()(ChunkView chunkView) { + assert(mode == Mode::Chunk); + return func( + Entity::Invalid(), + size_t_invalid, + RTDCmptsView{nullptr, nullptr}, + chunkView + ); + } + + void operator()() { + assert(mode == Mode::Job); + return func( + Entity::Invalid(), + size_t_invalid, + RTDCmptsView{ nullptr, nullptr }, + ChunkView{nullptr, size_t_invalid, nullptr} + ); } - // no arguments - bool IsJob() const noexcept { return isJob; } + Mode GetMode() const noexcept { return mode; } bool operator==(const SystemFunc& func) const noexcept { return name == func.name; } private: template SystemFunc(Func&& func, std::string name, EntityFilter filter, ArgList); - std::function func; + std::function func; std::string name; - bool isJob; + Mode mode; size_t hashCode; // after name }; } diff --git a/include/UECS/World.h b/include/UECS/World.h index 7de9be4..0d4a2a0 100644 --- a/include/UECS/World.h +++ b/include/UECS/World.h @@ -29,7 +29,7 @@ namespace Ubpa::UECS { // after running Update // use RTDCmptTraits' registered component name - Graphviz::Graph GenUpdateFrameGraph() const; + UGraphviz::Graph GenUpdateFrameGraph() const; void Accept(IListener* listener) const; diff --git a/include/UECS/detail/Archetype.h b/include/UECS/detail/Archetype.h index b5f3e6d..aacb166 100644 --- a/include/UECS/detail/Archetype.h +++ b/include/UECS/detail/Archetype.h @@ -54,6 +54,10 @@ namespace Ubpa::UECS { // Entity + Components std::tuple, std::vector>, std::vector> Locate(const std::set& cmptTypes) const; + + void* Locate(size_t chunkIdx, CmptType) const; + + Chunk* GetChunk(size_t chunkIdx) const { return chunks[chunkIdx]; } void* At(CmptType type, size_t idx) const; @@ -88,6 +92,7 @@ namespace Ubpa::UECS { size_t CmptNum() const noexcept { return types.size() - 1; } size_t EntityNum() const noexcept { return entityNum; } + size_t EntityNumOfChunk(size_t chunkIdx) const noexcept; size_t ChunkNum() const noexcept { return chunks.size(); } size_t ChunkCapacity() const noexcept { return chunkCapacity; } diff --git a/include/UECS/detail/ChunkView.inl b/include/UECS/detail/ChunkView.inl new file mode 100644 index 0000000..5dc31f3 --- /dev/null +++ b/include/UECS/detail/ChunkView.inl @@ -0,0 +1,5 @@ +#pragma once + +namespace Ubpa::UECS { + +} diff --git a/include/UECS/detail/CmptTag.inl b/include/UECS/detail/CmptTag.inl index 6d4860b..6c7f97f 100644 --- a/include/UECS/detail/CmptTag.inl +++ b/include/UECS/detail/CmptTag.inl @@ -8,10 +8,10 @@ namespace Ubpa::UECS { } namespace Ubpa::UECS { + template struct RemoveTag : IType {}; // default template struct RemoveTag : IType {}; template struct RemoveTag : IType {}; template struct RemoveTag> : IType {}; - template<> struct RemoveTag : IType {}; template struct DecayTag : IType {}; // template struct DecayTag : IType {}; diff --git a/include/UECS/detail/Schedule.inl b/include/UECS/detail/Schedule.inl index ed1f056..c8e8bf7 100644 --- a/include/UECS/detail/Schedule.inl +++ b/include/UECS/detail/Schedule.inl @@ -17,13 +17,6 @@ namespace Ubpa::UECS { void Schedule::Request(Args&&... args) { SystemFunc* sysFunc = sysFuncPool.Request(std::forward(args)...); sysFuncs.emplace(sysFunc->HashCode(), sysFunc); - const auto& locator = sysFunc->query.locator; - for (const auto& type : locator.LastFrameCmptTypes()) - cmptSysFuncsMap[type].lastFrameSysFuncs.push_back(sysFunc); - for (const auto& type : locator.WriteCmptTypes()) - cmptSysFuncsMap[type].writeSysFuncs.push_back(sysFunc); - for (const auto& type : locator.LatestCmptTypes()) - cmptSysFuncsMap[type].latestSysFuncs.push_back(sysFunc); } inline Schedule::Schedule(EntityMngr* entityMngr, SystemMngr* systemMngr) diff --git a/include/UECS/detail/SystemFunc.inl b/include/UECS/detail/SystemFunc.inl index 0170bac..61f5fec 100644 --- a/include/UECS/detail/SystemFunc.inl +++ b/include/UECS/detail/SystemFunc.inl @@ -10,7 +10,7 @@ namespace Ubpa::UECS::detail::System_ { namespace Ubpa::UECS { template SystemFunc::SystemFunc(Func&& func, std::string name, EntityLocator locator, EntityFilter filter) - : isJob{ IsEmpty_v> }, + : mode{ Mode::Entity }, func{ detail::System_::Pack(std::forward(func)) }, name{ std::move(name) }, hashCode{ HashCode(this->name) }, @@ -18,8 +18,11 @@ namespace Ubpa::UECS { { using ArgList = FuncTraits_ArgList; - static_assert(ContainTs_v, - "'s argument must contain RTDCmptsView"); + static_assert(Contain_v, + "(Mode::Entity) 's argument list must contain RTDCmptsView"); + + static_assert(!Contain_v, + "(Mode::Entity) 's argument list must not contain ChunkView"); } template @@ -31,12 +34,23 @@ namespace Ubpa::UECS { template SystemFunc::SystemFunc(Func&& func, std::string name, EntityFilter filter, ArgList) - : isJob{ IsEmpty_v }, + : func{ detail::System_::Pack(std::forward(func)) }, name{ std::move(name) }, hashCode{ HashCode(this->name) }, query{ std::move(filter), EntityLocator{Filter_t{}} } { + static_assert(!Contain_v, + "'s argument list contains RTDCmptsView, so you should use the constructor of the run-time dynamic version"); + if constexpr (IsEmpty_v) + mode = Mode::Job; + else if constexpr (std::is_same_v>) + mode = Mode::Chunk; + else { + static_assert(!Contain_v, + "(Mode::Entity) 's argument list must not contain ChunkView"); + mode = Mode::Entity; + } } } @@ -46,11 +60,16 @@ namespace Ubpa::UECS::detail::System_ { template struct Packer, TypeList> { - using CmptList = TypeList; + using CmptList = TypeList; // sorted template static auto run(Func&& func) noexcept { - return [func = std::forward(func)](Entity e, size_t entityIndexInQuery, RTDCmptsView rtdcmpts) { - auto unsorted_arg_tuple = std::make_tuple(e, entityIndexInQuery, rtdcmpts, reinterpret_cast(rtdcmpts.Components()[Find_v])...); + return [func = std::forward(func)](Entity e, size_t entityIndexInQuery, RTDCmptsView rtdcmpts, ChunkView chunkView) { + auto unsorted_arg_tuple = std::make_tuple( + e, + entityIndexInQuery, + rtdcmpts, + chunkView, + reinterpret_cast(rtdcmpts.Components()[Find_v])...); func(std::get(unsorted_arg_tuple)...); }; } diff --git a/src/core/Archetype.cpp b/src/core/Archetype.cpp index cc7c647..00de513 100644 --- a/src/core/Archetype.cpp +++ b/src/core/Archetype.cpp @@ -179,6 +179,13 @@ tuple, vector>, vector> Archetype::Locate( return { chunkEntity, chunkCmpts, sizes }; } +void* Archetype::Locate(size_t chunkIdx, CmptType t) const { + assert(types.Contains(t)); + assert(chunkIdx < chunks.size()); + auto buffer = chunks[chunkIdx]->Data(); + return buffer + Offsetof(t); +} + size_t Archetype::Erase(size_t idx) { assert(idx < entityNum); @@ -237,3 +244,10 @@ vector Archetype::Components(size_t idx) const { return rst; } + +size_t Archetype::EntityNumOfChunk(size_t chunkIdx) const noexcept { + if (chunkIdx == chunks.size() - 1) + return entityNum - (chunks.size() - 1) * chunkCapacity; + else + return chunkCapacity; +} diff --git a/src/core/ChunkView.cpp b/src/core/ChunkView.cpp new file mode 100644 index 0000000..6c2c369 --- /dev/null +++ b/src/core/ChunkView.cpp @@ -0,0 +1,17 @@ +#include + +#include + +using namespace Ubpa::UECS; + +void* ChunkView::GetCmptArray(CmptType t) const { + return Contains(t) ? archetype->Locate(chunkIdx, t) : nullptr; +} + +size_t ChunkView::EntityNum() const { + return archetype->EntityNumOfChunk(chunkIdx); +} + +bool ChunkView::Contains(CmptType t) const { + return archetype->GetCmptTypeSet().Contains(t); +} diff --git a/src/core/EntityLocator.cpp b/src/core/EntityLocator.cpp index 5ae5ca8..955dfc9 100644 --- a/src/core/EntityLocator.cpp +++ b/src/core/EntityLocator.cpp @@ -30,12 +30,12 @@ bool EntityLocator::operator==(const EntityLocator& locator) const noexcept { && latestCmptTypes == latestCmptTypes; } -Mode EntityLocator::GetCmptTagMode(CmptType type) const { +AccessMode EntityLocator::GetCmptTagMode(CmptType type) const { assert(cmptTypes.find(type) != cmptTypes.end()); if (lastFrameCmptTypes.find(type) != lastFrameCmptTypes.end()) - return Mode::LAST_FRAME; + return AccessMode::LAST_FRAME; else if (writeCmptTypes.find(type) != writeCmptTypes.end()) - return Mode::WRITE; + return AccessMode::WRITE; else // lastestCmptTypes.find(type) != lastestCmptTypes.end()) - return Mode::LATEST; + return AccessMode::LATEST; } diff --git a/src/core/EntityMngr.cpp b/src/core/EntityMngr.cpp index e879796..09415c4 100644 --- a/src/core/EntityMngr.cpp +++ b/src/core/EntityMngr.cpp @@ -252,7 +252,9 @@ void EntityMngr::Destroy(Entity e) { RecycleEntityEntry(e); } -void EntityMngr::GenJob(Job* job, SystemFunc* sys) const { +void EntityMngr::GenEntityJob(Job* job, SystemFunc* sys) const { + assert(sys->GetMode() == SystemFunc::Mode::Entity); + size_t indexOffsetInQuery = 0; for (Archetype* archetype : QueryArchetypes(sys->query)) { auto [chunkEntity, chunkCmpts, sizes] = archetype->Locate(sys->query.locator.CmptTypes()); @@ -279,6 +281,20 @@ void EntityMngr::GenJob(Job* job, SystemFunc* sys) const { } } +void EntityMngr::GenChunkJob(Job* job, SystemFunc* sys) const { + assert(sys->GetMode() == SystemFunc::Mode::Chunk); + + for (Archetype* archetype : QueryArchetypes(sys->query)) { + size_t chunkNum = archetype->ChunkNum(); + + for (size_t i = 0; i < chunkNum; i++) { + job->emplace([=]() { + (*sys)(ChunkView{ archetype, i, archetype->GetChunk(i) }); + }); + } + } +} + void EntityMngr::RunCommands() { lock_guard guard(commandBufferMutex); for (const auto& command : commandBuffer) diff --git a/src/core/Schedule.cpp b/src/core/Schedule.cpp index 22c8e4a..2990094 100644 --- a/src/core/Schedule.cpp +++ b/src/core/Schedule.cpp @@ -222,6 +222,61 @@ void Schedule::Clear() { sysLockFilter.clear(); } +unordered_map Schedule::GenCmptSysFuncsMap() const { + unordered_map rst; + for (const auto& [hashcode, sysFunc] : sysFuncs) { + const auto& locator = sysFunc->query.locator; + for (const auto& type : locator.LastFrameCmptTypes()) + rst[type].lastFrameSysFuncs.push_back(sysFunc); + for (const auto& type : locator.WriteCmptTypes()) + rst[type].writeSysFuncs.push_back(sysFunc); + for (const auto& type : locator.LatestCmptTypes()) + rst[type].latestSysFuncs.push_back(sysFunc); + + if (sysFunc->GetMode() == SystemFunc::Mode::Chunk) { + const auto& filter = sysFunc->query.filter; + for (const auto& type : filter.AllCmptTypes()) { + auto& cmptSysFuncs = rst[type]; + switch (type.GetAccessMode()) + { + case Ubpa::UECS::AccessMode::LAST_FRAME: + cmptSysFuncs.lastFrameSysFuncs.push_back(sysFunc); + break; + case Ubpa::UECS::AccessMode::WRITE: + cmptSysFuncs.writeSysFuncs.push_back(sysFunc); + break; + case Ubpa::UECS::AccessMode::LATEST: + cmptSysFuncs.latestSysFuncs.push_back(sysFunc); + break; + default: + assert(false); + break; + } + } + + for (const auto& type : filter.AnyCmptTypes()) { + auto& cmptSysFuncs = rst[type]; + switch (type.GetAccessMode()) + { + case Ubpa::UECS::AccessMode::LAST_FRAME: + cmptSysFuncs.lastFrameSysFuncs.push_back(sysFunc); + break; + case Ubpa::UECS::AccessMode::WRITE: + cmptSysFuncs.writeSysFuncs.push_back(sysFunc); + break; + case Ubpa::UECS::AccessMode::LATEST: + cmptSysFuncs.latestSysFuncs.push_back(sysFunc); + break; + default: + assert(false); + break; + } + } + } + } + return rst; +} + SysFuncGraph Schedule::GenSysFuncGraph() const { // [change func Filter] for (const auto& [hashcode, change] : sysFilterChange) { @@ -242,6 +297,8 @@ SysFuncGraph Schedule::GenSysFuncGraph() const { func->query.filter.EraseNone(change.eraseNones); } + auto cmptSysFuncsMap = GenCmptSysFuncsMap(); + // [gen groupMap] unordered_map groupMap; for (const auto& [hashcode, sysFunc] : sysFuncs) diff --git a/src/core/World.cpp b/src/core/World.cpp index 8599576..a93d122 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -22,10 +22,22 @@ void World::Update() { for (const auto& [func, adjVs] : graph.GetAdjList()) { auto job = jobPool.Request(func->Name()); jobs.push_back(job); - if (!func->IsJob()) - entityMngr.GenJob(job, func); - else - job->emplace([func = func]() { (*func)(Entity::Invalid(), size_t_invalid, RTDCmptsView{ nullptr,nullptr }); }); + switch (func->GetMode()) + { + case Ubpa::UECS::SystemFunc::Mode::Entity: + entityMngr.GenEntityJob(job, func); + break; + case Ubpa::UECS::SystemFunc::Mode::Chunk: + entityMngr.GenChunkJob(job, func); + break; + case Ubpa::UECS::SystemFunc::Mode::Job: + job->emplace([func = func]() { + (*func)(); + }); + break; + default: + break; + } table[func] = jobGraph.composed_of(*job); } @@ -45,15 +57,15 @@ string World::DumpUpdateJobGraph() const { } // after running Update -Graphviz::Graph World::GenUpdateFrameGraph() const { - Graphviz::Graph graph("Update Frame Graph", true); +UGraphviz::Graph World::GenUpdateFrameGraph() const { + UGraphviz::Graph graph("Update Frame Graph", true); graph .RegisterGraphNodeAttr("style", "filled") .RegisterGraphNodeAttr("fontcolor", "white") .RegisterGraphNodeAttr("fontname", "consolas"); - auto& registrar = graph.GetRegistrar(); + auto& registry = graph.GetRegistry(); auto& subgraph_cmpt = graph.GenSubgraph("Component Nodes"); auto& subgraph_sys = graph.GenSubgraph("System Function Nodes"); @@ -113,49 +125,50 @@ Graphviz::Graph World::GenUpdateFrameGraph() const { } for (auto cmptType : cmptTypes) { - auto cmptIdx = registrar.RegisterNode(queryCmptName(cmptType)); + auto cmptIdx = registry.RegisterNode(queryCmptName(cmptType)); cmptType2idx[cmptType] = cmptIdx; subgraph_cmpt.AddNode(cmptIdx); } - for (const auto& [hash, sysFuncs] : schedule.sysFuncs) { - auto sysIdx = registrar.RegisterNode(sysFuncs->Name()); + // TODO: filter + for (const auto& [hash, sysFunc] : schedule.sysFuncs) { + auto sysIdx = registry.RegisterNode(sysFunc->Name()); subgraph_sys.AddNode(sysIdx); - const auto& locator = sysFuncs->query.locator; + const auto& locator = sysFunc->query.locator; for (const auto& cmptType : locator.LastFrameCmptTypes()) { - auto edgeIdx = registrar.RegisterEdge(cmptType2idx[cmptType], sysIdx); + auto edgeIdx = registry.RegisterEdge(cmptType2idx[cmptType], sysIdx); subgraph_lastframe.AddEdge(edgeIdx); } for (const auto& cmptType : locator.WriteCmptTypes()) { - auto edgeIdx = registrar.RegisterEdge(sysIdx, cmptType2idx[cmptType]); + auto edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx[cmptType]); subgraph_write.AddEdge(edgeIdx); } for (const auto& cmptType : locator.LatestCmptTypes()) { - auto edgeIdx = registrar.RegisterEdge(cmptType2idx[cmptType], sysIdx); + auto edgeIdx = registry.RegisterEdge(cmptType2idx[cmptType], sysIdx); subgraph_latest.AddEdge(edgeIdx); } - const auto& filter = sysFuncs->query.filter; + const auto& filter = sysFunc->query.filter; for (const auto& cmptType : filter.AllCmptTypes()) { auto cmptIdx = cmptType2idx[cmptType]; - if (registrar.IsRegisteredEdge(sysIdx, cmptIdx)) + if (registry.IsRegisteredEdge(sysIdx, cmptIdx)) continue; - auto edgeIdx = registrar.RegisterEdge(sysIdx, cmptType2idx[cmptType]); + auto edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx[cmptType]); subgraph_all.AddEdge(edgeIdx); } for (const auto& cmptType : filter.AnyCmptTypes()) { auto cmptIdx = cmptType2idx[cmptType]; - if (registrar.IsRegisteredEdge(sysIdx, cmptIdx)) + if (registry.IsRegisteredEdge(sysIdx, cmptIdx)) continue; - auto edgeIdx = registrar.RegisterEdge(sysIdx, cmptType2idx[cmptType]); + auto edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx[cmptType]); subgraph_any.AddEdge(edgeIdx); } for (const auto& cmptType : filter.NoneCmptTypes()) { auto cmptIdx = cmptType2idx[cmptType]; - if (registrar.IsRegisteredEdge(sysIdx, cmptIdx)) + if (registry.IsRegisteredEdge(sysIdx, cmptIdx)) continue; - auto edgeIdx = registrar.RegisterEdge(sysIdx, cmptType2idx[cmptType]); + auto edgeIdx = registry.RegisterEdge(sysIdx, cmptType2idx[cmptType]); subgraph_none.AddEdge(edgeIdx); } } diff --git a/src/test/15_chunk_job/CMakeLists.txt b/src/test/15_chunk_job/CMakeLists.txt new file mode 100644 index 0000000..ec4a795 --- /dev/null +++ b/src/test/15_chunk_job/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/15_chunk_job/main.cpp b/src/test/15_chunk_job/main.cpp new file mode 100644 index 0000000..ea0f953 --- /dev/null +++ b/src/test/15_chunk_job/main.cpp @@ -0,0 +1,67 @@ +#include + +#include + +using namespace Ubpa::UECS; +using namespace Ubpa; +using namespace std; + +struct S { float value; }; +struct A { float value; }; +struct B { float value; }; + +constexpr float dt = 0.003f; + +struct SAB_System { + static void OnUpdate(Schedule& schedule) { + EntityFilter filter{ + TypeList{}, // all + TypeList, Latest>{}, // any + TypeList<>{} // none + }; + + schedule.Register([](ChunkView chunk) { + auto arrayS = chunk.GetCmptArray(); + auto arrayA = chunk.GetCmptArray(); + auto arrayB = chunk.GetCmptArray(); + bool containsA = arrayA != nullptr; + bool containsB = arrayB != nullptr; + bool containsAB = containsA && containsB; + + if (containsAB) { + cout << "[AB]" << endl; + for (size_t i = 0; i < chunk.EntityNum(); i++) { + arrayS[i].value += arrayA[i].value * arrayB[i].value; + } + } + else if (containsA) { + cout << "[A]" << endl; + for (size_t i = 0; i < chunk.EntityNum(); i++) { + arrayS[i].value += arrayA[i].value; + } + } + else { // containsB + cout << "[B]" << endl; + for (size_t i = 0; i < chunk.EntityNum(); i++) { + arrayS[i].value += arrayB[i].value; + } + } + }, "SAB_System", filter); + } +}; + +int main() { + World w; + w.systemMngr.Register(); + + w.entityMngr.Create(); + w.entityMngr.Create(); + w.entityMngr.Create(); + w.entityMngr.Create(); + + w.Update(); + + cout << w.GenUpdateFrameGraph().Dump() << endl; + + return 0; +}