diff --git a/framework/engine/src/mm/update_strategies/default_strategy.cpp b/framework/engine/src/mm/update_strategies/default_strategy.cpp index ad43855..f4e0938 100644 --- a/framework/engine/src/mm/update_strategies/default_strategy.cpp +++ b/framework/engine/src/mm/update_strategies/default_strategy.cpp @@ -1,6 +1,7 @@ #include "./default_strategy.hpp" #include +#include namespace MM::UpdateStrategies { @@ -206,17 +207,27 @@ void SingleThreadedDefault::doUpdate(MM::Engine& engine) { // post runType(engine, update_phase_t::POST); - if (!_defered_queue.empty()) { - for (auto&& fn : _defered_queue) { + // simulate async + for (size_t i = 0; !_async_queue.empty() && i < _max_async_per_tick; i++) { + _async_queue.back()(engine); + _async_queue.pop_back(); + } + + if (!_deferred_queue.empty()) { + for (auto&& fn : _deferred_queue) { fn(engine); } - _defered_queue.clear(); + _deferred_queue.clear(); } } -void SingleThreadedDefault::addDefered(std::function function) { - _defered_queue.emplace_back(std::move(function)); +void SingleThreadedDefault::addDeferred(std::function function) { + _deferred_queue.emplace_back(std::move(function)); +} + +void SingleThreadedDefault::addAsync(std::function function) { + _async_queue.emplace_back(std::move(function)); } #undef __L_ASSERT diff --git a/framework/engine/src/mm/update_strategies/default_strategy.hpp b/framework/engine/src/mm/update_strategies/default_strategy.hpp index 473701c..8ded6ac 100644 --- a/framework/engine/src/mm/update_strategies/default_strategy.hpp +++ b/framework/engine/src/mm/update_strategies/default_strategy.hpp @@ -44,7 +44,9 @@ class SingleThreadedDefault : public MM::UpdateStrategies::UpdateStrategy { std::set _main_active; std::set _post_active; - std::vector> _defered_queue; + std::vector> _deferred_queue; + std::vector> _async_queue; + const size_t _max_async_per_tick = 5; // prevent blocking, this should be finetuned private: Graph& getGraph(update_phase_t phase); @@ -72,7 +74,9 @@ class SingleThreadedDefault : public MM::UpdateStrategies::UpdateStrategy { bool depend(const update_key_t A, const update_key_t B) override; - void addDefered(std::function function) override; + void addDeferred(std::function function) override; + + void addAsync(std::function function) override; }; } // MM::UpdateStrategies diff --git a/framework/engine/src/mm/update_strategies/update_strategy.hpp b/framework/engine/src/mm/update_strategies/update_strategy.hpp index 9d9a194..77533f8 100644 --- a/framework/engine/src/mm/update_strategies/update_strategy.hpp +++ b/framework/engine/src/mm/update_strategies/update_strategy.hpp @@ -69,10 +69,13 @@ class UpdateStrategy { // WIP: // dont use, if you are not using it to modify the engine. - // you usualy dont need to use this, if you think you need to use this, you probably dont. - //virtual void addFixedDefered(std::function function) = 0; - virtual void addDefered(std::function function) = 0; // called after everything + // you usually dont need to use this, if you think you need to use this, you probably dont. + virtual void addDeferred(std::function function) = 0; // called after everything + // adds a task, which does not need to be completed on the end of the tick. + // warning: in a single-threaded environment, they will still be done on the main thread, so blocking is not a option + // note: the US might decide to limit the amount of executed asyncs per tick (eg. when single-threaded) + virtual void addAsync(std::function function) = 0; //virtual std::future addAsync(std::function function) = 0; }; diff --git a/framework/engine/test/default_us_test.cpp b/framework/engine/test/default_us_test.cpp index e8e03c0..abab5bf 100644 --- a/framework/engine/test/default_us_test.cpp +++ b/framework/engine/test/default_us_test.cpp @@ -29,6 +29,33 @@ TEST(default_update_strategy, simple_update) { engine.update(); } +// note: we test pure single-threaded behaviour, so nothing needs to be thread save +TEST(default_update_strategy, async) { + int counter = 1; + MM::Engine engine(std::make_unique()); + ASSERT_EQ(counter, 1); + + engine.getUpdateStrategy().addAsync([&counter](MM::Engine&) { counter++; }); + + engine.update(); + + ASSERT_EQ(counter, 2); + + for (size_t i = 0; i < 100; i++) { + engine.getUpdateStrategy().addAsync([&counter](MM::Engine&) { counter++; }); + } + + // make sure we dont have an infinity loop in case something is wrong + size_t max_loop_safety_count = 0; + + do { + engine.update(); + max_loop_safety_count++; + } while (counter != 102 && max_loop_safety_count < 10000); + + ASSERT_EQ(counter, 102); +} + TEST(default_update_strategy, service) { class TmpMockService : public MockService { public: @@ -56,7 +83,6 @@ TEST(default_update_strategy, service) { } } - TEST(default_update_strategy, run_1) { class TmpMockService : public MockService { int& _counter; @@ -96,7 +122,7 @@ TEST(default_update_strategy, run_1) { ASSERT_TRUE(engine.enableService()); ASSERT_EQ(counter, 1); - engine.getUpdateStrategy().addDefered([](MM::Engine& e) { e.stop(); }); + engine.getUpdateStrategy().addDeferred([](MM::Engine& e) { e.stop(); }); engine.run(); diff --git a/framework/engine/test/update_strategy_test.cpp b/framework/engine/test/update_strategy_test.cpp index 3b29ce2..af260d3 100644 --- a/framework/engine/test/update_strategy_test.cpp +++ b/framework/engine/test/update_strategy_test.cpp @@ -1,4 +1,3 @@ -#include "mm/services/service.hpp" #include #include @@ -36,7 +35,8 @@ class MockUpdateStrategy : public MM::UpdateStrategies::UpdateStrategy { MOCK_METHOD(bool, depend, (const MM::UpdateStrategies::update_key_t A, const MM::UpdateStrategies::update_key_t B), (override)); - MOCK_METHOD(void, addDefered, (std::function function), (override)); + MOCK_METHOD(void, addDeferred, (std::function function), (override)); + MOCK_METHOD(void, addAsync, (std::function function), (override)); }; class MockService : public MM::Services::Service { diff --git a/framework/screen_director/src/mm/services/screen_director.cpp b/framework/screen_director/src/mm/services/screen_director.cpp index 00e5a5c..db105b3 100644 --- a/framework/screen_director/src/mm/services/screen_director.cpp +++ b/framework/screen_director/src/mm/services/screen_director.cpp @@ -39,7 +39,7 @@ std::vector ScreenDirector::registerUpdate void ScreenDirector::update(MM::Engine& engine) { if (curr_screen_id != queued_screen_id) { - engine.getUpdateStrategy().addDefered([this](MM::Engine& e) { + engine.getUpdateStrategy().addDeferred([this](MM::Engine& e) { changeScreenTo(e, queued_screen_id); }); } diff --git a/framework/sdl_service/test/start_test.cpp b/framework/sdl_service/test/start_test.cpp index e850cb4..68b753f 100644 --- a/framework/sdl_service/test/start_test.cpp +++ b/framework/sdl_service/test/start_test.cpp @@ -104,7 +104,7 @@ TEST(sdl_service, event_handle_reg) { }; // register forge - engine.getUpdateStrategy().addDefered(event_forge_f); + engine.getUpdateStrategy().addDeferred(event_forge_f); // register sdl event handler to just stop the engine auto* stop_event_hook_h = sdl_ss_ptr->addEventHandler([&engine](const SDL_Event&){ engine.stop(); return true; }); diff --git a/framework/simple_scene/test/ss_test.cpp b/framework/simple_scene/test/ss_test.cpp index 3649cc1..347ac47 100644 --- a/framework/simple_scene/test/ss_test.cpp +++ b/framework/simple_scene/test/ss_test.cpp @@ -61,7 +61,7 @@ TEST(simple_scene, change_scene) { ASSERT_TRUE(sss->getScene().valid(e)); //engine.fixedUpdate(); - engine.getUpdateStrategy().addDefered([](MM::Engine& eng) {eng.stop();}); + engine.getUpdateStrategy().addDeferred([](MM::Engine& eng) {eng.stop();}); engine.run(); ASSERT_FALSE(sss->getScene().valid(e)); diff --git a/systems/player_velocity/test/player_velocity_test.cpp b/systems/player_velocity/test/player_velocity_test.cpp index 67419a9..33c905e 100644 --- a/systems/player_velocity/test/player_velocity_test.cpp +++ b/systems/player_velocity/test/player_velocity_test.cpp @@ -37,8 +37,9 @@ TEST(player_velocity, basic_run) { //v.velocity = { 1.f, 1.f }; //v.rotation = 0.f; - engine.getUpdateStrategy().addDefered([](auto& e) { e.stop(); }); - engine.run(); + //engine.getUpdateStrategy().addDeferred([](auto& e) { e.stop(); }); + //engine.run(); + engine.update(); //ASSERT_EQ(t.position.x, 1.f * delta); // TODO: TEST