diff --git a/kernel/src/kernel/render_2D.hpp b/kernel/src/kernel/render_2D.hpp index d88b079..51e938f 100644 --- a/kernel/src/kernel/render_2D.hpp +++ b/kernel/src/kernel/render_2D.hpp @@ -98,7 +98,7 @@ protected: static void run_prepare_data(Attached auto* object) { using Object = std::remove_pointer_t; auto& private_data = static_cast(object->d); - if constexpr (requires { private_data.prepare_data(object); }) private_data.prepare_data(object); + private_data.prepare_data(object); auto callback = [&](auto& value) { if constexpr (requires { value.after_prepare_data(object); }) value.after_prepare_data(object); }; @@ -108,6 +108,7 @@ public: struct Private : Prev_Private { using Run_Predicate = bool (*)(Root*, bool); using Rebuild_Predicate = bool (*)(Root*); + using Stage_Run = void (*)(Root*); using Graph_Builder = tf::Taskflow (*)(Root*, std::pmr::memory_resource*); using State_Access = State* (*)(Root*); using State_Notify = void (*)(Root*); @@ -116,14 +117,16 @@ public: Run_Predicate paint_predicate; Rebuild_Predicate prepare_rebuild_predicate; Rebuild_Predicate paint_rebuild_predicate; + Stage_Run prepare_run; + Stage_Run paint_run; Graph_Builder prepare_builder; Graph_Builder paint_builder; State_Access state_access; State_Notify state_notify; }; const Dispatch* dispatch{}; - tf::Taskflow prepare_graph; - tf::Taskflow paint_graph; + std::unique_ptr prepare_graph; + std::unique_ptr paint_graph; bool prepare_graph_built{}; bool paint_graph_built{}; bool should_rebuild_prepare_graph(Attached auto*, const State&) { @@ -138,22 +141,6 @@ public: bool should_paint(Attached auto*, const State&, bool dirty) { return dirty; } - tf::Taskflow build_prepare_graph(Attached auto* object, const State&, std::pmr::memory_resource*) { - tf::Taskflow taskflow; - taskflow.emplace([object] { - run_prepare_data(object); - }).name("renderable.prepare.data"); - return taskflow; - } - tf::Taskflow build_paint_graph(Attached auto* object, const State&, std::pmr::memory_resource*) { - using Object = std::remove_pointer_t; - tf::Taskflow taskflow; - taskflow.emplace([object] { - auto& private_data = static_cast(object->d); - private_data.paint(object); - }).name("renderable.paint.data"); - return taskflow; - } void prepare_data(Attached auto*) {} void after_prepare_data(Attached auto*) {} void paint(Attached auto*) {} @@ -183,16 +170,43 @@ private: auto& private_data = static_cast(value->d); return private_data.should_rebuild_paint_graph(value, *value->d.state.current); }, - [](Root* root, std::pmr::memory_resource* resource) { + [](Root* root) { + auto* value = static_cast(root); + run_prepare_data(value); + }, + [](Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); - return private_data.build_prepare_graph(value, *value->d.state.current, resource); - }, - [](Root* root, std::pmr::memory_resource* resource) { - auto* value = static_cast(root); - auto& private_data = static_cast(value->d); - return private_data.build_paint_graph(value, *value->d.state.current, resource); + private_data.paint(value); }, + []() -> Private::Graph_Builder { + if constexpr (requires(typename Object::Private& private_data, Object* value, const typename Object::State& state, std::pmr::memory_resource* resource) { + { private_data.build_prepare_graph(value, state, resource) } -> std::same_as; + }) { + return [](Root* root, std::pmr::memory_resource* resource) { + auto* value = static_cast(root); + auto& private_data = static_cast(value->d); + return private_data.build_prepare_graph(value, *value->d.state.current, resource); + }; + } + else { + return nullptr; + } + }(), + []() -> Private::Graph_Builder { + if constexpr (requires(typename Object::Private& private_data, Object* value, const typename Object::State& state, std::pmr::memory_resource* resource) { + { private_data.build_paint_graph(value, state, resource) } -> std::same_as; + }) { + return [](Root* root, std::pmr::memory_resource* resource) { + auto* value = static_cast(root); + auto& private_data = static_cast(value->d); + return private_data.build_paint_graph(value, *value->d.state.current, resource); + }; + } + else { + return nullptr; + } + }(), [](Root* root) { auto* value = static_cast(root); return static_cast(value->d.state.current); @@ -317,20 +331,34 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const auto& state = *dispatch->state_access(root); state.prepare_graph_rebuilt = false; state.prepare_execution_time_ns = 0; - bool rebuild = dispatch->prepare_rebuild_predicate(root); - if (!data->prepare_graph_built || rebuild) { - data->prepare_graph = dispatch->prepare_builder(root, detail::task_memory_resource()); - data->prepare_graph_built = true; - state.prepare_graph_rebuilt = true; - root->template mark_dirty(); + if (dispatch->prepare_builder) { + bool rebuild = dispatch->prepare_rebuild_predicate(root); + if (!data->prepare_graph_built || rebuild) { + *data->prepare_graph = dispatch->prepare_builder(root, detail::task_memory_resource()); + data->prepare_graph_built = true; + state.prepare_graph_rebuilt = true; + root->template mark_dirty(); + } + state.prepare_task_count = data->prepare_graph->num_tasks(); + } + else { + state.prepare_task_count = 1; } bool dirty = root->template dirty(); state.prepare_dirty = dirty; - state.prepare_task_count = data->prepare_graph.num_tasks(); state.prepare_executed = dispatch->prepare_predicate(root, dirty); return state.prepare_executed ? 0 : 1; }).name("renderable.prepare.condition"); - auto prepare_run = taskflow.composed_of(data->prepare_graph).name("renderable.prepare.graph"); + tf::Task prepare_run; + if (dispatch->prepare_builder) { + if (!data->prepare_graph) data->prepare_graph = std::make_unique(); + prepare_run = taskflow.composed_of(*data->prepare_graph).name("renderable.prepare.graph"); + } + else { + prepare_run = taskflow.emplace([dispatch, root] { + dispatch->prepare_run(root); + }).name("renderable.prepare.data"); + } auto prepare_done = taskflow.emplace([dispatch, root] { auto& state = *dispatch->state_access(root); if (!state.prepare_executed) return; @@ -343,20 +371,34 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const auto& state = *dispatch->state_access(root); state.paint_graph_rebuilt = false; state.paint_execution_time_ns = 0; - bool rebuild = dispatch->paint_rebuild_predicate(root); - if (!data->paint_graph_built || rebuild) { - data->paint_graph = dispatch->paint_builder(root, detail::task_memory_resource()); - data->paint_graph_built = true; - state.paint_graph_rebuilt = true; - root->template mark_dirty(); + if (dispatch->paint_builder) { + bool rebuild = dispatch->paint_rebuild_predicate(root); + if (!data->paint_graph_built || rebuild) { + *data->paint_graph = dispatch->paint_builder(root, detail::task_memory_resource()); + data->paint_graph_built = true; + state.paint_graph_rebuilt = true; + root->template mark_dirty(); + } + state.paint_task_count = data->paint_graph->num_tasks(); + } + else { + state.paint_task_count = 1; } bool dirty = root->template dirty(); state.paint_dirty = dirty; - state.paint_task_count = data->paint_graph.num_tasks(); state.paint_executed = dispatch->paint_predicate(root, dirty); return state.paint_executed ? 0 : 1; }).name("renderable.paint.condition"); - auto paint_run = taskflow.composed_of(data->paint_graph).name("renderable.paint.graph"); + tf::Task paint_run; + if (dispatch->paint_builder) { + if (!data->paint_graph) data->paint_graph = std::make_unique(); + paint_run = taskflow.composed_of(*data->paint_graph).name("renderable.paint.graph"); + } + else { + paint_run = taskflow.emplace([dispatch, root] { + dispatch->paint_run(root); + }).name("renderable.paint.data"); + } auto paint_done = taskflow.emplace([dispatch, root] { auto& state = *dispatch->state_access(root); if (state.paint_executed) root->template take_dirty();