diff --git a/kernel/src/kernel/base.cpp b/kernel/src/kernel/base.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/kernel/src/kernel/base.hpp b/kernel/src/kernel/base.hpp deleted file mode 100644 index 68240de..0000000 --- a/kernel/src/kernel/base.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "base/object.hpp" diff --git a/kernel/src/kernel/base/core.hpp b/kernel/src/kernel/base/core.hpp index e076f3e..211ce80 100644 --- a/kernel/src/kernel/base/core.hpp +++ b/kernel/src/kernel/base/core.hpp @@ -18,7 +18,7 @@ #include #include #include -namespace aethera { +namespace double_buffer { template concept Lockable = requires(T& lock) { { lock.lock() } -> std::same_as; diff --git a/kernel/src/kernel/base/object.hpp b/kernel/src/kernel/base/object.hpp index c0c3325..351c3a8 100644 --- a/kernel/src/kernel/base/object.hpp +++ b/kernel/src/kernel/base/object.hpp @@ -1,6 +1,6 @@ #pragma once #include "rely_storage.hpp" -namespace aethera { +namespace double_buffer { template concept Object = requires { requires Object_Root; diff --git a/kernel/src/kernel/base/rely.hpp b/kernel/src/kernel/base/rely.hpp index a0593b8..d083e34 100644 --- a/kernel/src/kernel/base/rely.hpp +++ b/kernel/src/kernel/base/rely.hpp @@ -1,6 +1,6 @@ #pragma once #include "core.hpp" -namespace aethera { +namespace double_buffer { struct Rely { using Error = Rely_Error; struct Node { diff --git a/kernel/src/kernel/base/rely_storage.hpp b/kernel/src/kernel/base/rely_storage.hpp index 47183d7..76b377e 100644 --- a/kernel/src/kernel/base/rely_storage.hpp +++ b/kernel/src/kernel/base/rely_storage.hpp @@ -1,6 +1,6 @@ #pragma once #include "rely.hpp" -namespace aethera { +namespace double_buffer { namespace detail { template concept Rely_Edit_Callback_For = Rely_List && std::invocable< diff --git a/kernel/src/kernel/render.cpp b/kernel/src/kernel/render.cpp index 91a58e7..6b8c7b3 100644 --- a/kernel/src/kernel/render.cpp +++ b/kernel/src/kernel/render.cpp @@ -2,13 +2,13 @@ #include #include #include -namespace aethera::render { +namespace aethera { namespace { -class Stage_Registry : Pinned { +class Stage_Registry : ::double_buffer::Pinned { private: struct Binding { const tf::Taskflow* owner; - Root* object; + ::double_buffer::Root* object; Renderable::Private* data; detail::Renderable_Stage stage; detail::Stage_Observer_Point point; @@ -16,7 +16,7 @@ private: std::unordered_map bindings; std::mutex mutex; public: - void bind(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) { + void bind(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) { std::lock_guard guard(mutex); bindings.insert_or_assign(task_hash, Binding{owner, object, data, stage, point}); } @@ -246,7 +246,7 @@ public: state.longest_task_type = longest_task_type; } }; -class Task_Resource : Pinned { +class Task_Resource : ::double_buffer::Pinned { private: std::unique_ptr executor; std::shared_ptr observer; @@ -257,7 +257,7 @@ private: std::atomic_size_t completed_taskflows{}; std::atomic_size_t failed_taskflows{}; Task_Runtime_State state; - ::aethera::detail::State_Callback_Storage state_callbacks; + ::double_buffer::detail::State_Callback_Storage state_callbacks; std::recursive_mutex state_mutex; void create_executor(std::size_t workers, std::shared_ptr worker_interface) { executor = std::make_unique(workers, std::move(worker_interface)); @@ -285,7 +285,7 @@ public: static Task_Resource value; return value; } - void initialize(std::size_t workers, std::shared_ptr worker_interface, Pmr pmr) { + void initialize(std::size_t workers, std::shared_ptr worker_interface, ::double_buffer::Pmr pmr) { std::lock_guard guard(state_mutex); memory = pmr.resource(); create_executor(workers, std::move(worker_interface)); @@ -315,7 +315,7 @@ public: publish_state(); return elapsed; } - void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) { + void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, detail::Renderable_Stage stage, detail::Stage_Observer_Point point) { stage_registry.bind(owner, task_hash, object, data, stage, point); } void clear_stage_observers(const tf::Taskflow* owner) { @@ -334,7 +334,7 @@ public: } }; } -void initialize_runtime(std::size_t workers, std::shared_ptr worker_interface, Pmr pmr) { +void initialize_runtime(std::size_t workers, std::shared_ptr worker_interface, ::double_buffer::Pmr pmr) { Task_Resource::instance().initialize(workers, std::move(worker_interface), pmr); } namespace detail { @@ -347,7 +347,7 @@ void clear_runtime_state_callback() { std::uint64_t run_taskflow(tf::Taskflow& taskflow) { return Task_Resource::instance().run(taskflow); } -void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point) { +void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point) { Task_Resource::instance().bind_stage_observer(owner, task_hash, object, data, stage, point); } void clear_stage_observers(const tf::Taskflow* owner) { diff --git a/kernel/src/kernel/render.hpp b/kernel/src/kernel/render.hpp index c270e1f..4cf02a8 100644 --- a/kernel/src/kernel/render.hpp +++ b/kernel/src/kernel/render.hpp @@ -1,5 +1,5 @@ #pragma once -#include "base.hpp" +#include "base/object.hpp" #include #include #include @@ -30,7 +30,7 @@ struct Task_Worker_State { double utilization{}; bool operator==(const Task_Worker_State&) const = default; }; -struct Task_Runtime_State : State_Type { +struct Task_Runtime_State : ::double_buffer::State_Type { std::size_t worker_count{}; std::size_t active_topology_count{}; std::size_t active_taskflow_count{}; @@ -63,7 +63,7 @@ struct Task_Runtime_State : State_Type { }; void initialize_runtime(std::size_t workers = std::thread::hardware_concurrency(), std::shared_ptr worker_interface = nullptr, - Pmr pmr = {}); + ::double_buffer::Pmr pmr = {}); namespace detail { void set_runtime_state_callback(std::function callback); void clear_runtime_state_callback(); @@ -80,30 +80,72 @@ void clear_runtime_state_callback() { detail::clear_runtime_state_callback(); } struct Renderable; +/* + * Prepare 数据模式定制点。 + * 子类的 Private 可定义: + * void prepare_data(T* object); + * 当未定义 build_prepare_graph(...) 时必须提供该函数。 + * 如果 prepare_data(...) 与 build_prepare_graph(...) 同时存在,Prepare 阶段选择子图模式, + * prepare_data(...) 不再作为该阶段的执行函数。 + */ template -concept Prepare_Data_Renderable = Attached && requires(typename T::Private& private_data, T* object) { +concept Prepare_Data_Renderable = ::double_buffer::Attached && requires(typename T::Private& private_data, T* object) { { private_data.prepare_data(object) } -> std::same_as; }; +/* + * Prepare 子图模式定制点。 + * 子类的 Private 可定义: + * tf::Taskflow build_prepare_graph(T* object, const T::State& state); + * 只要该函数存在且签名满足此概念,Prepare 阶段就进入子图模式。 + * 子图首次执行前一定会构建;之后仅在 should_rebuild_prepare_graph(...) 返回 true 时重建。 + * 子图构建需要 PMR 时直接使用 detail::task_memory_resource() 获取运行时全局资源, + * 不把 std::pmr::memory_resource 作为 Renderable 子类接口参数传递。 + * 不需要子图模式时不要定义一个仅返回空 Taskflow 的函数,应直接省略该定制点。 + */ template -concept Prepare_Graph_Renderable = Attached && requires(typename T::Private& private_data, T* object, const typename T::State& state, std::pmr::memory_resource* resource) { - { private_data.build_prepare_graph(object, state, resource) } -> std::same_as; +concept Prepare_Graph_Renderable = ::double_buffer::Attached && requires(typename T::Private& private_data, T* object, const typename T::State& state) { + { private_data.build_prepare_graph(object, state) } -> std::same_as; }; +/* + * Paint 数据模式定制点。 + * 子类的 Private 可定义: + * void paint(T* object); + * 当未定义 build_paint_graph(...) 时必须提供该函数。 + * 如果 paint(...) 与 build_paint_graph(...) 同时存在,Paint 阶段选择子图模式, + * paint(...) 不再作为该阶段的执行函数。 + */ template -concept Paint_Data_Renderable = Attached && requires(typename T::Private& private_data, T* object) { +concept Paint_Data_Renderable = ::double_buffer::Attached && requires(typename T::Private& private_data, T* object) { { private_data.paint(object) } -> std::same_as; }; +/* + * Paint 子图模式定制点。 + * 子类的 Private 可定义: + * tf::Taskflow build_paint_graph(T* object, const T::State& state); + * 只要该函数存在且签名满足此概念,Paint 阶段就进入子图模式。 + * 子图首次执行前一定会构建;之后仅在 should_rebuild_paint_graph(...) 返回 true 时重建。 + * 子图构建需要 PMR 时直接使用 detail::task_memory_resource() 获取运行时全局资源, + * 不把 std::pmr::memory_resource 作为 Renderable 子类接口参数传递。 + * 不需要子图模式时不要定义一个仅返回空 Taskflow 的函数,应直接省略该定制点。 + */ template -concept Paint_Graph_Renderable = Attached && requires(typename T::Private& private_data, T* object, const typename T::State& state, std::pmr::memory_resource* resource) { - { private_data.build_paint_graph(object, state, resource) } -> std::same_as; +concept Paint_Graph_Renderable = ::double_buffer::Attached && requires(typename T::Private& private_data, T* object, const typename T::State& state) { + { private_data.build_paint_graph(object, state) } -> std::same_as; }; +/* + * Renderable 子类完整契约。 + * Prepare 与 Paint 两个阶段都必须至少提供一种实现:普通函数或子图构建函数。 + * should_prepare(...)、should_paint(...)、should_rebuild_prepare_graph(...)、 + * should_rebuild_paint_graph(...) 在 Renderable::Private 中提供默认行为,子类可按需重新定义。 + */ template -concept Renderable_Object = Attached && std::derived_from && requires(typename T::Private& private_data, T* object, const typename T::State& state, bool dirty) { +concept Renderable_Object = ::double_buffer::Attached && std::derived_from && requires(typename T::Private& private_data, T* object, const typename T::State& state, bool dirty) { { private_data.should_prepare(object, state, dirty) } -> std::same_as; { private_data.should_paint(object, state, dirty) } -> std::same_as; { private_data.should_rebuild_prepare_graph(object, state) } -> std::same_as; { private_data.should_rebuild_paint_graph(object, state) } -> std::same_as; } && (Prepare_Data_Renderable || Prepare_Graph_Renderable) && (Paint_Data_Renderable || Paint_Graph_Renderable); -struct Renderable : Impl, Tagged_Buffer> { +struct Renderable : ::double_buffer::Impl, ::double_buffer::Tagged_Buffer> { struct Prop : Prev_Prop {}; struct State : Prev_State { bool prepare_dirty{}; @@ -130,12 +172,12 @@ protected: } public: struct Private : Prev_Private { - using Run_Predicate = bool (*)(Root*, bool); - using Rebuild_Predicate = bool (*)(Root*); - using Stage_Run = void (*)(Root*); - using Graph_Builder = tf::Taskflow (*)(Root*, std::pmr::memory_resource*); - using State_Access = State* (*)(Root*); - using State_Notify = void (*)(Root*); + using Run_Predicate = bool (*)(::double_buffer::Root*, bool); + using Rebuild_Predicate = bool (*)(::double_buffer::Root*); + using Stage_Run = void (*)(::double_buffer::Root*); + using Graph_Builder = tf::Taskflow (*)(::double_buffer::Root*); + using State_Access = State* (*)(::double_buffer::Root*); + using State_Notify = void (*)(::double_buffer::Root*); struct Stage_Dispatch { Run_Predicate predicate; Rebuild_Predicate rebuild_predicate; @@ -156,40 +198,74 @@ public: std::unique_ptr paint_graph; bool prepare_graph_built{}; bool paint_graph_built{}; - bool should_rebuild_prepare_graph(Attached auto*, const State&) { + /* + * Prepare 子图重建判定定制点。 + * 子类的 Private 可定义: + * bool should_rebuild_prepare_graph(T* object, const T::State& state); + * 仅在定义了 build_prepare_graph(...) 的子图模式下使用。 + * 首次子图构建不依赖该返回值;默认 false 表示首次构建后不主动重建。 + */ + bool should_rebuild_prepare_graph(::double_buffer::Attached auto*, const State&) { return false; } - bool should_rebuild_paint_graph(Attached auto*, const State&) { + /* + * Paint 子图重建判定定制点。 + * 子类的 Private 可定义: + * bool should_rebuild_paint_graph(T* object, const T::State& state); + * 仅在定义了 build_paint_graph(...) 的子图模式下使用。 + * 首次子图构建不依赖该返回值;默认 false 表示首次构建后不主动重建。 + */ + bool should_rebuild_paint_graph(::double_buffer::Attached auto*, const State&) { return false; } - bool should_prepare(Attached auto*, const State&, bool dirty) { + /* + * Prepare 阶段执行判定定制点。 + * 子类的 Private 可定义: + * bool should_prepare(T* object, const T::State& state, bool dirty); + * dirty 是运行时在完成必要的子图重建处理后读取到的 Prepare 脏状态。 + * 返回 true 执行 Prepare 阶段,返回 false 跳过;默认仅在 dirty 为 true 时执行。 + */ + bool should_prepare(::double_buffer::Attached auto*, const State&, bool dirty) { return dirty; } - bool should_paint(Attached auto*, const State&, bool dirty) { + /* + * Paint 阶段执行判定定制点。 + * 子类的 Private 可定义: + * bool should_paint(T* object, const T::State& state, bool dirty); + * dirty 是运行时在完成必要的子图重建处理后读取到的 Paint 脏状态。 + * 返回 true 执行 Paint 阶段,返回 false 跳过;默认仅在 dirty 为 true 时执行。 + */ + bool should_paint(::double_buffer::Attached auto*, const State&, bool dirty) { return dirty; } - void after_prepare_data(Attached auto*) {} + /* + * Prepare 数据模式完成后的可选后置钩子。 + * 子类的 Private 可定义: + * void after_prepare_data(T* object); + * 仅在 prepare_data(...) 数据模式执行完成后调用,Prepare 子图模式不会调用该钩子。 + */ + void after_prepare_data(::double_buffer::Attached auto*) {} }; private: - void bind_rely_object(Attached auto* object) { + void bind_rely_object(::double_buffer::Attached auto* object) { using Object = std::remove_pointer_t; static_assert(Renderable_Object); auto& data = static_cast(object->d); static const Private::Dispatch dispatch{ { - [](Root* root, bool dirty) { + [](::double_buffer::Root* root, bool dirty) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); return private_data.should_prepare(value, *value->d.state.current, dirty); }, - [](Root* root) { + [](::double_buffer::Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); return private_data.should_rebuild_prepare_graph(value, *value->d.state.current); }, []() -> Private::Stage_Run { if constexpr (Prepare_Data_Renderable) { - return [](Root* root) { + return [](::double_buffer::Root* root) { auto* value = static_cast(root); run_prepare_data(value); }; @@ -200,10 +276,10 @@ private: }(), []() -> Private::Graph_Builder { if constexpr (Prepare_Graph_Renderable) { - return [](Root* root, std::pmr::memory_resource* resource) { + return [](::double_buffer::Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); - return private_data.build_prepare_graph(value, *value->d.state.current, resource); + return private_data.build_prepare_graph(value, *value->d.state.current); }; } else { @@ -212,19 +288,19 @@ private: }() }, { - [](Root* root, bool dirty) { + [](::double_buffer::Root* root, bool dirty) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); return private_data.should_paint(value, *value->d.state.current, dirty); }, - [](Root* root) { + [](::double_buffer::Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); return private_data.should_rebuild_paint_graph(value, *value->d.state.current); }, []() -> Private::Stage_Run { if constexpr (Paint_Data_Renderable) { - return [](Root* root) { + return [](::double_buffer::Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); private_data.paint(value); @@ -236,10 +312,10 @@ private: }(), []() -> Private::Graph_Builder { if constexpr (Paint_Graph_Renderable) { - return [](Root* root, std::pmr::memory_resource* resource) { + return [](::double_buffer::Root* root) { auto* value = static_cast(root); auto& private_data = static_cast(value->d); - return private_data.build_paint_graph(value, *value->d.state.current, resource); + return private_data.build_paint_graph(value, *value->d.state.current); }; } else { @@ -248,11 +324,11 @@ private: }() }, { - [](Root* root) { + [](::double_buffer::Root* root) { auto* value = static_cast(root); return static_cast(value->d.state.current); }, - [](Root* root) { + [](::double_buffer::Root* root) { auto* value = static_cast(root); value->template notify_state(); } @@ -261,7 +337,7 @@ private: data.dispatch = &dispatch; object->template mark_dirty(); } - friend struct ::aethera::Rely; + friend struct ::double_buffer::Rely; }; namespace detail { enum class Renderable_Stage { @@ -272,10 +348,10 @@ enum class Stage_Observer_Point { Begin, End }; -void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point); +void bind_stage_observer(const tf::Taskflow* owner, std::size_t task_hash, ::double_buffer::Root* object, Renderable::Private* data, Renderable_Stage stage, Stage_Observer_Point point); void clear_stage_observers(const tf::Taskflow* owner); } -struct Scene : Impl, Rely_Type, Rely_Type> { +struct Scene : ::double_buffer::Impl, ::double_buffer::Rely_Type, ::double_buffer::Rely_Type> { struct Prop : Prev_Prop {}; struct State : Prev_State { bool taskflow_rebuilt{}; @@ -301,9 +377,9 @@ struct Scene : Impl, Rely_Type Callback> - void process(Attached auto* object, Callback&& callback) { + void process(::double_buffer::Attached auto* object, Callback&& callback) { auto& state = static_cast(*object->d.state.current); state.taskflow_rebuilt = taskflow_rebuilt; state.renderable_count = renderable_count; @@ -319,15 +395,15 @@ struct Scene : Impl, Rely_Type exchanged_objects{resource}; + std::pmr::unordered_set<::double_buffer::Root*> exchanged_objects{resource}; exchanged_objects.insert(object); object->for_each_current_rely( - [&](const Rely& rely) { + [&](const ::double_buffer::Rely& rely) { rely.for_each( - [&](const Rely::Node& node) { + [&](const ::double_buffer::Rely::Node& node) { if (exchanged_objects.insert(node.object).second) node.object->exchange_object(); } ); @@ -362,9 +438,9 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const tf::Task paint_entry; tf::Task paint_exit; }; - std::pmr::unordered_map stage_tasks{resource}; + std::pmr::unordered_map<::double_buffer::Root*, Stage_Tasks> stage_tasks{resource}; for (auto* renderable : renderables) { - Root* root = renderable; + ::double_buffer::Root* root = renderable; auto* data = prepare_dependencies.private_data(root); if (!data) data = paint_dependencies.private_data(root); if (!data) continue; @@ -376,7 +452,7 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const if (dispatch->prepare.builder) { bool rebuild = dispatch->prepare.rebuild_predicate(root); if (!data->prepare_graph_built || rebuild) { - *data->prepare_graph = dispatch->prepare.builder(root, detail::task_memory_resource()); + *data->prepare_graph = dispatch->prepare.builder(root); data->prepare_graph_built = true; state.prepare_graph_rebuilt = true; root->template mark_dirty(); @@ -416,7 +492,7 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const if (dispatch->paint.builder) { bool rebuild = dispatch->paint.rebuild_predicate(root); if (!data->paint_graph_built || rebuild) { - *data->paint_graph = dispatch->paint.builder(root, detail::task_memory_resource()); + *data->paint_graph = dispatch->paint.builder(root); data->paint_graph_built = true; state.paint_graph_rebuilt = true; root->template mark_dirty(); @@ -457,12 +533,12 @@ void Scene::Private::after_exchange(Attached auto* object, Prop*, State*, const } auto connect_dependencies = [&](const auto& rely, bool prepare) { rely.for_each( - [&](const Rely::Node& rely_node) { + [&](const ::double_buffer::Rely::Node& rely_node) { if (!rely.private_data(rely_node)) return; auto target = stage_tasks.find(rely_node.object); if (target == stage_tasks.end()) return; - std::pmr::unordered_set visited{resource}; - std::pmr::vector pending{resource}; + std::pmr::unordered_set<::double_buffer::Root*> visited{resource}; + std::pmr::vector pending{resource}; for (const auto* dependency : rely_node.dependencies) pending.push_back(dependency); while (!pending.empty()) { const auto* dependency = pending.back();