This commit is contained in:
2026-08-19 17:12:30 +08:00
parent bd954f5fb1
commit 2bdae2d9c7
2 changed files with 43 additions and 176 deletions
+15 -7
View File
@@ -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
View File
@@ -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());