From 921a9fad2a9c1a64d7dfaae4251192a73a5bb04e Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Wed, 19 Aug 2026 22:47:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/kernel/base/core.hpp | 16 + kernel/src/kernel/base/execution_graph.hpp | 55 --- kernel/src/kernel/base/object.hpp | 9 + kernel/src/kernel/base/rely.hpp | 6 +- kernel/src/kernel/base/rely_storage.hpp | 20 +- kernel/src/kernel/render_2D.hpp | 543 +++++++++++++-------- 6 files changed, 374 insertions(+), 275 deletions(-) delete mode 100644 kernel/src/kernel/base/execution_graph.hpp diff --git a/kernel/src/kernel/base/core.hpp b/kernel/src/kernel/base/core.hpp index e73e876..422aaf4 100644 --- a/kernel/src/kernel/base/core.hpp +++ b/kernel/src/kernel/base/core.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -129,6 +130,19 @@ struct Tagged_Buffer { template struct Rely_Type { using Tag_Type = Tag; +private: + std::atomic_flag clean = ATOMIC_FLAG_INIT; +protected: + void mark_dirty() noexcept { + clean.clear(std::memory_order_release); + } +public: + [[nodiscard]] bool dirty() const noexcept { + return !clean.test(std::memory_order_acquire); + } + bool take_dirty() noexcept { + return !clean.test_and_set(std::memory_order_acq_rel); + } }; namespace detail { template @@ -308,6 +322,8 @@ concept Object_Core = requires { }; namespace detail { template +struct Rely_Storage; +template struct Rely_Build_Storage; } enum class Rely_Error { diff --git a/kernel/src/kernel/base/execution_graph.hpp b/kernel/src/kernel/base/execution_graph.hpp deleted file mode 100644 index 9355937..0000000 --- a/kernel/src/kernel/base/execution_graph.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include "core.hpp" -#include -namespace aethera { -struct Execution_Graph : Pinned { - using Message = oneapi::tbb::flow::continue_msg; - struct Node : Pinned { - using Execute = oneapi::tbb::flow::continue_node; - Execute execute; - bool has_dependency{}; - template - Node(oneapi::tbb::flow::graph& graph, Callback&& callback) : execute( - graph, - [task = std::forward(callback)](const Message&) mutable { - std::invoke(task); - return Message{}; - } - ) {} - }; - struct Builder { - Execution_Graph* owner; - template - Node* add(Callback&& callback) { - owner->nodes.emplace_back(owner->graph, std::forward(callback)); - return &owner->nodes.back(); - } - void add_rely(Node* target, Node* source) { - oneapi::tbb::flow::make_edge(source->execute, target->execute); - target->has_dependency = true; - } - }; -private: - oneapi::tbb::flow::graph graph; - oneapi::tbb::flow::broadcast_node start; - std::pmr::list nodes; -public: - explicit Execution_Graph(std::pmr::memory_resource* resource) : start(graph), nodes(resource) {} - Builder builder() { - return Builder{this}; - } - void finish() { - for (auto& node : nodes) { - if (!node.has_dependency) oneapi::tbb::flow::make_edge(start, node.execute); - } - } - void wait() { - graph.wait_for_all(); - } - void run() { - if (nodes.empty()) return; - (void)start.try_put(Message{}); - wait(); - } -}; -} diff --git a/kernel/src/kernel/base/object.hpp b/kernel/src/kernel/base/object.hpp index ba48554..7cad9d8 100644 --- a/kernel/src/kernel/base/object.hpp +++ b/kernel/src/kernel/base/object.hpp @@ -181,6 +181,7 @@ public: template ... Tags, detail::Rely_Edit_Callback_For Callback> requires detail::Unique_Types::value std::expected edit_rely(Callback&& callback) { + std::lock_guard guard(lock); return d.rely_storage.template edit(std::forward(callback)); } std::expected check_rely() const { @@ -208,6 +209,14 @@ public: after_state_set(Member); this->emit_rely_source(detail::rely_id>()); } + template requires requires(Private& private_data, Attach_Object* object, Callback&& callback) { + private_data.render_scene(object, std::forward(callback)); + } + void render(Callback&& callback) { + std::lock_guard guard(lock); + exchange_unlocked(); + d.render_scene(this, std::forward(callback)); + } void exchange() { std::lock_guard guard(lock); exchange_unlocked(); diff --git a/kernel/src/kernel/base/rely.hpp b/kernel/src/kernel/base/rely.hpp index 22a9663..96e2d3d 100644 --- a/kernel/src/kernel/base/rely.hpp +++ b/kernel/src/kernel/base/rely.hpp @@ -9,7 +9,6 @@ struct Rely { std::pmr::vector rely; Bind bind; void* data{}; - mutable void* runtime{}; Node(Root* value, std::pmr::memory_resource* resource) : Node(value, resource, nullptr) {} Node(Root* value, std::pmr::memory_resource* resource, Bind value_bind) : object(value), rely(resource), bind(value_bind) {} }; @@ -160,6 +159,8 @@ public: } }; private: + template + friend struct detail::Rely_Storage; template friend struct detail::Rely_Build_Storage; std::pmr::memory_resource* pmr_resource; @@ -450,9 +451,6 @@ public: std::pmr::memory_resource* memory_resource() const noexcept { return pmr_resource; } - std::uint64_t revision() const noexcept { - return structure_revision; - } Node* find(Root* object) { auto current = nodes.find(object); if (current == nodes.end()) return nullptr; diff --git a/kernel/src/kernel/base/rely_storage.hpp b/kernel/src/kernel/base/rely_storage.hpp index 6144c3b..818b61b 100644 --- a/kernel/src/kernel/base/rely_storage.hpp +++ b/kernel/src/kernel/base/rely_storage.hpp @@ -29,11 +29,14 @@ struct Rely_Storage> { using allocator_type = std::pmr::polymorphic_allocator; private: template - struct Rely_Buffer : Double_Buffer { + struct Rely_Buffer : Double_Buffer, Mechanism { using Base = Double_Buffer; using allocator_type = typename Base::allocator_type; Rely_Buffer() = default; Rely_Buffer(std::allocator_arg_t, const allocator_type& allocator) : Base(std::allocator_arg, allocator) {} + void mark_structure_dirty() noexcept { + this->mark_dirty(); + } }; std::tuple...> relies; template > Tag> @@ -104,8 +107,20 @@ public: next ); if (!result) return result; + auto changed = [&](std::index_sequence) { + return std::tuple{ + (std::get(next).structure_revision != get().cache->structure_revision)... + }; + }(std::index_sequence_for{}); [&](std::index_sequence) { - (get().cache->swap(std::get(next)), ...); + ( + [&] { + auto& buffer = get(); + buffer.cache->swap(std::get(next)); + if (std::get(changed)) buffer.mark_structure_dirty(); + }(), + ... + ); }(std::index_sequence_for{}); return {}; } @@ -158,6 +173,7 @@ private: buffer.cache->bind_nodes(); *buffer.render = *buffer.cache; buffer.render->bind(); + buffer.mark_structure_dirty(); } public: Rely_Build_Storage() : Rely_Build_Storage(std::pmr::get_default_resource()) {} diff --git a/kernel/src/kernel/render_2D.hpp b/kernel/src/kernel/render_2D.hpp index 8c41550..5a72e29 100644 --- a/kernel/src/kernel/render_2D.hpp +++ b/kernel/src/kernel/render_2D.hpp @@ -1,34 +1,123 @@ +#pragma once #include "base.hpp" -#include "base/execution_graph.hpp" +#include namespace aethera::_2D { struct Prepare_Data_Tag {}; struct Paint_Tag {}; -struct Prepare_Graph_Tag {}; -struct Paint_Graph_Tag {}; struct Color_Cache {}; -struct Secene; -struct Renderable : Impl> { -public: - struct Private; - struct Node_Data { - Renderable* renderable{}; - }; - struct Graph_Update { - bool prepare{}; - bool paint{}; - [[nodiscard]] explicit operator bool() const { - return prepare || paint; +struct Renderable; +struct Secene : Impl, Rely_Type> { + struct Prop : Prev_Prop {}; + struct State : Prev_State {}; + struct Private : Prev_Private { + struct Result {}; + friend struct Renderable; + private: + using Message = oneapi::tbb::flow::continue_msg; + struct Task : Pinned { + using Gate = oneapi::tbb::flow::continue_node; + 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{}; + 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) { + Result result; + if (graph && tasks && !tasks->empty()) { + (void)start->try_put(Message{}); + graph->wait_for_all(); + } + std::invoke(std::forward(callback), std::as_const(result)); } }; +}; +struct Renderable : Impl> { struct Prop : Prev_Prop {}; struct State : Prev_State { bool operator==(const State&) const = default; }; -private: - Node_Data node_data; - std::unique_ptr prepare_graph; - std::unique_ptr paint_graph; - friend struct Secene; protected: template static void execute_prepare_data(Object* object) { @@ -45,19 +134,34 @@ protected: } public: struct Private : Prev_Private { + using Need_Call = bool (*)(Root*, bool); + using Make_Call = void (*)(Root*, Secene::Private&); + Need_Call need_prepare_call{}; + Need_Call need_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 typename Object::State&) { + bool need_update_prepare_graph(Object*, const State&) { return false; } template - bool need_update_paint_graph(Object*, const typename Object::State&) { + bool need_update_paint_graph(Object*, const State&) { return false; } template - void make_prepare_graph( - Object* object, - const typename Object::State&, - Execution_Graph::Builder& graph) { + bool need_prepare(Object*, const State&, bool dirty) { + return dirty; + } + template + bool need_paint(Object*, const State&, bool dirty) { + return dirty; + } + template + void make_prepare_graph(Object* object, const State&, auto& graph) { graph.add( [object] { execute_prepare_data(object); @@ -65,10 +169,7 @@ public: ); } template - void make_paint_graph( - Object* object, - const typename Object::State&, - Execution_Graph::Builder& graph) { + void make_paint_graph(Object* object, const State&, auto& graph) { graph.add( [object] { auto& private_data = static_cast(object->d); @@ -79,204 +180,218 @@ public: template void prepare_data(Object*) {} template - void after_prepare_data(Object* object) { - static_cast(object)->mark_paint_dirty(); - } + void after_prepare_data(Object*) {} template - void after_exchange( - Object* object, - typename Object::Prop*, - typename Object::State*, - const typename Object::Prop*, - const typename Object::State* state) { - auto* renderable = static_cast(object); + void after_exchange(Object* object, Prop*, State*, const Prop*, const State*) { auto& private_data = static_cast(object->d); - if ( - !renderable->prepare_graph || - private_data.template need_update_prepare_graph(object, *state)) { - auto graph = std::make_unique(object->memory_resource()); - auto builder = graph->builder(); - private_data.template make_prepare_graph(object, *state, builder); - graph->finish(); - renderable->prepare_graph = std::move(graph); - renderable->mark_dirty(); - renderable->mark_prepare_dirty(); + 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 ( - !renderable->paint_graph || - private_data.template need_update_paint_graph(object, *state)) { - auto graph = std::make_unique(object->memory_resource()); - auto builder = graph->builder(); - private_data.template make_paint_graph(object, *state, builder); - graph->finish(); - renderable->paint_graph = std::move(graph); - renderable->mark_dirty(); - renderable->mark_paint_dirty(); + if (private_data.template need_update_paint_graph(object, state)) { + paint_graph_dirty = true; + object->template mark_dirty(); } } template void paint(Object*) {} }; -public: +private: template void bind_rely_node(Rely::Node* node) { - if (!node_data.renderable) mark_prepare_dirty(); - node_data.renderable = this; - node->data = &node_data; - } - void mark_prepare_dirty() { - mark_dirty(); - } - [[nodiscard]] bool need_prepare_data() const { - return dirty(); - } - void mark_paint_dirty() { - mark_dirty(); - } - [[nodiscard]] Graph_Update graph_update() const { - return Graph_Update{dirty(), dirty()}; - } - Graph_Update take_graph_update() { - return Graph_Update{take_dirty(), take_dirty()}; - } -}; -namespace detail { -template -concept Stage_Tag = requires { - requires std::same_as || std::same_as; -}; -} -struct Secene : Impl, Rely_Type> { - struct Prop : Prev_Prop {}; - struct State : Prev_State {}; - struct Private : Prev_Private { - template - struct Stage : Pinned { - Execution_Graph graph; - std::uint64_t revision; - template - Stage(const Object* object, std::pmr::memory_resource* resource) : graph(resource), - revision(object->template render_rely().revision()) { - auto builder = graph.builder(); - (void)object->template for_each_rely_dag( - [&](const Rely::View& view, const Rely::Node& rely_node) { - auto* data = static_cast(rely_node.data); - Execution_Graph::Node* node; - if constexpr (std::same_as) { - node = builder.add( - [root = rely_node.object, renderable = data->renderable] { - if (root->take_dirty() && renderable->prepare_graph) { - renderable->prepare_graph->run(); - } - } - ); - } - else { - node = builder.add( - [renderable = data->renderable] { - if (renderable->take_dirty() && renderable->paint_graph) { - renderable->paint_graph->run(); - } - } - ); - } - rely_node.runtime = node; - for (const auto* dependency : view.get_rely(rely_node.object)) { - builder.add_rely(node, static_cast(dependency->runtime)); - } - } - ); - graph.finish(); - } - void wait() { - graph.wait(); - } - void run() { - graph.run(); - } + auto* object = static_cast(this); + 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); }; - template - static void update_stages(const Object* object) { - const auto& prepare_rely = object->template render_rely(); - const auto& paint_rely = object->template render_rely(); - if ( - object->prepare_stage && - object->paint_stage && - object->prepare_stage->revision == prepare_rely.revision() && - object->paint_stage->revision == paint_rely.revision()) - return; - if (object->prepare_stage) object->prepare_stage->wait(); - if (object->paint_stage) object->paint_stage->wait(); - auto prepare = std::make_unique>(object, object->memory_resource()); - auto paint = std::make_unique>(object, object->memory_resource()); - object->prepare_stage = std::move(prepare); - object->paint_stage = std::move(paint); - } - template - static void execute_prepare(const Object* object) { - if (!object->prepare_stage || !object->paint_stage) update_stages(object); - object->prepare_stage->run(); - } - template - static void execute_paint(const Object* object) { - if (!object->prepare_stage || !object->paint_stage) update_stages(object); - object->prepare_stage->run(); - object->paint_stage->run(); - } - template - void after_exchange( - Object* object, - typename Object::Prop*, - typename Object::State*, - const typename Object::Prop*, - const typename Object::State*) { - std::pmr::unordered_set exchanged{object->memory_resource()}; - object->for_each_render_rely( - [&](const Rely& rely) { - rely.for_each( - [&](const Rely::Node& node) { - if (exchanged.insert(node.object).second) node.object->exchange_object(); - } - ); + 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); + }; + data.make_prepare_call = [](Root* root, Secene::Private& graph) { + auto* value = static_cast(root); + auto& private_data = static_cast(value->d); + private_data.template make_prepare_graph(value, *value->d.state.render, graph); + }; + data.make_paint_call = [](Root* root, Secene::Private& graph) { + auto* value = static_cast(root); + auto& private_data = static_cast(value->d); + private_data.template make_paint_graph(value, *value->d.state.render, graph); + }; + 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(); + std::pmr::unordered_set exchanged{resource}; + exchanged.insert(object); + object->for_each_render_rely( + [&](const Rely& rely) { + rely.for_each( + [&](const Rely::Node& node) { + if (exchanged.insert(node.object).second) node.object->exchange_object(); } ); - update_stages(object); } - }; -private: - using Call = void (*)(const Secene*); - Call prepare_execute_call{}; - Call paint_execute_call{}; - mutable std::unique_ptr> prepare_stage; - mutable std::unique_ptr> paint_stage; -protected: - template - void bind_object_crtp() { - Prev_Object::template bind_object_crtp(); - prepare_execute_call = [](const Secene* scene) { - Private::execute_prepare(static_cast(scene)); - }; - paint_execute_call = [](const Secene* scene) { - Private::execute_paint(static_cast(scene)); - }; - } -public: - void execute_prepare() const { - prepare_execute_call(this); - } - void execute_paint() const { - paint_execute_call(this); - } - template - struct Builder : Prev_Builder { - using Base = Prev_Builder; - using Base::Base; - std::expected, Rely_Error> build() { - auto result = Base::build(); - if (!result) return std::unexpected(result.error()); - Private::update_stages(result->get()); - return result; + ); + 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(); + 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; } + ); + 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 (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); + struct Endpoints { + Task* prepare_entry; + Task* prepare_exit; + Task* paint_entry; + Task* paint_exit; }; -}; + std::pmr::unordered_map endpoints{resource}; + 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); + 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}); + } + building_enabled = nullptr; + auto connect_rely = [&](const Rely& rely, bool prepare) { + rely.for_each( + [&](const Rely::Node& rely_node) { + if (!rely_node.data) return; + auto target = endpoints.find(rely_node.object); + if (target == endpoints.end()) return; + std::pmr::unordered_set visited{resource}; + std::pmr::vector pending{resource}; + for (const auto* dependency : rely_node.rely) pending.push_back(dependency); + while (!pending.empty()) { + const auto* dependency = pending.back(); + pending.pop_back(); + if (!visited.insert(dependency->object).second) continue; + 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); + } + continue; + } + for (const auto* next : dependency->rely) pending.push_back(next); + } + } + ); + }; + 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; + } +} }