#include "stage.h"
-#include <msp/debug/demangle.h>
#include <msp/strings/format.h>
#include "accessguard.h"
#include "camera.h"
{
scheduler.remove_system(s);
erase_if(systems, [&s](auto &p){ return p.get()==&s; });
- pending_reschedule = true;
}
void Stage::set_active_camera(Handle<Camera> c)
void Stage::tick(Time::TimeDelta dt)
{
- if(pending_reschedule)
- {
- scheduler.schedule();
- pending_reschedule = false;
- }
-
for(const auto &s: systems)
s->early_tick();
- {
-#ifdef DEBUG
- AccessGuard::BlockForScope _block;
-#endif
- for(const SystemScheduler::Group &g: scheduler.get_groups())
- for(System *s: g.systems)
- {
- System::Activator act(*s);
- try
- {
- s->tick(dt);
- }
- catch(const invalid_access &exc)
- {
- throw invalid_access(format("%s by %s", exc.what(), Debug::demangle(typeid(*s).name())));
- }
- }
- }
+ scheduler.run(dt);
for(const auto &s: systems)
s->deferred_tick();
std::vector<std::unique_ptr<System>> systems;
SystemScheduler scheduler;
Handle<Camera> active_camera;
- bool pending_reschedule = false;
public:
Stage(const std::string &, ThreadPool &, Reflection::Reflector &, DataFile::Collection &);
auto &sys = static_cast<T &>(*systems.emplace_back(std::make_unique<T>(*this, std::forward<Args>(args)...)));
reflector.get_or_create_class<T>().template set_polymorphic_base<System>(sys);
scheduler.add_system(sys);
- pending_reschedule = true;
return sys;
}
void SystemScheduler::add_system(System &s)
{
+ if(nodes.size()>=MAX_SYSTEMS)
+ throw invalid_state("SystemScheduler::add_system");
nodes.emplace_back(&s, reflector.find_class(typeid(s)));
+ pending_reschedule = true;
}
void SystemScheduler::remove_system(System &s)
{
erase_if(nodes, [&s](const GraphNode &n){ return n.system==&s; });
- for(auto i=groups.begin(); i!=groups.end(); )
- {
- erase_if(i->systems, [&s](System *gs){ return gs==&s; });
- if(i->systems.empty())
- i = groups.erase(i);
- else
- ++i;
- }
+ pending_reschedule = true;
}
void SystemScheduler::schedule()
{
for(GraphNode &n: nodes)
- {
- n.scheduled_order = ~0U;
- n.predecessors.clear();
- }
+ n.prerequisites = 0;
- for(auto i=nodes.begin(); i!=nodes.end(); ++i)
- for(auto j=i; ++j!=nodes.end(); )
+ for(size_t i=0; i+1<nodes.size(); ++i)
+ for(size_t j=i+1; j<nodes.size(); ++j)
{
- int order = get_order(*i, *j);
+ int order = get_order(nodes[i], nodes[j]);
if(order<0)
- j->predecessors.push_back(&*i);
+ nodes[j].prerequisites |= 1ULL<<i;
else if(order>0)
- i->predecessors.push_back(&*j);
+ nodes[i].prerequisites |= 1ULL<<j;
}
-
- groups.clear();
- unsigned unscheduled_count = nodes.size();
- while(unscheduled_count)
- {
- unsigned order = groups.size();
- Group &group = groups.emplace_back();
- for(GraphNode &n: nodes)
- if(!~n.scheduled_order && ranges::all_of(n.predecessors, [order](GraphNode *p){ return p->scheduled_order<order; }))
- {
- group.systems.push_back(n.system);
- n.scheduled_order = order;
- --unscheduled_count;
- }
- }
}
int SystemScheduler::get_order(const GraphNode &node1, const GraphNode &node2)
return data_order;
}
+void SystemScheduler::run(Time::TimeDelta dt)
+{
+ if(nodes.empty())
+ return;
+
+ if(pending_reschedule)
+ {
+ schedule();
+ pending_reschedule = false;
+ }
+
+#ifdef DEBUG
+ AccessGuard::BlockForScope _block;
+#endif
+
+ uint64_t pending = (~0ULL)>>(MAX_SYSTEMS-nodes.size());
+ while(pending)
+ {
+ for(size_t i=0; i<nodes.size(); ++i)
+ if(!(pending&nodes[i].prerequisites))
+ {
+ System::Activator act(*nodes[i].system);
+ try
+ {
+ nodes[i].system->tick(dt);
+ }
+ catch(const invalid_access &exc)
+ {
+ throw invalid_access(format("%s by %s", exc.what(), nodes[i].type->get_name()));
+ }
+ pending &= ~(1ULL<<i);
+ }
+ }
+}
+
} // namespace Msp::Game
#define MSP_GAME_SYSTEMSCHEDULER_H_
#include <vector>
+#include <msp/time/timedelta.h>
#include "mspgame_api.h"
#include "reflection.h"
class MSPGAME_API SystemScheduler
{
public:
- struct Group
- {
- std::vector<System *> systems;
- };
+ using PrerequisiteMask = std::uint64_t;
+ static constexpr unsigned MAX_SYSTEMS = sizeof(PrerequisiteMask)*8;
-private:
struct GraphNode
{
System *system = nullptr;
Reflection::ClassBase *type = nullptr;
- std::vector<GraphNode *> predecessors;
- unsigned scheduled_order = 0;
+ PrerequisiteMask prerequisites = 0;
};
+private:
Reflection::Reflector &reflector;
std::vector<GraphNode> nodes;
- std::vector<Group> groups;
+ bool pending_reschedule = false;
public:
SystemScheduler(Reflection::Reflector &r): reflector(r) { }
static int get_order(const GraphNode &, const GraphNode &);
static int get_explicit_order(const GraphNode &, const GraphNode &);
static int get_data_order(const GraphNode &, const GraphNode &);
+
public:
- const std::vector<Group> &get_groups() const { return groups; }
+ void run(Time::TimeDelta);
};
} // namespace Msp::Game