升级
This commit is contained in:
@@ -36,6 +36,13 @@ concept Impl_Mechanisms = requires {
|
||||
requires Rely_List<Impl_Relies<Base, Local_Mechanisms...>>;
|
||||
};
|
||||
}
|
||||
template <typename T>
|
||||
concept Attached = requires {
|
||||
requires Object_Core<T>;
|
||||
typename T::Attached_Object;
|
||||
requires Object_Root<typename T::Attached_Object>;
|
||||
requires std::derived_from<T, typename T::Attached_Object>;
|
||||
};
|
||||
template <typename Self, Object_Root Base, detail::Mechanism_Type... Local_Mechanisms> requires
|
||||
detail::Impl_Mechanisms<Base, Local_Mechanisms...>
|
||||
struct Impl : Base {
|
||||
@@ -59,13 +66,14 @@ struct Impl : Base {
|
||||
void after_exchange(Self*, Prop*, State*, const Prop*, const State*) {}
|
||||
};
|
||||
using Prev_Private = Private;
|
||||
};
|
||||
template <typename T>
|
||||
concept Attached = requires {
|
||||
requires Object_Core<T>;
|
||||
typename T::Attached_Object;
|
||||
requires Object_Root<typename T::Attached_Object>;
|
||||
requires std::derived_from<T, typename T::Attached_Object>;
|
||||
template <bool Reverse, Object_Core Layer, Attached Object, typename Callback>
|
||||
static void walk_private(Object* object, Callback& callback) {
|
||||
if constexpr (requires { typename Layer::Prev_Object; }) {
|
||||
if constexpr (!Reverse) walk_private<Reverse, typename Layer::Prev_Object>(object, callback);
|
||||
callback(static_cast<typename Layer::Private&>(object->d));
|
||||
if constexpr (Reverse) walk_private<Reverse, typename Layer::Prev_Object>(object, callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
template <Object_Root Obj, Lockable Lock = std::mutex>
|
||||
struct Attach_Object : Obj {
|
||||
|
||||
+28
-169
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#include "base.hpp"
|
||||
#include <oneapi/tbb/flow_graph.h>
|
||||
namespace aethera::_2D {
|
||||
@@ -5,22 +6,13 @@ struct Prepare_Data_Tag {};
|
||||
struct Paint_Tag {};
|
||||
namespace detail {
|
||||
using Flow_Message = oneapi::tbb::flow::continue_msg;
|
||||
using Flow_Async_Node = oneapi::tbb::flow::async_node<Flow_Message, Flow_Message>;
|
||||
using Flow_Gateway = typename Flow_Async_Node::gateway_type;
|
||||
template <typename Context, auto Callback>
|
||||
concept Sync_Task = std::invocable<decltype(Callback), Context*>;
|
||||
template <typename Context, auto Callback>
|
||||
concept Async_Task = std::invocable<decltype(Callback), Context*, Flow_Gateway&>;
|
||||
}
|
||||
struct Color_Cache {};
|
||||
struct Secene;
|
||||
struct Renderable : Impl<Renderable, Root, Tagged_Buffer<Color_Cache>> {
|
||||
public:
|
||||
using Message = detail::Flow_Message;
|
||||
using Async_Node = detail::Flow_Async_Node;
|
||||
using Gateway = detail::Flow_Gateway;
|
||||
struct Private;
|
||||
struct Node_Data {
|
||||
void (*prepare)(Root*, Gateway&){};
|
||||
Renderable* renderable{};
|
||||
};
|
||||
struct Prop : Prev_Prop {};
|
||||
@@ -28,17 +20,7 @@ public:
|
||||
bool operator==(const State&) const = default;
|
||||
};
|
||||
private:
|
||||
using Task_Call = void (*)(void*, Gateway&);
|
||||
using Task_State = std::tuple<void*, Task_Call>;
|
||||
Node_Data node_data;
|
||||
template <bool Reverse, Object_Core Layer, Attached Object, typename Callback>
|
||||
static void walk_private(Object* object, Callback& callback) {
|
||||
if constexpr (requires { typename Layer::Prev_Object; }) {
|
||||
if constexpr (!Reverse) walk_private<Reverse, typename Layer::Prev_Object>(object, callback);
|
||||
callback(static_cast<typename Layer::Private&>(object->d));
|
||||
if constexpr (Reverse) walk_private<Reverse, typename Layer::Prev_Object>(object, callback);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
template <Attached Object>
|
||||
static void execute_prepare_data(Object* object) {
|
||||
@@ -55,49 +37,6 @@ protected:
|
||||
}
|
||||
public:
|
||||
struct Private : Prev_Private {
|
||||
template <auto Callback, detail::Sync_Task<Callback> Context>
|
||||
static void set_sync(Double_Buffer<Task_State>& buffer, Context* context, bool initial) {
|
||||
Task_State task{
|
||||
context,
|
||||
[](void* value, Gateway& gateway) {
|
||||
std::invoke(Callback, static_cast<Context*>(value));
|
||||
(void)gateway.try_put(Message{});
|
||||
}
|
||||
};
|
||||
*buffer.cache = task;
|
||||
if (initial) *buffer.render = task;
|
||||
}
|
||||
template <auto Callback, detail::Async_Task<Callback> Context>
|
||||
static void set_async(Double_Buffer<Task_State>& buffer, Context* context, bool initial) {
|
||||
Task_State task{
|
||||
context,
|
||||
[](void* value, Gateway& gateway) {
|
||||
gateway.reserve_wait();
|
||||
std::invoke(Callback, static_cast<Context*>(value), gateway);
|
||||
}
|
||||
};
|
||||
*buffer.cache = task;
|
||||
if (initial) *buffer.render = task;
|
||||
}
|
||||
static void publish(Double_Buffer<Task_State>& buffer) {
|
||||
Task_State value = *buffer.cache;
|
||||
buffer.exchange();
|
||||
*buffer.cache = value;
|
||||
}
|
||||
template <Attached Object>
|
||||
static void prepare(Object* object) {
|
||||
execute_prepare_data(object);
|
||||
}
|
||||
template <Attached Object>
|
||||
static void bind(Renderable* renderable, Object* object) {
|
||||
renderable->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);
|
||||
};
|
||||
set_sync<&Private::template prepare<Object>>(renderable->prepare_task, object, true);
|
||||
set_sync<&Object::paint>(renderable->paint_task, object, true);
|
||||
}
|
||||
template <Attached Object>
|
||||
void prepare_data(Object*) {}
|
||||
template <Attached Object>
|
||||
@@ -105,43 +44,31 @@ public:
|
||||
static_cast<Renderable*>(object)->paint_dirty = true;
|
||||
}
|
||||
template <Attached Object>
|
||||
void after_exchange(
|
||||
Object* object,
|
||||
typename Object::Prop*,
|
||||
typename Object::State*,
|
||||
const typename Object::Prop*,
|
||||
const typename Object::State*) {
|
||||
auto* renderable = static_cast<Renderable*>(object);
|
||||
publish(renderable->prepare_task);
|
||||
publish(renderable->paint_task);
|
||||
}
|
||||
template <Attached Object>
|
||||
void paint(Object*) {}
|
||||
};
|
||||
private:
|
||||
using Call = void (*)(Renderable*);
|
||||
Call prepare_call{};
|
||||
Call paint_call{};
|
||||
bool paint_dirty{true};
|
||||
Double_Buffer<Task_State> prepare_task;
|
||||
Double_Buffer<Task_State> paint_task;
|
||||
friend struct Secene;
|
||||
protected:
|
||||
template <Attached Object>
|
||||
void bind_object_crtp() {
|
||||
Prev_Object::template bind_object_crtp<Object>();
|
||||
Private::bind(this, static_cast<Object*>(this));
|
||||
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.prepare) {
|
||||
auto* object = static_cast<Object*>(this);
|
||||
object->template mark_dirty<Prepare_Data_Tag>();
|
||||
node_data.prepare = [](Root* root, Gateway& gateway) {
|
||||
execute_prepare_data(static_cast<Object*>(root));
|
||||
(void)gateway.try_put(Message{});
|
||||
};
|
||||
}
|
||||
if (!node_data.renderable) mark_dirty<Prepare_Data_Tag>();
|
||||
node_data.renderable = this;
|
||||
node->data = &node_data;
|
||||
}
|
||||
@@ -162,51 +89,6 @@ public:
|
||||
void paint() {
|
||||
paint_call(this);
|
||||
}
|
||||
template <auto Callback, detail::Sync_Task<Callback> Context>
|
||||
void set_prepare_task(Context* context) {
|
||||
Private::template set_sync<Callback>(prepare_task, context, false);
|
||||
}
|
||||
template <auto Callback, detail::Async_Task<Callback> Context>
|
||||
void set_prepare_async_task(Context* context) {
|
||||
Private::template set_async<Callback>(prepare_task, context, false);
|
||||
}
|
||||
template <auto Callback, detail::Sync_Task<Callback> Context>
|
||||
void set_paint_task(Context* context) {
|
||||
Private::template set_sync<Callback>(paint_task, context, false);
|
||||
}
|
||||
template <auto Callback, detail::Async_Task<Callback> Context>
|
||||
void set_paint_async_task(Context* context) {
|
||||
Private::template set_async<Callback>(paint_task, context, false);
|
||||
}
|
||||
template <typename Object>
|
||||
struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
using Base::Base;
|
||||
template <auto Callback> requires detail::Sync_Task<Object, Callback>
|
||||
Builder& set_prepare_task() {
|
||||
auto* renderable = static_cast<Renderable*>(this->object.get());
|
||||
Private::template set_sync<Callback>(renderable->prepare_task, this->object.get(), true);
|
||||
return *this;
|
||||
}
|
||||
template <auto Callback> requires detail::Async_Task<Object, Callback>
|
||||
Builder& set_prepare_async_task() {
|
||||
auto* renderable = static_cast<Renderable*>(this->object.get());
|
||||
Private::template set_async<Callback>(renderable->prepare_task, this->object.get(), true);
|
||||
return *this;
|
||||
}
|
||||
template <auto Callback> requires detail::Sync_Task<Object, Callback>
|
||||
Builder& set_paint_task() {
|
||||
auto* renderable = static_cast<Renderable*>(this->object.get());
|
||||
Private::template set_sync<Callback>(renderable->paint_task, this->object.get(), true);
|
||||
return *this;
|
||||
}
|
||||
template <auto Callback> requires detail::Async_Task<Object, Callback>
|
||||
Builder& set_paint_async_task() {
|
||||
auto* renderable = static_cast<Renderable*>(this->object.get());
|
||||
Private::template set_async<Callback>(renderable->paint_task, this->object.get(), true);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
};
|
||||
namespace detail {
|
||||
template <typename Tag>
|
||||
@@ -219,59 +101,35 @@ struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_
|
||||
struct State : Prev_State {};
|
||||
struct Private : Prev_Private {
|
||||
using Message = detail::Flow_Message;
|
||||
using Async_Node = detail::Flow_Async_Node;
|
||||
template <detail::Stage_Tag Tag>
|
||||
struct Stage : Pinned {
|
||||
struct Node : Pinned {
|
||||
using Gate = oneapi::tbb::flow::continue_node<Message>;
|
||||
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, data](const Message&, typename Async_Node::gateway_type& gateway) {
|
||||
if (!object->take_dirty<Prepare_Data_Tag>()) {
|
||||
(void)gateway.try_put(Message{});
|
||||
return;
|
||||
}
|
||||
if (!data->renderable) {
|
||||
data->prepare(object, gateway);
|
||||
return;
|
||||
}
|
||||
auto& task = *data->renderable->prepare_task.render;
|
||||
std::get<1>(task)(std::get<0>(task), gateway);
|
||||
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&, typename Async_Node::gateway_type& gateway) {
|
||||
if (!renderable->take_paint_dirty()) {
|
||||
(void)gateway.try_put(Message{});
|
||||
return;
|
||||
}
|
||||
auto& task = *renderable->paint_task.render;
|
||||
std::get<1>(task)(std::get<0>(task), gateway);
|
||||
return [renderable = data->renderable](const Message&) {
|
||||
if (renderable->take_paint_dirty()) renderable->paint_call(renderable);
|
||||
return Message{};
|
||||
};
|
||||
}
|
||||
}
|
||||
Gate gate;
|
||||
Async_Node execute;
|
||||
Node(oneapi::tbb::flow::graph& graph, Root* object, Renderable::Node_Data* data) :
|
||||
gate(
|
||||
graph,
|
||||
[](const Message&) {
|
||||
return Message{};
|
||||
}
|
||||
),
|
||||
execute(graph, oneapi::tbb::flow::unlimited, body(object, data)) {
|
||||
oneapi::tbb::flow::make_edge(gate, execute);
|
||||
}
|
||||
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;
|
||||
std::uint64_t revision;
|
||||
template <Attached Object>
|
||||
Stage(const Object* object, std::pmr::memory_resource* resource) :
|
||||
start(graph),
|
||||
nodes(resource),
|
||||
revision(object->template render_rely<Tag>().revision()) {
|
||||
Stage(const Object* object, std::pmr::memory_resource* resource) : start(graph),
|
||||
nodes(resource),
|
||||
revision(object->template render_rely<Tag>().revision()) {
|
||||
(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);
|
||||
@@ -279,10 +137,10 @@ struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_
|
||||
auto* node = &nodes.back();
|
||||
rely_node.runtime = node;
|
||||
auto dependencies = view.get_rely(rely_node.object);
|
||||
if (dependencies.empty()) oneapi::tbb::flow::make_edge(start, node->gate);
|
||||
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->gate);
|
||||
oneapi::tbb::flow::make_edge(source->execute, node->execute);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -300,7 +158,8 @@ struct Secene : Impl<Secene, Root, Rely_Type<Prepare_Data_Tag>, Rely_Type<Paint_
|
||||
object->prepare_stage &&
|
||||
object->paint_stage &&
|
||||
object->prepare_stage->revision == prepare_rely.revision() &&
|
||||
object->paint_stage->revision == paint_rely.revision()) return;
|
||||
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();
|
||||
auto prepare = std::make_unique<Stage<Prepare_Data_Tag>>(object, object->memory_resource());
|
||||
|
||||
Reference in New Issue
Block a user