升级
This commit is contained in:
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user