From 90a0b89a6ccc7e04124ddb2b402dfc8374fdb09c Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Thu, 20 Aug 2026 09:05:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=8D=A2=E4=B8=BA=20taskflow=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/cmake/rely.cmake | 60 ++-- kernel/main.cmake | 9 +- kernel/src/kernel/base/object.hpp | 5 + kernel/src/kernel/base/rely.hpp | 5 +- kernel/src/kernel/base/rely_storage.hpp | 9 + kernel/src/kernel/render_2D.cpp | 38 +++ kernel/src/kernel/render_2D.hpp | 402 ++++++++---------------- 7 files changed, 231 insertions(+), 297 deletions(-) diff --git a/kernel/cmake/rely.cmake b/kernel/cmake/rely.cmake index 92128b7..23debb8 100644 --- a/kernel/cmake/rely.cmake +++ b/kernel/cmake/rely.cmake @@ -1,34 +1,42 @@ include_guard(GLOBAL) block() - rcl_init(render_kernel) - set(oneTBB_option ${base_options}) - list(APPEND oneTBB_option - -DBUILD_SHARED_LIBS=ON - -DTBB_BUILD=ON - -DTBB_INSTALL=ON - -DTBB_TEST=OFF - -DTBB_EXAMPLES=OFF - -DTBB_STRICT=OFF - -DTBB4PY_BUILD=OFF - -DTBBMALLOC_BUILD=OFF - -DTBBMALLOC_PROXY_BUILD=OFF + rcl_init(aethera_kernel) + set(taskflow_option ${base_options}) + list(APPEND taskflow_option + -DTF_BUILD_EXAMPLES=OFF + -DTF_BUILD_TESTS=OFF + -DTF_BUILD_BENCHMARKS=OFF + -DTF_BUILD_PROFILER=OFF + -DTF_BUILD_CUDA=OFF + -DTF_BUILD_MODULES=OFF ) - _register_git_cmake_library(render_kernel::oneTBB - "https://github.com/uxlfoundation/oneTBB.git" - "v2023.1.0" + _register_git_cmake_library(aethera_kernel::taskflow + "https://github.com/taskflow/taskflow.git" + "v4.1.0" ) - rcl_get_effective_install_dir(render_kernel::oneTBB ONETBB_ROOT) - set(TBB_CONFIG_DIR "${ONETBB_ROOT}/lib/cmake/TBB") - rcl_cmake_library_set_cmake_options(render_kernel::oneTBB ${oneTBB_option}) - rcl_cmake_library_set_other_use_opt(render_kernel::oneTBB - "-DTBB_DIR=\"${TBB_CONFIG_DIR}\"" + rcl_get_effective_install_dir( + aethera_kernel::taskflow + TASKFLOW_ROOT ) - rcl_cmake_library_set_init_script(render_kernel::oneTBB - "set(ONETBB_ROOT \"${ONETBB_ROOT}\")" - "set(TBB_DIR \"${TBB_CONFIG_DIR}\")" + set(Taskflow_DIR + "${TASKFLOW_ROOT}/share/cmake/Taskflow" ) - rcl_cmake_library_set_clear_script(render_kernel::oneTBB - "unset(ONETBB_ROOT)" - "unset(TBB_DIR)" + rcl_cmake_library_set_cmake_options( + aethera_kernel::taskflow + ${taskflow_option} + ) + rcl_cmake_library_set_other_use_opt( + aethera_kernel::taskflow + "-DTaskflow_DIR=\"${Taskflow_DIR}\"" + ) + rcl_cmake_library_set_init_script( + aethera_kernel::taskflow + "set(TASKFLOW_ROOT \"${TASKFLOW_ROOT}\")" + "set(Taskflow_DIR \"${Taskflow_DIR}\")" + ) + rcl_cmake_library_set_clear_script( + aethera_kernel::taskflow + "unset(TASKFLOW_ROOT)" + "unset(Taskflow_DIR)" ) endblock() \ No newline at end of file diff --git a/kernel/main.cmake b/kernel/main.cmake index 8998740..876d694 100644 --- a/kernel/main.cmake +++ b/kernel/main.cmake @@ -1,5 +1,5 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/rely.cmake) -set(Aethera_Kernel_dependencies render_kernel::oneTBB global::magic_enum global::expected) +set(Aethera_Kernel_dependencies aethera_kernel::taskflow global::magic_enum global::expected) if (Aethera_BUILD_TESTS) set(Aethera_Kernel_test_targets) list(APPEND Aethera_Kernel_dependencies global::GTest) @@ -13,7 +13,7 @@ if (Aethera_Kernel_dependencies_installed) endif () rcl_load_dependency_environment(${Aethera_Kernel_dependencies}) find_package(Threads REQUIRED) -find_package(TBB CONFIG REQUIRED) +find_package(Taskflow CONFIG REQUIRED) find_package(magic_enum CONFIG REQUIRED) find_package(tl-expected CONFIG REQUIRED) if (Aethera_BUILD_TESTS) @@ -30,9 +30,10 @@ target_include_directories(Aethera_Kernel PUBLIC ) target_compile_features(Aethera_Kernel PUBLIC cxx_std_20) target_link_libraries(Aethera_Kernel PUBLIC - TBB::tbb + Taskflow::Taskflow magic_enum::magic_enum - tl::expected) + tl::expected +) target_link_libraries(Aethera_Kernel PRIVATE Threads::Threads) function(Aethera_stage_kernel_runtime target) if (WIN32) diff --git a/kernel/src/kernel/base/object.hpp b/kernel/src/kernel/base/object.hpp index 7cad9d8..51e08ee 100644 --- a/kernel/src/kernel/base/object.hpp +++ b/kernel/src/kernel/base/object.hpp @@ -178,6 +178,11 @@ public: [[nodiscard]] const Rely& render_rely() const { return *d.rely_storage.template get().render; } + template ... Tags, detail::Rely_Render_State_Callback_For Callback> requires + detail::Unique_Types::value + void render_rely(Callback&& callback) { + d.rely_storage.template render(std::forward(callback)); + } template ... Tags, detail::Rely_Edit_Callback_For Callback> requires detail::Unique_Types::value std::expected edit_rely(Callback&& callback) { diff --git a/kernel/src/kernel/base/rely.hpp b/kernel/src/kernel/base/rely.hpp index 96e2d3d..25788a1 100644 --- a/kernel/src/kernel/base/rely.hpp +++ b/kernel/src/kernel/base/rely.hpp @@ -241,9 +241,10 @@ private: } template static Node::Bind node_bind() { - if constexpr (requires(Object* object, Node* node) { object->template bind_rely_node(node); }) { + if constexpr (requires(Object* object, Node* node) { object->bind_rely_node(node, object); }) { return [](Node* node, Root* root) { - static_cast(root)->template bind_rely_node(node); + auto* object = static_cast(root); + object->bind_rely_node(node, object); }; } else { diff --git a/kernel/src/kernel/base/rely_storage.hpp b/kernel/src/kernel/base/rely_storage.hpp index 818b61b..df9fa90 100644 --- a/kernel/src/kernel/base/rely_storage.hpp +++ b/kernel/src/kernel/base/rely_storage.hpp @@ -11,6 +11,8 @@ template concept Rely_View_Node_Callback = std::invocable; template concept Rely_Render_Callback = std::invocable; +template +concept Rely_Render_State_Callback_For = std::invocable&...>; } inline bool Root::mark_dirty_id(const void* tag, const void* dirty_key) { if (std::find(dirty_tags.begin(), dirty_tags.end(), tag) != dirty_tags.end()) return false; @@ -73,6 +75,13 @@ public: const auto& get() const { return std::get()>(relies); } + template >... Tags, Rely_Render_State_Callback_For Callback> requires Unique_Types::value + void render(Callback&& callback) { + std::invoke( + std::forward(callback), + static_cast&>(get())... + ); + } template >... Tags, Rely_Edit_Callback_For Callback> requires Unique_Types::value std::expected edit(Callback&& callback) { std::tuple...> next(*get().cache...); diff --git a/kernel/src/kernel/render_2D.cpp b/kernel/src/kernel/render_2D.cpp index e69de29..ad3f172 100644 --- a/kernel/src/kernel/render_2D.cpp +++ b/kernel/src/kernel/render_2D.cpp @@ -0,0 +1,38 @@ +#include "render_2D.hpp" +namespace aethera::_2D { +namespace { +class Task_Resource : Pinned { +private: + std::unique_ptr executor_value; + std::pmr::memory_resource* memory_value; +public: + Task_Resource() : memory_value(std::pmr::get_default_resource()) {} + static Task_Resource& instance() { + static Task_Resource value; + return value; + } + void initialize(std::size_t workers, std::shared_ptr worker_interface, Pmr pmr) { + executor_value = std::make_unique(workers, std::move(worker_interface)); + memory_value = pmr.resource(); + } + tf::Executor& executor() { + if (!executor_value) executor_value = std::make_unique(); + return *executor_value; + } + std::pmr::memory_resource* memory_resource() const noexcept { + return memory_value; + } +}; +} +void initialize(std::size_t workers, std::shared_ptr worker_interface, Pmr pmr) { + Task_Resource::instance().initialize(workers, std::move(worker_interface), pmr); +} +namespace detail { +tf::Executor& task_executor() { + return Task_Resource::instance().executor(); +} +std::pmr::memory_resource* task_memory_resource() noexcept { + return Task_Resource::instance().memory_resource(); +} +} +} diff --git a/kernel/src/kernel/render_2D.hpp b/kernel/src/kernel/render_2D.hpp index 5a72e29..aca0b39 100644 --- a/kernel/src/kernel/render_2D.hpp +++ b/kernel/src/kernel/render_2D.hpp @@ -1,10 +1,17 @@ #pragma once #include "base.hpp" -#include +#include namespace aethera::_2D { struct Prepare_Data_Tag {}; struct Paint_Tag {}; struct Color_Cache {}; +void initialize(std::size_t workers = std::thread::hardware_concurrency(), + std::shared_ptr worker_interface = nullptr, + Pmr pmr = {}); +namespace detail { +tf::Executor& task_executor(); +std::pmr::memory_resource* task_memory_resource() noexcept; +} struct Renderable; struct Secene : Impl, Rely_Type> { struct Prop : Prev_Prop {}; @@ -13,102 +20,14 @@ struct Secene : Impl, Rely_Type; - using Execute = oneapi::tbb::flow::async_node; - using Gateway = typename Execute::gateway_type; - struct Async_Tag {}; - struct Completion { - Gateway* gateway; - void operator()() const { - (void)gateway->try_put(Message{}); - gateway->release_wait(); - } - }; - Gate gate; - Execute execute; - template - Task(oneapi::tbb::flow::graph& graph, bool* enabled, Callback&& callback) : gate( - graph, - [](const Message&) { - return Message{}; - } - ), - execute( - graph, - oneapi::tbb::flow::unlimited, - [state = enabled, task = std::forward(callback)](const Message&, Gateway& gateway) mutable { - if (!state || *state) std::invoke(task); - (void)gateway.try_put(Message{}); - } - ) { - oneapi::tbb::flow::make_edge(gate, execute); - } - template Callback> - Task( - oneapi::tbb::flow::graph& graph, - bool* enabled, - Async_Tag, - Callback&& callback) : gate( - graph, - [](const Message&) { - return Message{}; - } - ), - execute( - graph, - oneapi::tbb::flow::unlimited, - [state = enabled, task = std::forward(callback)](const Message&, Gateway& gateway) mutable { - if (state && !*state) { - (void)gateway.try_put(Message{}); - return; - } - gateway.reserve_wait(); - try { - std::invoke(task, Completion{&gateway}); - } - catch (...) { - gateway.release_wait(); - throw; - } - } - ) { - oneapi::tbb::flow::make_edge(gate, execute); - } - }; - std::unique_ptr graph; - std::unique_ptr> start; - std::unique_ptr> tasks; - bool* building_enabled{}; + tf::Taskflow graph; + bool graph_ready{}; public: - template - Task* add(Callback&& callback) { - tasks->emplace_back(*graph, building_enabled, std::forward(callback)); - return &tasks->back(); - } - template Callback> - Task* add_async(Callback&& callback) { - tasks->emplace_back( - *graph, - building_enabled, - typename Task::Async_Tag{}, - std::forward(callback) - ); - return &tasks->back(); - } - void add_rely(Task* target, Task* source) { - oneapi::tbb::flow::make_edge(source->execute, target->gate); - } - template - void after_exchange(Object* object, Prop*, State*, const Prop*, const State*); - template Callback> - void render_scene(Object*, Callback&& callback) { + void after_exchange(Attached auto* object, Prop*, State*, const Prop*, const State*); + template Callback> + void render_scene(Root*, Callback&& callback) { Result result; - if (graph && tasks && !tasks->empty()) { - (void)start->try_put(Message{}); - graph->wait_for_all(); - } + if (graph_ready && !graph.empty()) detail::task_executor().run(graph).get(); std::invoke(std::forward(callback), std::as_const(result)); } }; @@ -119,15 +38,15 @@ struct Renderable : Impl> { bool operator==(const State&) const = default; }; protected: - template - static void execute_prepare_data(Object* object) { + static void execute_prepare_data(Attached auto* object) { + using Object = std::remove_pointer_t; auto& private_data = static_cast(object->d); - if constexpr (requires { private_data.template prepare_data(object); }) { - private_data.template prepare_data(object); + if constexpr (requires { private_data.prepare_data(object); }) { + private_data.prepare_data(object); } auto callback = [&](auto& value) { - if constexpr (requires { value.template after_prepare_data(object); }) { - value.template after_prepare_data(object); + if constexpr (requires { value.after_prepare_data(object); }) { + value.after_prepare_data(object); } }; walk_private(object, callback); @@ -135,103 +54,136 @@ protected: public: struct Private : Prev_Private { using Need_Call = bool (*)(Root*, bool); - using Make_Call = void (*)(Root*, Secene::Private&); + using Update_Call = bool (*)(Root*); + using Make_Call = tf::Taskflow (*)(Root*, std::pmr::memory_resource*); Need_Call need_prepare_call{}; Need_Call need_paint_call{}; + Update_Call update_prepare_call{}; + Update_Call update_paint_call{}; Make_Call make_prepare_call{}; Make_Call make_paint_call{}; - bool prepare_graph_dirty{true}; - bool paint_graph_dirty{true}; - bool prepare_enabled{}; - bool paint_enabled{}; - template - bool need_update_prepare_graph(Object*, const State&) { + tf::Taskflow prepare_graph; + tf::Taskflow paint_graph; + tf::Taskflow prepare_flow; + tf::Taskflow paint_flow; + bool prepare_graph_ready{}; + bool paint_graph_ready{}; + bool flow_ready{}; + bool need_update_prepare_graph(Attached auto*, const State&) { return false; } - template - bool need_update_paint_graph(Object*, const State&) { + bool need_update_paint_graph(Attached auto*, const State&) { return false; } - template - bool need_prepare(Object*, const State&, bool dirty) { + bool need_prepare(Attached auto*, const State&, bool dirty) { return dirty; } - template - bool need_paint(Object*, const State&, bool dirty) { + bool need_paint(Attached auto*, const State&, bool dirty) { return dirty; } - template - void make_prepare_graph(Object* object, const State&, auto& graph) { - graph.add( - [object] { - execute_prepare_data(object); + tf::Taskflow make_prepare_graph(Attached auto* object, const State&, std::pmr::memory_resource*) { + tf::Taskflow graph; + graph.emplace([object] { + execute_prepare_data(object); + }); + return graph; + } + tf::Taskflow make_paint_graph(Attached auto* object, const State&, std::pmr::memory_resource*) { + using Object = std::remove_pointer_t; + tf::Taskflow graph; + graph.emplace([object] { + auto& private_data = static_cast(object->d); + private_data.paint(object); + }); + return graph; + } + void prepare_data(Attached auto*) {} + void after_prepare_data(Attached auto*) {} + void paint(Attached auto*) {} + private: + void make_flow(Root* root) { + prepare_flow.clear(); + paint_flow.clear(); + auto prepare_if = prepare_flow.emplace([this, root] { + bool update = update_prepare_call(root); + if (!prepare_graph_ready || update) { + prepare_graph = make_prepare_call(root, detail::task_memory_resource()); + prepare_graph_ready = true; + root->template mark_dirty(); } - ); - } - template - void make_paint_graph(Object* object, const State&, auto& graph) { - graph.add( - [object] { - auto& private_data = static_cast(object->d); - private_data.template paint(object); + return need_prepare_call(root, root->template dirty()) ? 0 : -1; + }); + auto prepare_run = prepare_flow.composed_of(prepare_graph); + auto prepare_done = prepare_flow.emplace([root] { + root->template take_dirty(); + root->template mark_dirty(); + }); + prepare_if.precede(prepare_run); + prepare_run.precede(prepare_done); + auto paint_if = paint_flow.emplace([this, root] { + bool update = update_paint_call(root); + if (!paint_graph_ready || update) { + paint_graph = make_paint_call(root, detail::task_memory_resource()); + paint_graph_ready = true; + root->template mark_dirty(); } - ); + return need_paint_call(root, root->template dirty()) ? 0 : -1; + }); + auto paint_run = paint_flow.composed_of(paint_graph); + auto paint_done = paint_flow.emplace([root] { + root->template take_dirty(); + }); + paint_if.precede(paint_run); + paint_run.precede(paint_done); + flow_ready = true; } - template - void prepare_data(Object*) {} - template - void after_prepare_data(Object*) {} - template - void after_exchange(Object* object, Prop*, State*, const Prop*, const State*) { - auto& private_data = static_cast(object->d); - const auto& state = *object->d.state.render; - if (private_data.template need_update_prepare_graph(object, state)) { - prepare_graph_dirty = true; - object->template mark_dirty(); - } - if (private_data.template need_update_paint_graph(object, state)) { - paint_graph_dirty = true; - object->template mark_dirty(); - } - } - template - void paint(Object*) {} + friend struct Renderable; }; private: - template - void bind_rely_node(Rely::Node* node) { - auto* object = static_cast(this); + void bind_rely_node(Rely::Node* node, Attached auto* object) { + using Object = std::remove_pointer_t; auto& data = static_cast(object->d); data.need_prepare_call = [](Root* root, bool dirty) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); - return private_data.template need_prepare(value, *value->d.state.render, dirty); + return private_data.need_prepare(value, *value->d.state.render, dirty); }; data.need_paint_call = [](Root* root, bool dirty) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); - return private_data.template need_paint(value, *value->d.state.render, dirty); + return private_data.need_paint(value, *value->d.state.render, dirty); }; - data.make_prepare_call = [](Root* root, Secene::Private& graph) { + data.update_prepare_call = [](Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); - private_data.template make_prepare_graph(value, *value->d.state.render, graph); + return private_data.need_update_prepare_graph(value, *value->d.state.render); }; - data.make_paint_call = [](Root* root, Secene::Private& graph) { + data.update_paint_call = [](Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); - private_data.template make_paint_graph(value, *value->d.state.render, graph); + return private_data.need_update_paint_graph(value, *value->d.state.render); }; + data.make_prepare_call = [](Root* root, std::pmr::memory_resource* resource) { + auto* value = static_cast(root); + auto& private_data = static_cast(value->d); + return private_data.make_prepare_graph(value, *value->d.state.render, resource); + }; + data.make_paint_call = [](Root* root, std::pmr::memory_resource* resource) { + auto* value = static_cast(root); + auto& private_data = static_cast(value->d); + return private_data.make_paint_graph(value, *value->d.state.render, resource); + }; + if (!data.flow_ready) data.make_flow(object); object->template mark_dirty(); node->data = &data; } friend struct ::aethera::Rely; }; -template -void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*, const State*) { - auto* resource = object->memory_resource(); +void Secene::Private::after_exchange(Attached auto* object, Prop*, State*, const Prop*, const State*) { + auto* resource = detail::task_memory_resource(); std::pmr::unordered_set exchanged{resource}; exchanged.insert(object); + // 交换双缓冲 object->for_each_render_rely( [&](const Rely& rely) { rely.for_each( @@ -241,44 +193,30 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*, ); } ); - auto& prepare_state = object->d.rely_storage.template get(); - auto& paint_state = object->d.rely_storage.template get(); - bool prepare_graph_dirty = prepare_state.dirty(); - bool paint_graph_dirty = paint_state.dirty(); + bool scene_graph_dirty = !graph_ready; + object->template render_rely( + [&](auto& prepare_state, auto& paint_state) { + scene_graph_dirty = scene_graph_dirty || prepare_state.dirty() || paint_state.dirty(); + } + ); + if (!scene_graph_dirty) return; const auto& prepare_rely = object->template render_rely(); const auto& paint_rely = object->template render_rely(); std::pmr::unordered_set renderables{resource}; prepare_rely.for_each( [&](const Rely::Node& node) { - if (!node.data) return; - renderables.insert(node.object); - auto* data = static_cast(node.data); - prepare_graph_dirty = prepare_graph_dirty || data->prepare_graph_dirty; - paint_graph_dirty = paint_graph_dirty || data->paint_graph_dirty; + if (node.data) renderables.insert(node.object); } ); paint_rely.for_each( [&](const Rely::Node& node) { - if (!node.data) return; - renderables.insert(node.object); - auto* data = static_cast(node.data); - prepare_graph_dirty = prepare_graph_dirty || data->prepare_graph_dirty; - paint_graph_dirty = paint_graph_dirty || data->paint_graph_dirty; + if (node.data) renderables.insert(node.object); } ); - if (graph && !prepare_graph_dirty && !paint_graph_dirty) return; - if (graph) graph->wait_for_all(); - tasks.reset(); - start.reset(); - graph.reset(); - graph = std::make_unique(); - start = std::make_unique>(*graph); - tasks = std::make_unique>(resource); + graph.clear(); struct Endpoints { - Task* prepare_entry; - Task* prepare_exit; - Task* paint_entry; - Task* paint_exit; + tf::Task prepare; + tf::Task paint; }; std::pmr::unordered_map endpoints{resource}; for (auto* root : renderables) { @@ -286,74 +224,11 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*, if (!rely_node || !rely_node->data) rely_node = paint_rely.find(root); if (!rely_node || !rely_node->data) continue; auto* data = static_cast(rely_node->data); - tasks->emplace_back( - *graph, - nullptr, - [root, data] { - data->prepare_enabled = data->need_prepare_call(root, root->template dirty()); - } - ); - auto* prepare_entry = &tasks->back(); - tasks->emplace_back( - *graph, - nullptr, - [root, data] { - if (!data->prepare_enabled) return; - root->template take_dirty(); - root->template mark_dirty(); - } - ); - auto* prepare_exit = &tasks->back(); - tasks->emplace_back( - *graph, - nullptr, - [root, data] { - data->paint_enabled = data->need_paint_call(root, root->template dirty()); - } - ); - auto* paint_entry = &tasks->back(); - tasks->emplace_back( - *graph, - nullptr, - [root, data] { - if (data->paint_enabled) root->template take_dirty(); - } - ); - auto* paint_exit = &tasks->back(); - oneapi::tbb::flow::make_edge(*start, prepare_entry->gate); - oneapi::tbb::flow::make_edge(*start, paint_entry->gate); - oneapi::tbb::flow::make_edge(prepare_exit->execute, paint_entry->gate); - auto prepare_begin = tasks->size(); - building_enabled = &data->prepare_enabled; - data->make_prepare_call(root, *this); - if (tasks->size() == prepare_begin) { - oneapi::tbb::flow::make_edge(prepare_entry->execute, prepare_exit->gate); - } - else { - std::size_t index = 0; - for (auto& task : *tasks) { - if (index++ < prepare_begin) continue; - oneapi::tbb::flow::make_edge(prepare_entry->execute, task.gate); - oneapi::tbb::flow::make_edge(task.execute, prepare_exit->gate); - } - } - auto paint_begin = tasks->size(); - building_enabled = &data->paint_enabled; - data->make_paint_call(root, *this); - if (tasks->size() == paint_begin) { - oneapi::tbb::flow::make_edge(paint_entry->execute, paint_exit->gate); - } - else { - std::size_t index = 0; - for (auto& task : *tasks) { - if (index++ < paint_begin) continue; - oneapi::tbb::flow::make_edge(paint_entry->execute, task.gate); - oneapi::tbb::flow::make_edge(task.execute, paint_exit->gate); - } - } - endpoints.emplace(root, Endpoints{prepare_entry, prepare_exit, paint_entry, paint_exit}); + auto prepare = graph.composed_of(data->prepare_flow); + auto paint = graph.composed_of(data->paint_flow); + prepare.precede(paint); + endpoints.emplace(root, Endpoints{prepare, paint}); } - building_enabled = nullptr; auto connect_rely = [&](const Rely& rely, bool prepare) { rely.for_each( [&](const Rely::Node& rely_node) { @@ -370,9 +245,9 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*, if (dependency->data) { auto source = endpoints.find(dependency->object); if (source != endpoints.end()) { - auto* source_exit = prepare ? source->second.prepare_exit : source->second.paint_exit; - auto* target_entry = prepare ? target->second.prepare_entry : target->second.paint_entry; - oneapi::tbb::flow::make_edge(source_exit->execute, target_entry->gate); + auto source_task = prepare ? source->second.prepare : source->second.paint; + auto target_task = prepare ? target->second.prepare : target->second.paint; + source_task.precede(target_task); } continue; } @@ -383,15 +258,12 @@ void Secene::Private::after_exchange(Object* object, Prop*, State*, const Prop*, }; connect_rely(prepare_rely, true); connect_rely(paint_rely, false); - if (prepare_state.dirty()) prepare_state.take_dirty(); - if (paint_state.dirty()) paint_state.take_dirty(); - for (auto* root : renderables) { - const Rely::Node* rely_node = prepare_rely.find(root); - if (!rely_node || !rely_node->data) rely_node = paint_rely.find(root); - if (!rely_node || !rely_node->data) continue; - auto* data = static_cast(rely_node->data); - data->prepare_graph_dirty = false; - data->paint_graph_dirty = false; - } + object->template render_rely( + [](auto& prepare_state, auto& paint_state) { + if (prepare_state.dirty()) prepare_state.take_dirty(); + if (paint_state.dirty()) paint_state.take_dirty(); + } + ); + graph_ready = true; } }