|
|
|
@@ -1,10 +1,17 @@
|
|
|
|
|
#pragma once
|
|
|
|
|
#include "base.hpp"
|
|
|
|
|
#include <oneapi/tbb/flow_graph.h>
|
|
|
|
|
#include <taskflow/taskflow.hpp>
|
|
|
|
|
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<tf::WorkerInterface> worker_interface = nullptr,
|
|
|
|
|
Pmr pmr = {});
|
|
|
|
|
namespace detail {
|
|
|
|
|
tf::Executor& task_executor();
|
|
|
|
|
std::pmr::memory_resource* task_memory_resource() noexcept;
|
|
|
|
|
}
|
|
|
|
|
struct Renderable;
|
|
|
|
|
struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_Tag>> {
|
|
|
|
|
struct Prop : Prev_Prop {};
|
|
|
|
@@ -13,102 +20,14 @@ struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_
|
|
|
|
|
struct Result {};
|
|
|
|
|
friend struct Renderable;
|
|
|
|
|
private:
|
|
|
|
|
using Message = oneapi::tbb::flow::continue_msg;
|
|
|
|
|
struct Task : Pinned {
|
|
|
|
|
using Gate = oneapi::tbb::flow::continue_node<Message>;
|
|
|
|
|
using Execute = oneapi::tbb::flow::async_node<Message, Message>;
|
|
|
|
|
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 <std::invocable Callback>
|
|
|
|
|
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>(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 <std::invocable<Completion> 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>(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<oneapi::tbb::flow::graph> graph;
|
|
|
|
|
std::unique_ptr<oneapi::tbb::flow::broadcast_node<Message>> start;
|
|
|
|
|
std::unique_ptr<std::pmr::list<Task>> tasks;
|
|
|
|
|
bool* building_enabled{};
|
|
|
|
|
tf::Taskflow graph;
|
|
|
|
|
bool graph_ready{};
|
|
|
|
|
public:
|
|
|
|
|
template <std::invocable Callback>
|
|
|
|
|
Task* add(Callback&& callback) {
|
|
|
|
|
tasks->emplace_back(*graph, building_enabled, std::forward<Callback>(callback));
|
|
|
|
|
return &tasks->back();
|
|
|
|
|
}
|
|
|
|
|
template <std::invocable<typename Task::Completion> Callback>
|
|
|
|
|
Task* add_async(Callback&& callback) {
|
|
|
|
|
tasks->emplace_back(
|
|
|
|
|
*graph,
|
|
|
|
|
building_enabled,
|
|
|
|
|
typename Task::Async_Tag{},
|
|
|
|
|
std::forward<Callback>(callback)
|
|
|
|
|
);
|
|
|
|
|
return &tasks->back();
|
|
|
|
|
}
|
|
|
|
|
void add_rely(Task* target, Task* source) {
|
|
|
|
|
oneapi::tbb::flow::make_edge(source->execute, target->gate);
|
|
|
|
|
}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
void after_exchange(Object* object, Prop*, State*, const Prop*, const State*);
|
|
|
|
|
template <Attached Object, std::invocable<const Result&> Callback>
|
|
|
|
|
void render_scene(Object*, Callback&& callback) {
|
|
|
|
|
void after_exchange(Attached auto* object, Prop*, State*, const Prop*, const State*);
|
|
|
|
|
template <std::invocable<const Result&> 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>(callback), std::as_const(result));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
@@ -119,15 +38,15 @@ struct Renderable : Impl<Renderable, Root, Tagged_Buffer<Color_Cache>> {
|
|
|
|
|
bool operator==(const State&) const = default;
|
|
|
|
|
};
|
|
|
|
|
protected:
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
static void execute_prepare_data(Object* object) {
|
|
|
|
|
static void execute_prepare_data(Attached auto* object) {
|
|
|
|
|
using Object = std::remove_pointer_t<decltype(object)>;
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(object->d);
|
|
|
|
|
if constexpr (requires { private_data.template prepare_data<Object>(object); }) {
|
|
|
|
|
private_data.template prepare_data<Object>(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>(object); }) {
|
|
|
|
|
value.template after_prepare_data<Object>(object);
|
|
|
|
|
if constexpr (requires { value.after_prepare_data(object); }) {
|
|
|
|
|
value.after_prepare_data(object);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
walk_private<true, typename Object::Attached_Object>(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 <Attached Object>
|
|
|
|
|
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 <Attached Object>
|
|
|
|
|
bool need_update_paint_graph(Object*, const State&) {
|
|
|
|
|
bool need_update_paint_graph(Attached auto*, const State&) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
bool need_prepare(Object*, const State&, bool dirty) {
|
|
|
|
|
bool need_prepare(Attached auto*, const State&, bool dirty) {
|
|
|
|
|
return dirty;
|
|
|
|
|
}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
bool need_paint(Object*, const State&, bool dirty) {
|
|
|
|
|
bool need_paint(Attached auto*, const State&, bool dirty) {
|
|
|
|
|
return dirty;
|
|
|
|
|
}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
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<decltype(object)>;
|
|
|
|
|
tf::Taskflow graph;
|
|
|
|
|
graph.emplace([object] {
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(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<Prepare_Data_Tag>();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
void make_paint_graph(Object* object, const State&, auto& graph) {
|
|
|
|
|
graph.add(
|
|
|
|
|
[object] {
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(object->d);
|
|
|
|
|
private_data.template paint<Object>(object);
|
|
|
|
|
return need_prepare_call(root, root->template dirty<Prepare_Data_Tag>()) ? 0 : -1;
|
|
|
|
|
});
|
|
|
|
|
auto prepare_run = prepare_flow.composed_of(prepare_graph);
|
|
|
|
|
auto prepare_done = prepare_flow.emplace([root] {
|
|
|
|
|
root->template take_dirty<Prepare_Data_Tag>();
|
|
|
|
|
root->template mark_dirty<Paint_Tag>();
|
|
|
|
|
});
|
|
|
|
|
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<Paint_Tag>();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
return need_paint_call(root, root->template dirty<Paint_Tag>()) ? 0 : -1;
|
|
|
|
|
});
|
|
|
|
|
auto paint_run = paint_flow.composed_of(paint_graph);
|
|
|
|
|
auto paint_done = paint_flow.emplace([root] {
|
|
|
|
|
root->template take_dirty<Paint_Tag>();
|
|
|
|
|
});
|
|
|
|
|
paint_if.precede(paint_run);
|
|
|
|
|
paint_run.precede(paint_done);
|
|
|
|
|
flow_ready = true;
|
|
|
|
|
}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
void prepare_data(Object*) {}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
void after_prepare_data(Object*) {}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
void after_exchange(Object* object, Prop*, State*, const Prop*, const State*) {
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(object->d);
|
|
|
|
|
const auto& state = *object->d.state.render;
|
|
|
|
|
if (private_data.template need_update_prepare_graph<Object>(object, state)) {
|
|
|
|
|
prepare_graph_dirty = true;
|
|
|
|
|
object->template mark_dirty<Prepare_Data_Tag>();
|
|
|
|
|
}
|
|
|
|
|
if (private_data.template need_update_paint_graph<Object>(object, state)) {
|
|
|
|
|
paint_graph_dirty = true;
|
|
|
|
|
object->template mark_dirty<Paint_Tag>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
void paint(Object*) {}
|
|
|
|
|
friend struct Renderable;
|
|
|
|
|
};
|
|
|
|
|
private:
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
void bind_rely_node(Rely::Node* node) {
|
|
|
|
|
auto* object = static_cast<Object*>(this);
|
|
|
|
|
void bind_rely_node(Rely::Node* node, Attached auto* object) {
|
|
|
|
|
using Object = std::remove_pointer_t<decltype(object)>;
|
|
|
|
|
auto& data = static_cast<Private&>(object->d);
|
|
|
|
|
data.need_prepare_call = [](Root* root, bool dirty) {
|
|
|
|
|
auto* value = static_cast<Object*>(root);
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
|
|
|
|
return private_data.template need_prepare<Object>(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<Object*>(root);
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
|
|
|
|
return private_data.template need_paint<Object>(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<Object*>(root);
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
|
|
|
|
private_data.template make_prepare_graph<Object>(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<Object*>(root);
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(value->d);
|
|
|
|
|
private_data.template make_paint_graph<Object>(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<Object*>(root);
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(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<Object*>(root);
|
|
|
|
|
auto& private_data = static_cast<typename Object::Private&>(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<Prepare_Data_Tag>();
|
|
|
|
|
node->data = &data;
|
|
|
|
|
}
|
|
|
|
|
friend struct ::aethera::Rely;
|
|
|
|
|
};
|
|
|
|
|
template <Attached Object>
|
|
|
|
|
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<Root*> 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<Prepare_Data_Tag>();
|
|
|
|
|
auto& paint_state = object->d.rely_storage.template get<Paint_Tag>();
|
|
|
|
|
bool prepare_graph_dirty = prepare_state.dirty();
|
|
|
|
|
bool paint_graph_dirty = paint_state.dirty();
|
|
|
|
|
bool scene_graph_dirty = !graph_ready;
|
|
|
|
|
object->template render_rely<Prepare_Data_Tag, Paint_Tag>(
|
|
|
|
|
[&](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<Prepare_Data_Tag>();
|
|
|
|
|
const auto& paint_rely = object->template render_rely<Paint_Tag>();
|
|
|
|
|
std::pmr::unordered_set<Root*> renderables{resource};
|
|
|
|
|
prepare_rely.for_each(
|
|
|
|
|
[&](const Rely::Node& node) {
|
|
|
|
|
if (!node.data) return;
|
|
|
|
|
renderables.insert(node.object);
|
|
|
|
|
auto* data = static_cast<Renderable::Private*>(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<Renderable::Private*>(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<oneapi::tbb::flow::graph>();
|
|
|
|
|
start = std::make_unique<oneapi::tbb::flow::broadcast_node<Message>>(*graph);
|
|
|
|
|
tasks = std::make_unique<std::pmr::list<Task>>(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<Root*, Endpoints> 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<Renderable::Private*>(rely_node->data);
|
|
|
|
|
tasks->emplace_back(
|
|
|
|
|
*graph,
|
|
|
|
|
nullptr,
|
|
|
|
|
[root, data] {
|
|
|
|
|
data->prepare_enabled = data->need_prepare_call(root, root->template dirty<Prepare_Data_Tag>());
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
auto* prepare_entry = &tasks->back();
|
|
|
|
|
tasks->emplace_back(
|
|
|
|
|
*graph,
|
|
|
|
|
nullptr,
|
|
|
|
|
[root, data] {
|
|
|
|
|
if (!data->prepare_enabled) return;
|
|
|
|
|
root->template take_dirty<Prepare_Data_Tag>();
|
|
|
|
|
root->template mark_dirty<Paint_Tag>();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
auto* prepare_exit = &tasks->back();
|
|
|
|
|
tasks->emplace_back(
|
|
|
|
|
*graph,
|
|
|
|
|
nullptr,
|
|
|
|
|
[root, data] {
|
|
|
|
|
data->paint_enabled = data->need_paint_call(root, root->template dirty<Paint_Tag>());
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
auto* paint_entry = &tasks->back();
|
|
|
|
|
tasks->emplace_back(
|
|
|
|
|
*graph,
|
|
|
|
|
nullptr,
|
|
|
|
|
[root, data] {
|
|
|
|
|
if (data->paint_enabled) root->template take_dirty<Paint_Tag>();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
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<Renderable::Private*>(rely_node->data);
|
|
|
|
|
data->prepare_graph_dirty = false;
|
|
|
|
|
data->paint_graph_dirty = false;
|
|
|
|
|
}
|
|
|
|
|
object->template render_rely<Prepare_Data_Tag, Paint_Tag>(
|
|
|
|
|
[](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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|