Skip to content

Commit

Permalink
CommandBuffer
Browse files Browse the repository at this point in the history
  • Loading branch information
Ubpa committed Mar 22, 2021
1 parent 1636998 commit 016f15f
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 50 deletions.
9 changes: 8 additions & 1 deletion include/UECS/Chunk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,12 @@ namespace Ubpa::UECS {
std::uint8_t data[ChunkSize];
};

using ChunkView = const Chunk*;
class ChunkView {
public:
ChunkView(const Chunk* c = nullptr) : chunk { c }{}
const Chunk* GetChunk() const noexcept { return chunk; }
const Chunk* operator->() const noexcept { return chunk; }
private:
const Chunk* chunk;
};
}
42 changes: 42 additions & 0 deletions include/UECS/CommandBuffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <functional>
#include <vector>
#include <map>

namespace Ubpa::UECS {
class CommandBuffer {
public:
void AddCommand(std::function<void()> command, int layer) { lcommands[layer].push_back(std::move(command)); }
void AddCommandBuffer(CommandBuffer cb) {
for (auto& [layer, cmds] : cb.lcommands) {
auto& dst = lcommands[layer];
dst.reserve(dst.size() + cmds.size());
for (auto& cmd : cmds)
dst.push_back(std::move(cmd));
}
}
bool Empty() const noexcept {
for (const auto& [layer, cmds] : lcommands) {
if (!cmds.empty())
return false;
}
return true;
}
void Clear() { lcommands.clear(); }

auto& GetCommands() noexcept { return lcommands; }
const auto& GetCommands() const noexcept { return lcommands; }
private:
std::map<int, std::vector<std::function<void()>>> lcommands;
};

class CommandBufferView {
public:
CommandBufferView(CommandBuffer* cb = nullptr) : commandBuffer{ cb } {}
CommandBuffer* GetCommandBuffer() const noexcept { return commandBuffer; }
CommandBuffer* operator->()const noexcept { return commandBuffer; }
private:
CommandBuffer* commandBuffer;
};
}
7 changes: 0 additions & 7 deletions include/UECS/Schedule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,6 @@ namespace Ubpa::UECS {
ChunkJobConfig config
);

Schedule& RegisterCommand(std::function<void(World*)> command, int layer = 0) {
commandBuffer[layer].push_back(std::move(command));
return *this;
}

Schedule& Order(std::string_view x, std::string_view y);

Schedule& AddNone(std::string_view sys, TypeID);
Expand Down Expand Up @@ -159,8 +154,6 @@ namespace Ubpa::UECS {

std::unordered_map<std::size_t, small_vector<TypeID>> sysNones;

std::map<int, std::vector<std::function<void(World*)>>> commandBuffer;

mutable std::pmr::monotonic_buffer_resource frame_rsrc; // release in every frame
std::string_view RegisterFrameString(std::string_view str);

Expand Down
9 changes: 6 additions & 3 deletions include/UECS/SystemFunc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "CmptsView.hpp"
#include "SingletonsView.hpp"
#include "Chunk.hpp"
#include "CommandBuffer.hpp"

#include <functional>

Expand All @@ -24,9 +25,11 @@ namespace Ubpa::UECS {
// * std::size_t indexInQuery
// * <tagged-components>: {LastFrame|Write|Latest}<Cmpt>...
// * CmptsView
// * CommandBufferView
// 2. Mode::Chunk
// * std::size_t entityBeginIndexInQuery
// * ChunkView (necessary)
// * CommandBufferView
// 3. Mode::Job
// * Write<Singleton<Cmpt>> (only job can write singletons)
class SystemFunc {
Expand Down Expand Up @@ -60,8 +63,8 @@ namespace Ubpa::UECS {

std::size_t GetValue() const noexcept { return hashCode; }

void operator()(World*, SingletonsView, Entity, std::size_t entityIndexInQuery, CmptsView) const;
void operator()(World*, SingletonsView, std::size_t entityBeginIndexInQuery, ChunkView) const;
void operator()(World*, SingletonsView, Entity, std::size_t entityIndexInQuery, CmptsView, CommandBufferView) const;
void operator()(World*, SingletonsView, std::size_t entityBeginIndexInQuery, ChunkView, CommandBufferView) const;
void operator()(World*, SingletonsView) const;

Mode GetMode() const noexcept { return mode; }
Expand All @@ -73,7 +76,7 @@ namespace Ubpa::UECS {
std::string_view name;
std::size_t hashCode; // after name
bool isParallel;
std::function<void(World*, SingletonsView, Entity, std::size_t, CmptsView, ChunkView)> func;
std::function<void(World*, SingletonsView, Entity, std::size_t, CmptsView, ChunkView, CommandBufferView)> func;
};
}

Expand Down
4 changes: 3 additions & 1 deletion include/UECS/World.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "Entity.hpp"
#include "CommandBuffer.hpp"
#include "SystemMngr.hpp"
#include "EntityMngr.hpp"
#include "Schedule.hpp"
Expand Down Expand Up @@ -33,6 +34,7 @@ namespace Ubpa::UECS {
void Update();

void AddCommand(std::function<void()> command, int layer = 0);
void AddCommandBuffer(CommandBuffer cb);

// after running Update()
// you can use graphviz to vistualize the graph
Expand Down Expand Up @@ -130,7 +132,7 @@ namespace Ubpa::UECS {
std::unique_ptr<std::pmr::unsynchronized_pool_resource> jobRsrc;

// command
std::map<int, std::vector<std::function<void()>>> commandBuffer;
CommandBuffer commandBuffer;
std::mutex commandBufferMutex;
void RunCommands();

Expand Down
5 changes: 0 additions & 5 deletions include/UECS/details/CmptTag.inl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace Ubpa::UECS {
struct Entity;
class CmptLocator;
class World;
class Chunk;
}

namespace Ubpa::UECS {
Expand Down Expand Up @@ -172,8 +171,6 @@ namespace Ubpa::UECS {
struct DecayArg : DecayTag<Arg> {};
template<>
struct DecayArg<const World*> : std::type_identity<World*> {};
template<>
struct DecayArg<const Chunk*> : std::type_identity<const Chunk*> {};

// ====

Expand All @@ -187,14 +184,12 @@ namespace Ubpa::UECS {
template<typename Cmpt> struct IsWrite<Cmpt*> : std::true_type {};
template<typename Cmpt> struct IsWrite<const Cmpt*> : std::false_type {};
template<> struct IsWrite<World*> : std::false_type {};
template<> struct IsWrite<Chunk*> : std::false_type { static_assert("you should use const Chunk*"); };

template<typename T> struct IsLatest : std::false_type {};
template<typename Cmpt> struct IsLatest<Latest<Cmpt>> : std::true_type {};
template<typename Cmpt> struct IsLatest<Latest<Singleton<Cmpt>>> : std::false_type {};
template<typename Cmpt> struct IsLatest<const Cmpt*> : std::true_type {};
template<> struct IsLatest<const World*> : std::false_type {};
template<> struct IsLatest<const Chunk*> : std::false_type {};

template<typename T> struct IsLastFrameSingleton : std::false_type {};
template<typename Cmpt> struct IsLastFrameSingleton<LastFrame<Singleton<Cmpt>>> : std::true_type {};
Expand Down
11 changes: 7 additions & 4 deletions include/UECS/details/SystemFunc.inl
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ namespace Ubpa::UECS {
!Contain_v<ArgList, Entity>
&& !Contain_v<ArgList, std::size_t>
&& !Contain_v<ArgList, CmptsView>
&& !Contain_v<ArgList, ChunkView>,
"(Mode::Job) SystemFunc's argument list cann't have Entity, indexInQuery CmptsView or ChunkView"
);
&& !Contain_v<ArgList, ChunkView>
&& !Contain_v<ArgList, CommandBufferView>,
"(Mode::Job) SystemFunc's argument list cann't have Entity, indexInQuery CmptsView, ChunkView or CommandBufferView"
);
}
}

Expand All @@ -125,7 +126,8 @@ namespace Ubpa::UECS::details {
Entity e,
std::size_t entityIndexInQuery,
CmptsView cmpts,
ChunkView chunkView)
ChunkView chunkView,
CommandBufferView cbv)
{
auto args = std::tuple{
w,
Expand All @@ -136,6 +138,7 @@ namespace Ubpa::UECS::details {
cmpts,
reinterpret_cast<NonSingletons*>(cmpts.Components()[Find_v<NonSingletonList, NonSingletons>].Ptr())...,
chunkView,
cbv
};
func(std::get<DecayedArgs>(args)...);
};
Expand Down
Empty file added src/core/CommandBuffer.cpp
Empty file.
37 changes: 25 additions & 12 deletions src/core/EntityMngr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <UECS/SystemFunc.hpp>
#include <UECS/IListener.hpp>
#include <UECS/CommandBuffer.hpp>

using namespace Ubpa::UECS;
using namespace std;
Expand Down Expand Up @@ -176,7 +177,7 @@ void EntityMngr::Attach(Entity e, std::span<const TypeID> types) {
auto target = dstArchetype->GetCmptTraits().GetTypes().find(type);
assert(target != dstArchetype->GetCmptTraits().GetTypes().end());
auto idx = static_cast<std::size_t>(std::distance(dstArchetype->GetCmptTraits().GetTypes().begin(), target));
srcArchetype->GetCmptTraits().GetTraits()[idx].DefaultConstruct(info.archetype->WriteAt(type, info.idxInArchetype).Ptr());
dstArchetype->GetCmptTraits().GetTraits()[idx].DefaultConstruct(info.archetype->WriteAt(type, info.idxInArchetype).Ptr());
}
}

Expand Down Expand Up @@ -321,12 +322,13 @@ bool EntityMngr::GenEntityJob(World* w, Job* job, SystemFunc* sys) const {
auto singletons = LocateSingletons(sys->singletonLocator);
if (!sys->singletonLocator.SingletonTypes().empty() && singletons.empty())
return false;


const auto& archetypes = QueryArchetypes(sys->entityQuery);
if (archetypes.empty())
return false;

if (sys->IsParallel()) {
assert(job);
const auto& archetypes = QueryArchetypes(sys->entityQuery);
if (archetypes.empty())
return false;
std::size_t indexOffsetInQuery = 0;
for (Archetype* archetype : archetypes) {
auto [chunkEntity, chunkCmpts, sizes] = archetype->Locate(sys->entityQuery.locator.AccessTypeIDs());
Expand All @@ -344,29 +346,32 @@ bool EntityMngr::GenEntityJob(World* w, Job* job, SystemFunc* sys) const {
std::size_t indexOffsetInQueryChunk = indexOffsetInQuery + idxOffsetInChunk;
CmptsView chunkView{ std::span{cmpts.data(), cmpts.size()} };
SingletonsView singletonsView{ std::span{singletons.data(), singletons.size()} };

CommandBuffer cb;
std::size_t J = min(chunkCapacity, num - idxOffsetInChunk);
for (std::size_t j = 0; j < J; j++) {
(*sys)(
w,
singletonsView,
entities[j],
indexOffsetInQueryChunk + j,
chunkView
chunkView,
&cb
);
for (std::size_t k = 0; k < cmpts.size(); k++)
reinterpret_cast<uint8_t*&>(cmpts[k].p) += sizes[k];
}
w->AddCommandBuffer(std::move(cb));
});
}

indexOffsetInQuery += num;
}
}
else {
auto work = [this, singletons = std::move(singletons), sys, w]() {
auto work = [this, singletons = std::move(singletons), sys, w, archetypes]() {
CommandBuffer cb;
std::size_t indexOffsetInQuery = 0;
for (Archetype* archetype : QueryArchetypes(sys->entityQuery)) {
for (Archetype* archetype : archetypes) {
auto [chunkEntity, chunkCmpts, sizes] = archetype->Locate(sys->entityQuery.locator.AccessTypeIDs());

std::size_t num = archetype->EntityNum();
Expand All @@ -388,7 +393,8 @@ bool EntityMngr::GenEntityJob(World* w, Job* job, SystemFunc* sys) const {
singletonsView,
chunkEntity[i][j],
indexOffsetInQueryChunk + j,
chunkView
chunkView,
&cb
);
for (std::size_t k = 0; k < chunkCmpts[i].size(); k++)
reinterpret_cast<uint8_t*&>(chunkCmpts[i][k].p) += sizes[k];
Expand All @@ -397,6 +403,7 @@ bool EntityMngr::GenEntityJob(World* w, Job* job, SystemFunc* sys) const {

indexOffsetInQuery += num;
}
w->AddCommandBuffer(std::move(cb));
};

if (job)
Expand Down Expand Up @@ -433,12 +440,15 @@ bool EntityMngr::GenChunkJob(World* w, Job* job, SystemFunc* sys) const {
std::size_t idxOffsetInChunk = i * chunkCapacity;
std::size_t indexOffsetInQueryChunk = indexOffsetInQuery + idxOffsetInChunk;
job->emplace([=, singletons = singletons]() {
CommandBuffer cb;
(*sys)(
w,
SingletonsView{ std::span{singletons.data(), singletons.size()} },
indexOffsetInQueryChunk,
archetype->chunks[i]
archetype->chunks[i],
&cb
);
w->AddCommandBuffer(std::move(cb));
});
}

Expand All @@ -449,6 +459,7 @@ bool EntityMngr::GenChunkJob(World* w, Job* job, SystemFunc* sys) const {
auto work = [this, w, sys, singletons = std::move(singletons)]() {
SingletonsView singletonsView{ std::span{singletons.data(), singletons.size()} };

CommandBuffer cb;
std::size_t indexOffsetInQuery = 0;
for (Archetype* archetype : QueryArchetypes(sys->entityQuery)) {
std::size_t num = archetype->EntityNum();
Expand All @@ -465,10 +476,12 @@ bool EntityMngr::GenChunkJob(World* w, Job* job, SystemFunc* sys) const {
w,
singletonsView,
indexOffsetInQueryChunk,
archetype->chunks[i]
archetype->chunks[i],
&cb
);
}
}
w->AddCommandBuffer(std::move(cb));
};

if (job)
Expand Down
11 changes: 7 additions & 4 deletions src/core/SystemFunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,29 @@

using namespace Ubpa::UECS;

void SystemFunc::operator()(World* w, SingletonsView singletonsView, Entity e, std::size_t entityIndexInQuery, CmptsView cmptsView) const {
void SystemFunc::operator()(World* w, SingletonsView singletonsView, Entity e, std::size_t entityIndexInQuery, CmptsView cmptsView, CommandBufferView cbv) const {
assert(mode == Mode::Entity);
return func(
w,
singletonsView,
e,
entityIndexInQuery,
cmptsView,
{}
{},
cbv
);
}

void SystemFunc::operator()(World* w, SingletonsView singletonsView, std::size_t entityBeginIndexInQuery, ChunkView chunkView) const {
void SystemFunc::operator()(World* w, SingletonsView singletonsView, std::size_t entityBeginIndexInQuery, ChunkView chunkView, CommandBufferView cbv) const {
assert(mode == Mode::Chunk);
return func(
w,
singletonsView,
Entity::Invalid(),
entityBeginIndexInQuery,
{},
chunkView
chunkView,
cbv
);
}

Expand All @@ -34,6 +36,7 @@ void SystemFunc::operator()(World* w, SingletonsView singletonsView) const {
Entity::Invalid(),
static_cast<std::size_t>(-1),
{},
{},
{}
);
}
Loading

0 comments on commit 016f15f

Please sign in to comment.