This commit is contained in:
2026-08-19 17:36:43 +08:00
parent 2bdae2d9c7
commit c783fd88c2
2 changed files with 169 additions and 69 deletions
@@ -0,0 +1,55 @@
#pragma once
#include "core.hpp"
#include <oneapi/tbb/flow_graph.h>
namespace aethera {
struct Execution_Graph : Pinned {
using Message = oneapi::tbb::flow::continue_msg;
struct Node : Pinned {
using Execute = oneapi::tbb::flow::continue_node<Message>;
Execute execute;
bool has_dependency{};
template <std::invocable Callback>
Node(oneapi::tbb::flow::graph& graph, Callback&& callback) : execute(
graph,
[task = std::forward<Callback>(callback)](const Message&) mutable {
std::invoke(task);
return Message{};
}
) {}
};
struct Builder {
Execution_Graph* owner;
template <std::invocable Callback>
Node* add(Callback&& callback) {
owner->nodes.emplace_back(owner->graph, std::forward<Callback>(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<Message> start;
std::pmr::list<Node> 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();
}
};
}
+114 -69
View File
@@ -1,12 +1,10 @@
#pragma once
#include "base.hpp"
#include <oneapi/tbb/flow_graph.h>
#include "base/execution_graph.hpp"
namespace aethera::_2D {
struct Prepare_Data_Tag {};
struct Paint_Tag {};
namespace detail {
using Flow_Message = oneapi::tbb::flow::continue_msg;
}
struct Prepare_Graph_Tag {};
struct Paint_Graph_Tag {};
struct Color_Cache {};
struct Secene;
struct Renderable : Impl<Renderable, Root, Tagged_Buffer<Color_Cache>> {
@@ -15,12 +13,22 @@ public:
struct Node_Data {
Renderable* renderable{};
};
struct Graph_Update {
bool prepare{};
bool paint{};
[[nodiscard]] explicit operator bool() const {
return prepare || paint;
}
};
struct Prop : Prev_Prop {};
struct State : Prev_State {
bool operator==(const State&) const = default;
};
private:
Node_Data node_data;
std::unique_ptr<Execution_Graph> prepare_graph;
std::unique_ptr<Execution_Graph> paint_graph;
friend struct Secene;
protected:
template <Attached Object>
static void execute_prepare_data(Object* object) {
@@ -37,38 +45,82 @@ protected:
}
public:
struct Private : Prev_Private {
template <Attached Object>
bool need_update_prepare_graph(Object*, const typename Object::State&) {
return false;
}
template <Attached Object>
bool need_update_paint_graph(Object*, const typename Object::State&) {
return false;
}
template <Attached Object>
void make_prepare_graph(
Object* object,
const typename Object::State&,
Execution_Graph::Builder& graph) {
graph.add(
[object] {
execute_prepare_data(object);
}
);
}
template <Attached Object>
void make_paint_graph(
Object* object,
const typename Object::State&,
Execution_Graph::Builder& graph) {
graph.add(
[object] {
auto& private_data = static_cast<typename Object::Private&>(object->d);
private_data.template paint<Object>(object);
}
);
}
template <Attached Object>
void prepare_data(Object*) {}
template <Attached Object>
void after_prepare_data(Object* object) {
static_cast<Renderable*>(object)->paint_dirty = true;
static_cast<Renderable*>(object)->mark_paint_dirty();
}
template <Attached Object>
void after_exchange(
Object* object,
typename Object::Prop*,
typename Object::State*,
const typename Object::Prop*,
const typename Object::State* state) {
auto* renderable = static_cast<Renderable*>(object);
auto& private_data = static_cast<typename Object::Private&>(object->d);
if (
!renderable->prepare_graph ||
private_data.template need_update_prepare_graph<Object>(object, *state)) {
auto graph = std::make_unique<Execution_Graph>(object->memory_resource());
auto builder = graph->builder();
private_data.template make_prepare_graph<Object>(object, *state, builder);
graph->finish();
renderable->prepare_graph = std::move(graph);
renderable->mark_dirty<Prepare_Graph_Tag>();
renderable->mark_prepare_dirty();
}
if (
!renderable->paint_graph ||
private_data.template need_update_paint_graph<Object>(object, *state)) {
auto graph = std::make_unique<Execution_Graph>(object->memory_resource());
auto builder = graph->builder();
private_data.template make_paint_graph<Object>(object, *state, builder);
graph->finish();
renderable->paint_graph = std::move(graph);
renderable->mark_dirty<Paint_Graph_Tag>();
renderable->mark_paint_dirty();
}
}
template <Attached Object>
void paint(Object*) {}
};
private:
using Call = void (*)(Renderable*);
Call prepare_call{};
Call paint_call{};
bool paint_dirty{true};
friend struct Secene;
protected:
template <Attached Object>
void bind_object_crtp() {
Prev_Object::template bind_object_crtp<Object>();
prepare_call = [](Renderable* value) {
execute_prepare_data(static_cast<Object*>(value));
};
paint_call = [](Renderable* value) {
auto* current = static_cast<Object*>(value);
auto& private_data = static_cast<typename Object::Private&>(current->d);
private_data.template paint<Object>(current);
};
}
public:
template <Attached Object>
void bind_rely_node(Rely::Node* node) {
if (!node_data.renderable) mark_dirty<Prepare_Data_Tag>();
if (!node_data.renderable) mark_prepare_dirty();
node_data.renderable = this;
node->data = &node_data;
}
@@ -79,15 +131,13 @@ public:
return dirty<Prepare_Data_Tag>();
}
void mark_paint_dirty() {
paint_dirty = true;
mark_dirty<Paint_Tag>();
}
bool take_paint_dirty() {
if (!paint_dirty) return false;
paint_dirty = false;
return true;
[[nodiscard]] Graph_Update graph_update() const {
return Graph_Update{dirty<Prepare_Graph_Tag>(), dirty<Paint_Graph_Tag>()};
}
void paint() {
paint_call(this);
Graph_Update take_graph_update() {
return Graph_Update{take_dirty<Prepare_Graph_Tag>(), take_dirty<Paint_Graph_Tag>()};
}
};
namespace detail {
@@ -100,54 +150,49 @@ struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_
struct Prop : Prev_Prop {};
struct State : Prev_State {};
struct Private : Prev_Private {
using Message = detail::Flow_Message;
template <detail::Stage_Tag Tag>
struct Stage : Pinned {
struct Node : Pinned {
using Execute = oneapi::tbb::flow::continue_node<Message>;
static auto body(Root* object, Renderable::Node_Data* data) {
if constexpr (std::same_as<Tag, Prepare_Data_Tag>) {
return [object, renderable = data->renderable](const Message&) {
if (object->take_dirty<Prepare_Data_Tag>()) renderable->prepare_call(renderable);
return Message{};
};
}
else {
return [renderable = data->renderable](const Message&) {
if (renderable->take_paint_dirty()) renderable->paint_call(renderable);
return Message{};
};
}
}
Execute execute;
Node(oneapi::tbb::flow::graph& graph, Root* object, Renderable::Node_Data* data) : execute(graph, body(object, data)) {}
};
oneapi::tbb::flow::graph graph;
oneapi::tbb::flow::broadcast_node<Message> start;
std::pmr::list<Node> nodes;
Execution_Graph graph;
std::uint64_t revision;
template <Attached Object>
Stage(const Object* object, std::pmr::memory_resource* resource) : start(graph),
nodes(resource),
Stage(const Object* object, std::pmr::memory_resource* resource) : graph(resource),
revision(object->template render_rely<Tag>().revision()) {
auto builder = graph.builder();
(void)object->template for_each_rely_dag<Tag>(
[&](const Rely::View& view, const Rely::Node& rely_node) {
auto* data = static_cast<Renderable::Node_Data*>(rely_node.data);
nodes.emplace_back(graph, rely_node.object, data);
auto* node = &nodes.back();
Execution_Graph::Node* node;
if constexpr (std::same_as<Tag, Prepare_Data_Tag>) {
node = builder.add(
[root = rely_node.object, renderable = data->renderable] {
if (root->take_dirty<Prepare_Data_Tag>() && renderable->prepare_graph) {
renderable->prepare_graph->run();
}
}
);
}
else {
node = builder.add(
[renderable = data->renderable] {
if (renderable->take_dirty<Paint_Tag>() && renderable->paint_graph) {
renderable->paint_graph->run();
}
}
);
}
rely_node.runtime = node;
auto dependencies = view.get_rely(rely_node.object);
if (dependencies.empty()) oneapi::tbb::flow::make_edge(start, node->execute);
for (const auto* dependency : dependencies) {
auto* source = static_cast<Node*>(dependency->runtime);
oneapi::tbb::flow::make_edge(source->execute, node->execute);
for (const auto* dependency : view.get_rely(rely_node.object)) {
builder.add_rely(node, static_cast<Execution_Graph::Node*>(dependency->runtime));
}
}
);
graph.finish();
}
void wait() {
graph.wait();
}
void run() {
(void)start.try_put(Message{});
graph.wait_for_all();
graph.run();
}
};
template <Attached Object>
@@ -160,8 +205,8 @@ struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_
object->prepare_stage->revision == prepare_rely.revision() &&
object->paint_stage->revision == paint_rely.revision())
return;
if (object->prepare_stage) object->prepare_stage->graph.wait_for_all();
if (object->paint_stage) object->paint_stage->graph.wait_for_all();
if (object->prepare_stage) object->prepare_stage->wait();
if (object->paint_stage) object->paint_stage->wait();
auto prepare = std::make_unique<Stage<Prepare_Data_Tag>>(object, object->memory_resource());
auto paint = std::make_unique<Stage<Paint_Tag>>(object, object->memory_resource());
object->prepare_stage = std::move(prepare);