From 8288be996d9ba81071d061f1f0af2fc7d4a86871 Mon Sep 17 00:00:00 2001 From: ubpa Date: Mon, 22 Mar 2021 20:27:07 +0800 Subject: [PATCH] copy/move schedule, Run* support CommandBufferView --- include/UECS/CommandBuffer.hpp | 6 ++++ include/UECS/Schedule.hpp | 14 ++++++--- include/UECS/SystemFunc.hpp | 4 +++ include/UECS/World.hpp | 11 +++---- include/UECS/details/Schedule.inl | 5 ++-- include/UECS/details/World.inl | 14 +++++---- src/core/Schedule.cpp | 43 ++++++++++++++++++--------- src/core/World.cpp | 48 +++++++++++++++++++------------ 8 files changed, 96 insertions(+), 49 deletions(-) diff --git a/include/UECS/CommandBuffer.hpp b/include/UECS/CommandBuffer.hpp index 3a8d7c1..ea528c2 100644 --- a/include/UECS/CommandBuffer.hpp +++ b/include/UECS/CommandBuffer.hpp @@ -17,6 +17,12 @@ namespace Ubpa::UECS { auto& GetCommands() noexcept { return commands; } const auto& GetCommands() const noexcept { return commands; } + + void Run() { + for (const auto& cmd : commands) + cmd(); + commands.clear(); + } private: std::vector> commands; }; diff --git a/include/UECS/Schedule.hpp b/include/UECS/Schedule.hpp index 5d893c9..9987df6 100644 --- a/include/UECS/Schedule.hpp +++ b/include/UECS/Schedule.hpp @@ -18,6 +18,8 @@ namespace Ubpa::UECS { class SystemMngr; class SysFuncGraph; + static constexpr int SpecialLayer = -std::numeric_limits::max(); + // [description] // system infomation record // - SystemFunc @@ -117,12 +119,17 @@ namespace Ubpa::UECS { Schedule& Disable(std::string_view sys, int layer = 0); // clear every frame - std::pmr::monotonic_buffer_resource* GetFrameMonotonicResource() { return &frame_rsrc; } + std::pmr::monotonic_buffer_resource* GetFrameMonotonicResource() { return frame_rsrc.get(); } template T* CreateFrameObject(Args&&... args) const; + std::string_view RegisterFrameString(std::string_view str); - ~Schedule(); private: + Schedule(); + Schedule(const Schedule&); + Schedule(Schedule&&) noexcept = default; + ~Schedule(); + template const SystemFunc* Request(int layer, Args&&...); @@ -163,8 +170,7 @@ namespace Ubpa::UECS { std::map layerInfos; - mutable std::pmr::monotonic_buffer_resource frame_rsrc; // release in every frame - std::string_view RegisterFrameString(std::string_view str); + std::unique_ptr frame_rsrc; // release in every frame friend class World; }; diff --git a/include/UECS/SystemFunc.hpp b/include/UECS/SystemFunc.hpp index cc0f20f..5246f97 100644 --- a/include/UECS/SystemFunc.hpp +++ b/include/UECS/SystemFunc.hpp @@ -13,6 +13,8 @@ #include namespace Ubpa::UECS { + class Schedule; + // [- description] // system function registered by Schedule in ::OnUpdate(Schedule&) // name + query(archetype filter + component locator) + singleton locator + function<...> @@ -72,6 +74,8 @@ namespace Ubpa::UECS { bool operator==(const SystemFunc& sysFunc) const noexcept { return name == sysFunc.name; } private: + friend class Schedule; + SystemFunc(const SystemFunc&) = default; Mode mode; std::string_view name; std::size_t hashCode; // after name diff --git a/include/UECS/World.hpp b/include/UECS/World.hpp index 5ecd4a2..1405325 100644 --- a/include/UECS/World.hpp +++ b/include/UECS/World.hpp @@ -16,10 +16,7 @@ namespace Ubpa::UECS { // SystemMngr + EntityMngr class World { public: - World() : - jobRsrc{ std::make_unique() }, - systemMngr { this } {} - // not copy/move schedule, so you can't use DumpUpdateJobGraph() and GenUpdateFrameGraph() before Update() + World(); World(const World&); World(World&&) noexcept; ~World(); @@ -57,7 +54,7 @@ namespace Ubpa::UECS { // : [const] *... // CmptsView template - void RunEntityJob( + CommandBuffer RunEntityJob( Func&&, bool isParallel = true, ArchetypeFilter = {}, @@ -91,7 +88,7 @@ namespace Ubpa::UECS { // std::size_t entityBeginIndexInQuery // ChunkView (necessary) template - void RunChunkJob( + CommandBuffer RunChunkJob( Func&&, ArchetypeFilter = {}, bool isParallel = true, @@ -136,7 +133,7 @@ namespace Ubpa::UECS { std::mutex commandBufferMutex; void RunCommands(int layer); - void Run(SystemFunc*); + CommandBuffer Run(SystemFunc*); std::pmr::synchronized_pool_resource frame_sync_rsrc; }; diff --git a/include/UECS/details/Schedule.inl b/include/UECS/details/Schedule.inl index 190dfb4..f64414d 100644 --- a/include/UECS/details/Schedule.inl +++ b/include/UECS/details/Schedule.inl @@ -3,7 +3,7 @@ namespace Ubpa::UECS { template T* Schedule::CreateFrameObject(Args&&... args) const { - void* buffer = frame_rsrc.allocate(sizeof(T), alignof(T)); + void* buffer = frame_rsrc->allocate(sizeof(T), alignof(T)); return new(buffer)T(std::forward(args)...); } @@ -111,7 +111,8 @@ namespace Ubpa::UECS { template const SystemFunc* Schedule::Request(int layer, Args&&... args) { - SystemFunc* sysFunc = (SystemFunc*)frame_rsrc.allocate(sizeof(SystemFunc), alignof(SystemFunc)); + assert(layer != SpecialLayer); + SystemFunc* sysFunc = (SystemFunc*)frame_rsrc->allocate(sizeof(SystemFunc), alignof(SystemFunc)); new(sysFunc)SystemFunc(std::forward(args)...); layerInfos[layer].sysFuncs.emplace(sysFunc->GetValue(), sysFunc); return sysFunc; diff --git a/include/UECS/details/World.inl b/include/UECS/details/World.inl index a58fb2a..490460d 100644 --- a/include/UECS/details/World.inl +++ b/include/UECS/details/World.inl @@ -2,7 +2,7 @@ namespace Ubpa::UECS { template - void World::RunEntityJob( + CommandBuffer World::RunEntityJob( Func&& func, bool isParallel, ArchetypeFilter filter, @@ -19,7 +19,7 @@ namespace Ubpa::UECS { {}, isParallel }; - Run(&sys); + return Run(&sys); } template @@ -35,6 +35,8 @@ namespace Ubpa::UECS { "const RunEntityJob should use const World*"); static_assert(Length_v> == 0, "const RunEntityJob can't write cmpt"); + static_assert(!Contain_v, + "const RunEntityJob shouldn't use CommandBufferView"); assert("const RunEntityJob can't write cmpt" && !cmptLocator.HasWriteTypeID()); @@ -48,7 +50,7 @@ namespace Ubpa::UECS { } template - void World::RunChunkJob( + CommandBuffer World::RunChunkJob( Func&& func, ArchetypeFilter filter, bool isParallel, @@ -63,7 +65,7 @@ namespace Ubpa::UECS { {}, isParallel }; - Run(&sys); + return Run(&sys); } template @@ -74,8 +76,10 @@ namespace Ubpa::UECS { SingletonLocator singletonLocator ) const { using ArgList = FuncTraits_ArgList; - static_assert(Contain_v == 0, + static_assert(!Contain_v, "const RunChunkJob should use const World*"); + static_assert(!Contain_v, + "const RunChunkJob shouldn't use CommandBufferView"); assert("const RunChunkJob can't write cmpt" && !filter.HaveWriteTypeID()); diff --git a/src/core/Schedule.cpp b/src/core/Schedule.cpp index 49b2ce6..8316a30 100644 --- a/src/core/Schedule.cpp +++ b/src/core/Schedule.cpp @@ -6,36 +6,51 @@ using namespace Ubpa; using namespace Ubpa::UECS; using namespace std; -Schedule::~Schedule() { - Clear(); +Schedule::Schedule() : frame_rsrc{ std::make_unique() } {} + +Schedule::~Schedule() { Clear(); } + +Schedule::Schedule(const Schedule& other) : + frame_rsrc{ std::make_unique() }, + layerInfos{ other.layerInfos } +{ + for (auto& [layer, info] : layerInfos) { + for (auto& [id, sys] : info.sysFuncs) { + sys = CreateFrameObject(*sys); + sys->name = RegisterFrameString(sys->Name()); + } + } } std::string_view Schedule::RegisterFrameString(std::string_view str) { - auto* buffer = (char*)frame_rsrc.allocate((str.size() + 1) * sizeof(char), alignof(char)); + auto* buffer = (char*)frame_rsrc->allocate((str.size() + 1) * sizeof(char), alignof(char)); std::memcpy(buffer, str.data(), str.size() * sizeof(char)); buffer[str.size()] = 0; return str; } Schedule& Schedule::Order(string_view x, string_view y, int layer) { + assert(layer != SpecialLayer); layerInfos[layer].sysFuncOrder.emplace(SystemFunc::GetValue(x), SystemFunc::GetValue(y)); return *this; } Schedule& Schedule::AddNone(string_view sys, TypeID type, int layer) { + assert(layer != SpecialLayer); std::size_t hashcode = SystemFunc::GetValue(sys); layerInfos[layer].sysNones[hashcode].push_back(type); return *this; } Schedule& Schedule::Disable(std::string_view sys, int layer) { + assert(layer != SpecialLayer); layerInfos[layer].disabledSysFuncs.insert(SystemFunc::GetValue(sys)); return *this; } void Schedule::Clear() { for (auto& [layer, layerinfo] : layerInfos) { - //auto alloc = std::pmr::polymorphic_allocator{ &frame_rsrc }; + //auto alloc = std::pmr::polymorphic_allocator{ frame_rsrc.get() }; for (const auto& [hash, sysFunc] : layerinfo.sysFuncs) { sysFunc->~SystemFunc(); // no need to deallocate @@ -47,21 +62,22 @@ void Schedule::Clear() { layerinfo.sysNones.clear(); } layerInfos.clear(); - frame_rsrc.release(); + frame_rsrc->release(); } Schedule::CmptSysFuncsMap* Schedule::GenCmptSysFuncsMap(int layer) const { + assert(layer != SpecialLayer); const auto& layerinfo = layerInfos.at(layer); const auto& sysFuncs = layerinfo.sysFuncs; const auto& disabledSysFuncs = layerinfo.disabledSysFuncs; - CmptSysFuncsMap* rst = CreateFrameObject(CmptSysFuncsMap::allocator_type{ &frame_rsrc }); + CmptSysFuncsMap* rst = CreateFrameObject(CmptSysFuncsMap::allocator_type{ frame_rsrc.get() }); for (const auto& [hashcode, sysFunc] : sysFuncs) { if (disabledSysFuncs.contains(hashcode)) continue; for (const auto& type : sysFunc->entityQuery.locator.AccessTypeIDs()) { - auto& cmptSysFuncs = rst->try_emplace(type, &frame_rsrc).first->second; + auto& cmptSysFuncs = rst->try_emplace(type, frame_rsrc.get()).first->second; switch (type.GetAccessMode()) { case AccessMode::LAST_FRAME: @@ -79,7 +95,7 @@ Schedule::CmptSysFuncsMap* Schedule::GenCmptSysFuncsMap(int layer) const { } } for (const auto& type : sysFunc->singletonLocator.SingletonTypes()) { - auto& cmptSysFuncs = rst->try_emplace(type, &frame_rsrc).first->second; + auto& cmptSysFuncs = rst->try_emplace(type, frame_rsrc.get()).first->second; switch (type.GetAccessMode()) { case AccessMode::LAST_FRAME: @@ -97,7 +113,7 @@ Schedule::CmptSysFuncsMap* Schedule::GenCmptSysFuncsMap(int layer) const { } } for (const auto& type : sysFunc->randomAccessor.types) { - auto& cmptSysFuncs = rst->try_emplace(type, &frame_rsrc).first->second; + auto& cmptSysFuncs = rst->try_emplace(type, frame_rsrc.get()).first->second; switch (type.GetAccessMode()) { case AccessMode::LAST_FRAME: @@ -118,7 +134,7 @@ Schedule::CmptSysFuncsMap* Schedule::GenCmptSysFuncsMap(int layer) const { if (sysFunc->GetMode() == SystemFunc::Mode::Chunk) { const auto& filter = sysFunc->entityQuery.filter; for (const auto& type : filter.all) { - auto& cmptSysFuncs = rst->try_emplace(type, &frame_rsrc).first->second; + auto& cmptSysFuncs = rst->try_emplace(type, frame_rsrc.get()).first->second; switch (type.GetAccessMode()) { case AccessMode::LAST_FRAME: @@ -137,7 +153,7 @@ Schedule::CmptSysFuncsMap* Schedule::GenCmptSysFuncsMap(int layer) const { } for (const auto& type : filter.any) { - auto& cmptSysFuncs = rst->try_emplace(type, &frame_rsrc).first->second; + auto& cmptSysFuncs = rst->try_emplace(type, frame_rsrc.get()).first->second; switch (type.GetAccessMode()) { case AccessMode::LAST_FRAME: @@ -160,6 +176,7 @@ Schedule::CmptSysFuncsMap* Schedule::GenCmptSysFuncsMap(int layer) const { } SysFuncGraph* Schedule::GenSysFuncGraph(int layer) const { + assert(layer != SpecialLayer); const auto& layerinfo = layerInfos.at(layer); const auto& sysNones = layerinfo.sysNones; const auto& sysFuncs = layerinfo.sysFuncs; @@ -182,7 +199,7 @@ SysFuncGraph* Schedule::GenSysFuncGraph(int layer) const { CmptSysFuncsMap* cmptSysFuncsMap = GenCmptSysFuncsMap(layer); // use frame rsrc, no need to release // [gen graph] - SysFuncGraph* graph = CreateFrameObject(&frame_rsrc); + SysFuncGraph* graph = CreateFrameObject(frame_rsrc.get()); // [gen graph] - vertex for (const auto& [hashcode, sysFunc] : sysFuncs) { @@ -228,7 +245,7 @@ SysFuncGraph* Schedule::GenSysFuncGraph(int layer) const { if (cmptSysFuncs.writeSysFuncs.empty()) continue; - SysFuncGraph* subgraph = CreateFrameObject(&frame_rsrc); + SysFuncGraph* subgraph = CreateFrameObject(frame_rsrc.get()); graph->SubGraph(*subgraph, std::span{ cmptSysFuncs.writeSysFuncs.data(), cmptSysFuncs.writeSysFuncs.size() }); auto [success, sorted_wirtes] = subgraph->Toposort(); assert(success); diff --git a/src/core/World.cpp b/src/core/World.cpp index 88b293d..b8bac6a 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -8,43 +8,43 @@ using namespace Ubpa::UECS; using namespace Ubpa; using namespace std; -World::World(const World& w) - : +World::World() : + jobRsrc{ std::make_unique() }, + systemMngr{ this } {} + +World::World(const World& w) : jobRsrc{ std::make_unique() }, systemMngr{ w.systemMngr, this }, - entityMngr{ w.entityMngr } -{} + entityMngr{ w.entityMngr }, + schedule{ w.schedule } {} -World::World(World&& w) noexcept - : +World::World(World&& w) noexcept : jobRsrc{ std::make_unique() }, systemMngr{ std::move(w.systemMngr), this }, - entityMngr{ std::move(w.entityMngr) } -{} + entityMngr{ std::move(w.entityMngr) }, + schedule{ std::move(w.schedule) }{} World::~World() { + schedule.Clear(); systemMngr.Clear(); entityMngr.Clear(); } void World::Update() { - // 1. clear + // 1. update schedule - frame_sync_rsrc.release(); schedule.Clear(); - - // 2. run systems schedule - for (const auto& ID : systemMngr.GetActiveSystemIDs()) systemMngr.Update(ID, schedule); - // 3. generate job graph + // 2. run job graph for several layers inRunningJobGraph = true; auto* table = schedule.CreateFrameObject> (std::pmr::unordered_map::allocator_type{ schedule.GetFrameMonotonicResource() }); for (const auto& [layer, layerinfo] : schedule.layerInfos) { + assert(layer != SpecialLayer); for (const auto& [hashcode, func] : layerinfo.sysFuncs) { auto* job_buffer = jobRsrc->allocate(sizeof(Job), alignof(Job)); auto* job = new(job_buffer)Job{ std::string{func->Name()} }; @@ -74,28 +74,39 @@ void World::Update() { } inRunningJobGraph = false; - // 4. update version + // 3. update version version++; entityMngr.UpdateVersion(version); + + // 4. clear frame resource + frame_sync_rsrc.release(); } string World::DumpUpdateJobGraph() const { return jobGraph.dump(); } -void World::Run(SystemFunc* sys) { +CommandBuffer World::Run(SystemFunc* sys) { if (sys->IsParallel()) { assert(!inRunningJobGraph); Job job; - entityMngr.AutoGen(this, &job, sys, 0); + entityMngr.AutoGen(this, &job, sys, SpecialLayer); executor.run(job).wait(); } else - entityMngr.AutoGen(this, nullptr, sys, 0); + entityMngr.AutoGen(this, nullptr, sys, SpecialLayer); + + auto target = lcommandBuffer.find(SpecialLayer); + if (target == lcommandBuffer.end()) + return {}; + CommandBuffer rst = std::move(target->second); + lcommandBuffer.erase(target); + return rst; } // after running Update UGraphviz::Graph World::GenUpdateFrameGraph(int layer) const { + assert(layer != SpecialLayer); std::string title = "Update Frame Graph [layer: " + std::to_string(layer) + "]"; UGraphviz::Graph graph(std::move(title), true); @@ -347,6 +358,7 @@ void World::AddCommandBuffer(CommandBuffer cb, int layer) { } void World::RunCommands(int layer) { + assert(layer != SpecialLayer); auto target = lcommandBuffer.find(layer); if (target == lcommandBuffer.end()) return;