From e7fdbb93c12a03c97f47e0af22f52f2c38b8baea Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Wed, 2 Sep 2026 11:09:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../function/frame_policy/Frame_Policy.hpp | 26 ++-- .../frame_policy/Throttled_Latest_Only.cpp | 52 ++++---- .../frame_policy/Throttled_Latest_Only.hpp | 5 +- .../frame_policy/Throttled_Latest_Only.ipp | 31 +++-- .../include/function/frame_policy/global.cpp | 4 - .../include/function/frame_policy/global.hpp | 27 ---- .../include/function/frame_policy/global.ipp | 3 - .../function/frame_policy/rely_facade.h | 20 +++ .../include/function/renderable/rely_facade.h | 14 ++ .../function/renderable/rely_facade.hpp | 2 - .../function/renderable/renderable.hpp | 4 +- .../function/renderable/renderable.ipp | 22 +--- .../kernel/include/function/scene/Scene.cpp | 55 +++++--- .../kernel/include/function/scene/Scene.hpp | 2 +- .../kernel/include/function/scene/Scene.ipp | 10 +- .../include/function/scene/rely_facade.h | 20 ++- kernel/kernel/include/global.hpp | 1 - kernel/kernel/include/model/Model.hpp | 26 +++- kernel/kernel/include/model/Model.ipp | 5 - kernel/kernel/include/model/design.md | 2 + kernel/kernel/include/task_flow/design.md | 66 ++-------- kernel/kernel/include/task_flow/rely_facade.h | 2 + .../include/task_flow/task_flow_facade.cpp | 124 ++++++++++-------- .../include/task_flow/task_flow_facade.hpp | 39 ------ .../include/time_thread/Timer_Service.cpp | 43 +++--- .../include/time_thread/Timer_Service.hpp | 8 +- .../include/time_thread/Timer_Time_Source.hpp | 7 +- .../kernel/include/time_thread/rely_facade.h | 2 + .../Throttled_Latest_Only_Tests.cpp | 67 +++++----- kernel/kernel/test/model/Model_Tests.cpp | 61 +++++---- .../test/time_thread/Timer_Service_Tests.cpp | 17 ++- 31 files changed, 371 insertions(+), 396 deletions(-) delete mode 100644 kernel/kernel/include/function/frame_policy/global.cpp delete mode 100644 kernel/kernel/include/function/frame_policy/global.hpp delete mode 100644 kernel/kernel/include/function/frame_policy/global.ipp create mode 100644 kernel/kernel/include/function/frame_policy/rely_facade.h create mode 100644 kernel/kernel/include/function/renderable/rely_facade.h delete mode 100644 kernel/kernel/include/function/renderable/rely_facade.hpp create mode 100644 kernel/kernel/include/task_flow/rely_facade.h delete mode 100644 kernel/kernel/include/task_flow/task_flow_facade.hpp create mode 100644 kernel/kernel/include/time_thread/rely_facade.h diff --git a/kernel/kernel/include/function/frame_policy/Frame_Policy.hpp b/kernel/kernel/include/function/frame_policy/Frame_Policy.hpp index dd56bd4..0fbffd4 100644 --- a/kernel/kernel/include/function/frame_policy/Frame_Policy.hpp +++ b/kernel/kernel/include/function/frame_policy/Frame_Policy.hpp @@ -19,10 +19,10 @@ enum struct Frame_Policy_Render_Submission_Result : std::uint8_t { }; struct Frame_Policy_Prop { std::optional user_frames_per_second; /* 有值时作为用户帧率上限;无值时不参与限速。 */ - bool render_rate_limit_enabled{}; /* true 时用渲染平均耗时推导理论生成上限。 */ - bool send_rate_limit_enabled{}; /* true 时用发送平均耗时推导理论发送上限。 */ - bool statistics_enabled{}; /* true 时对外发布完整滑动统计。 */ - std::size_t statistics_window_size{120}; /* 统计或理论限速启用时的样本窗口容量。 */ + bool render_rate_limit_enabled{}; /* true 时用渲染平均耗时推导理论生成上限。 */ + bool send_rate_limit_enabled{}; /* true 时用发送平均耗时推导理论发送上限。 */ + bool statistics_enabled{}; /* true 时对外发布完整滑动统计。 */ + std::size_t statistics_window_size{120}; /* 统计或理论限速启用时的样本窗口容量。 */ }; struct Frame_Policy_State; struct Frame_Policy : Model_Layer, Storage_Registration> { @@ -33,16 +33,16 @@ struct Frame_Policy : Model_Layer render_capacity_fps; /* 有渲染样本时推导出的理论最大生成帧率。 */ - std::optional send_capacity_fps; /* 有发送样本时推导出的理论最大发送帧率。 */ + std::uint64_t timer_ticks{}; /* 已处理的调度到期次数。 */ + std::uint64_t dropped_timer_ticks{}; /* 到期时三帧均忙而丢弃的次数。 */ + std::uint64_t completed_frames{}; /* 已完成媒体发送的帧数。 */ + std::optional render_capacity_fps; /* 有渲染样本时推导出的理论最大生成帧率。 */ + std::optional send_capacity_fps; /* 有发送样本时推导出的理论最大发送帧率。 */ double effective_frames_per_second{Frame_Policy::Default_Frames_Per_Second}; /* 当前有效限速来源的最小值。 */ - Statistics_Summary render_time_ns; /* 渲染耗时滑动统计,单位纳秒。 */ - Statistics_Summary send_time_ns; /* 发送耗时滑动统计,单位纳秒。 */ - Statistics_Summary end_to_end_time_ns; /* 渲染开始至发送完成耗时统计,单位纳秒。 */ - std::optional configuration_error; /* 动态配置无效时记录原因;有效时为空。 */ + Statistics_Summary render_time_ns; /* 渲染耗时滑动统计,单位纳秒。 */ + Statistics_Summary send_time_ns; /* 发送耗时滑动统计,单位纳秒。 */ + Statistics_Summary end_to_end_time_ns; /* 渲染开始至发送完成耗时统计,单位纳秒。 */ + std::optional configuration_error; /* 动态配置无效时记录原因;有效时为空。 */ std::optional render_submission_error; /* Scene 拒绝最近一次渲染提交时的策略级原因;下一次提交成功后清空。 */ }; } // namespace aethera diff --git a/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.cpp b/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.cpp index 5dc1683..12be7fd 100644 --- a/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.cpp +++ b/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.cpp @@ -18,7 +18,7 @@ auto start_result(Frame_Policy::Configuration_Result result) noexcept -> Throttl std::terminate(); } } // namespace -Throttled_Latest_only::Throttled_Latest_only(proxy timer_service, proxy scene, proxy sink) : Def(std::move(timer_service), std::move(scene), std::move(sink)) {} +Throttled_Latest_only::Throttled_Latest_only(proxy timer_service, proxy scene, proxy sink) : Def(std::move(timer_service), std::move(scene), std::move(sink)) {} Throttled_Latest_only::~Throttled_Latest_only() noexcept { if (!d->destructible()) { std::terminate(); @@ -30,13 +30,13 @@ auto Throttled_Latest_only::start() -> std::expected { auto Throttled_Latest_only::stop(Stop_Completion completion) -> std::expected { return d->stop(std::move(completion)); } -Throttled_Latest_only::Private::Private(proxy timer_service, proxy scene, proxy sink) : timer_service(std::move(timer_service)), scene(std::move(scene)), sink(std::move(sink)) {} +Throttled_Latest_only::Private::Private(proxy timer_service, proxy scene, proxy sink) : timer_service(std::move(timer_service)), scene(std::move(scene)), sink(std::move(sink)) {} auto Throttled_Latest_only::Private::start() -> std::expected { const auto interval = prepare_start(); if (!interval) { return std::unexpected(interval.error()); } - Timer_Id scheduled_timer_id{}; + frame_policy::Timer_Id scheduled_timer_id{}; try { scheduled_timer_id = timer_service->schedule_every(*interval, [this] { frame_due(); @@ -63,11 +63,10 @@ auto Throttled_Latest_only::Private::prepare_start() -> std::expected, Frame_Count> created_frames; + std::array, Frame_Count> created_frames; try { - auto scene_private = scene->d_ptr(); for (auto& created_frame : created_frames) { - created_frame = scene_private->create_frame(); + created_frame = scene->create_frame(); if (!created_frame) { rollback_start(); return std::unexpected(Start_Result::frame_unavailable); @@ -102,7 +101,7 @@ auto Throttled_Latest_only::Private::prepare_start() -> std::expected, Frame_Count> retired_frames; + std::array, Frame_Count> retired_frames; { std::lock_guard lock(mutex); if (phase != Phase::starting || timer_id) { @@ -115,7 +114,7 @@ void Throttled_Latest_only::Private::rollback_start() { phase = Phase::stopped; } } -void Throttled_Latest_only::Private::timer_started(Timer_Id id) { +void Throttled_Latest_only::Private::timer_started(frame_policy::Timer_Id id) { std::lock_guard lock(mutex); if (id == 0 || phase != Phase::starting || timer_id) { std::terminate(); @@ -127,7 +126,7 @@ auto Throttled_Latest_only::Private::stop(Stop_Completion completion) -> std::ex if (!completion) { return std::unexpected(Stop_Result::completion_missing); } - Timer_Id cancelled_timer_id{}; + frame_policy::Timer_Id cancelled_timer_id{}; { std::lock_guard lock(mutex); switch (phase) { @@ -179,7 +178,7 @@ void Throttled_Latest_only::Private::timer_cancelled() { } void Throttled_Latest_only::Private::frame_due() { std::size_t selected_index = Frame_Count; - Timer_Id scheduled_timer_id{}; + frame_policy::Timer_Id scheduled_timer_id{}; std::optional interval; { std::lock_guard lock(mutex); @@ -194,7 +193,9 @@ void Throttled_Latest_only::Private::frame_due() { if (refreshed_interval) { interval = *refreshed_interval; scheduled_timer_id = *timer_id; - const bool rendering = std::ranges::any_of(frames, [](const Frame_Slot& slot) { return slot.phase == Frame_Phase::rendering; }); + const bool rendering = std::ranges::any_of(frames, [](const Frame_Slot& slot) { + return slot.phase == Frame_Phase::rendering; + }); if (!rendering) { for (std::size_t index = 0; index < Frame_Count; ++index) { if (frames[index].phase == Frame_Phase::idle) { @@ -219,8 +220,7 @@ void Throttled_Latest_only::Private::frame_due() { return; } try { - auto scene_private = scene->d_ptr(); - const auto result = scene_private->render(frames[selected_index].frame, [this, selected_index](proxy& completed_frame, std::exception_ptr failure) { + const auto result = scene->render(frames[selected_index].frame, [this, selected_index](proxy& completed_frame, std::exception_ptr failure) { if (failure) { abandon_render(selected_index); std::rethrow_exception(failure); @@ -228,26 +228,29 @@ void Throttled_Latest_only::Private::frame_due() { rendered(selected_index, completed_frame); }); record_render_submission(result); - if (result != Render_Scene_Result::submitted) abandon_render(selected_index); + if (result != frame_policy::Render_Scene_Result::submitted) abandon_render(selected_index); } catch (...) { abandon_render(selected_index); throw; } } -void Throttled_Latest_only::Private::record_render_submission(Render_Scene_Result result) { +void Throttled_Latest_only::Private::record_render_submission(frame_policy::Render_Scene_Result result) { std::lock_guard lock(mutex); auto& state = *get().internal.use(); switch (result) { - case Render_Scene_Result::submitted: state.render_submission_error.reset(); break; - case Render_Scene_Result::runtime_not_initialized: state.render_submission_error = Frame_Policy_Render_Submission_Result::runtime_not_initialized; break; - case Render_Scene_Result::task_graph_invalid: state.render_submission_error = Frame_Policy_Render_Submission_Result::task_graph_invalid; break; - case Render_Scene_Result::frame_missing: - case Render_Scene_Result::completion_missing: std::terminate(); + case frame_policy::Render_Scene_Result::submitted: state.render_submission_error.reset(); + break; + case frame_policy::Render_Scene_Result::runtime_not_initialized: state.render_submission_error = Frame_Policy_Render_Submission_Result::runtime_not_initialized; + break; + case frame_policy::Render_Scene_Result::task_graph_invalid: state.render_submission_error = Frame_Policy_Render_Submission_Result::task_graph_invalid; + break; + case frame_policy::Render_Scene_Result::frame_missing: + case frame_policy::Render_Scene_Result::completion_missing: std::terminate(); } publish_state(); } -void Throttled_Latest_only::Private::rendered(std::size_t slot_index, proxy& completed_frame) { +void Throttled_Latest_only::Private::rendered(std::size_t slot_index, proxy& completed_frame) { bool dispatch = false; { std::lock_guard lock(mutex); @@ -295,8 +298,7 @@ void Throttled_Latest_only::Private::rendered(std::size_t slot_index, proxyd_ptr(); - sink_private->send(frames[slot_index].frame, [this, slot_index](proxy& completed_frame) { + sink->send(frames[slot_index].frame, [this, slot_index](proxy& completed_frame) { sent(slot_index, completed_frame); }); } @@ -305,7 +307,7 @@ void Throttled_Latest_only::Private::dispatch_send(std::size_t slot_index) { throw; } } -void Throttled_Latest_only::Private::sent(std::size_t slot_index, proxy& completed_frame) { +void Throttled_Latest_only::Private::sent(std::size_t slot_index, proxy& completed_frame) { std::size_t next_send_index = Frame_Count; { std::lock_guard lock(mutex); @@ -359,7 +361,7 @@ void Throttled_Latest_only::Private::abandon_send(std::size_t slot_index) { finish_stop_if_ready(); } void Throttled_Latest_only::Private::finish_stop_if_ready() { - std::array, Frame_Count> retired_frames; + std::array, Frame_Count> retired_frames; Stop_Completion completion; { std::lock_guard lock(mutex); diff --git a/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.hpp b/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.hpp index afddcdf..af1eb7c 100644 --- a/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.hpp +++ b/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.hpp @@ -1,7 +1,6 @@ #pragma once #include "function/frame_policy/Frame_Policy.hpp" -#include "function/frame_policy/global.hpp" -#include "time_thread/Timer_Service.hpp" +#include "rely_facade.h" #include #include #include @@ -29,7 +28,7 @@ struct Throttled_Latest_only : Def { }; using Stop_Completion = std::function; struct Private; - Throttled_Latest_only(proxy timer_service, proxy scene, proxy sink); + Throttled_Latest_only(proxy timer_service, proxy scene, proxy sink); ~Throttled_Latest_only() noexcept; auto start() -> std::expected; auto stop(Stop_Completion completion) -> std::expected; diff --git a/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.ipp b/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.ipp index 380be07..31aed00 100644 --- a/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.ipp +++ b/kernel/kernel/include/function/frame_policy/Throttled_Latest_Only.ipp @@ -18,39 +18,38 @@ struct Throttled_Latest_only::Private : Prev_Private { sending }; struct Frame_Slot { - proxy frame; /* 帧池在本槽唯一拥有并循环复用的物理帧。 */ - Frame_Phase phase{Frame_Phase::idle}; /* 本槽当前用途的唯一权威状态。 */ + proxy frame; /* 帧池在本槽唯一拥有并循环复用的物理帧。 */ + Frame_Phase phase{Frame_Phase::idle}; /* 本槽当前用途的唯一权威状态。 */ std::chrono::steady_clock::time_point render_start; /* 当前帧开始渲染的单调时刻。 */ - std::chrono::steady_clock::time_point send_start; /* 当前帧开始发送的单调时刻。 */ + std::chrono::steady_clock::time_point send_start; /* 当前帧开始发送的单调时刻。 */ }; static constexpr std::size_t Frame_Count{3}; - Private(proxy timer_service, proxy scene, proxy sink); + Private(proxy timer_service, proxy scene, proxy sink); auto start() -> std::expected; auto stop(Stop_Completion completion) -> std::expected; [[nodiscard]] bool destructible() const noexcept; - private: auto prepare_start() -> std::expected; void rollback_start(); - void timer_started(Timer_Id id); + void timer_started(frame_policy::Timer_Id id); void cancel_failed(); void timer_cancelled(); void frame_due(); - void record_render_submission(Render_Scene_Result result); - void rendered(std::size_t slot_index, proxy& completed_frame); + void record_render_submission(frame_policy::Render_Scene_Result result); + void rendered(std::size_t slot_index, proxy& completed_frame); void dispatch_send(std::size_t slot_index); - void sent(std::size_t slot_index, proxy& completed_frame); + void sent(std::size_t slot_index, proxy& completed_frame); void abandon_render(std::size_t slot_index); void abandon_send(std::size_t slot_index); void finish_stop_if_ready(); void publish_state(); - proxy timer_service; /* 动态重设计时期限的必填业务能力所有权。 */ - proxy scene; /* 创建三帧并执行渲染的必填业务能力所有权。 */ - proxy sink; /* 串行发送最新已渲染帧的必填业务能力所有权。 */ + proxy timer_service; /* 动态重设计时期限的必填业务能力所有权。 */ + proxy scene; /* 创建三帧并执行渲染的必填业务能力所有权。 */ + proxy sink; /* 串行发送最新已渲染帧的必填业务能力所有权。 */ std::array frames; /* 固定三个槽位的轮转帧池。 */ - Stop_Completion stop_completion; /* 本次异步停止的唯一完成回调。 */ - std::optional timer_id; /* running/stopping 阶段的周期计时器标识。 */ - mutable std::mutex mutex; /* 保护生命周期、帧槽、Prop 推进、统计和 State 发布。 */ - Phase phase{Phase::stopped}; /* start/stop 生命周期的唯一权威状态。 */ + Stop_Completion stop_completion; /* 本次异步停止的唯一完成回调。 */ + std::optional timer_id; /* running/stopping 阶段的周期计时器标识。 */ + mutable std::mutex mutex; /* 保护生命周期、帧槽、Prop 推进、统计和 State 发布。 */ + Phase phase{Phase::stopped}; /* start/stop 生命周期的唯一权威状态。 */ }; } // namespace aethera diff --git a/kernel/kernel/include/function/frame_policy/global.cpp b/kernel/kernel/include/function/frame_policy/global.cpp deleted file mode 100644 index 5d86027..0000000 --- a/kernel/kernel/include/function/frame_policy/global.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "global.ipp" -#include -#include -namespace aethera {} diff --git a/kernel/kernel/include/function/frame_policy/global.hpp b/kernel/kernel/include/function/frame_policy/global.hpp deleted file mode 100644 index b05aa7c..0000000 --- a/kernel/kernel/include/function/frame_policy/global.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "model/Model.hpp" -#include -#include -#include -#include -namespace aethera { -struct FP_Frame : facade_builder::build {}; -using FP_Frame_Completion = std::function&)>; -using FP_Render_Completion = std::function&, std::exception_ptr)>; -enum struct Render_Scene_Result : std::uint8_t { - submitted, - frame_missing, - completion_missing, - runtime_not_initialized, - task_graph_invalid -}; -struct FP_Scene_Private : facade_builder -::add_convention<_create_frame, proxy()> -::add_convention<_render, Render_Scene_Result(proxy&, FP_Render_Completion)> -::build {}; -struct FP_Scene : facade_builder::add_convention<_d_ptr, proxy()>::build {}; -struct FP_Sink_Private : facade_builder -::add_convention<_send, void(proxy&, FP_Frame_Completion)> -::build {}; -struct FP_Sink : facade_builder::add_convention<_d_ptr, proxy()>::build {}; -} // namespace aethera diff --git a/kernel/kernel/include/function/frame_policy/global.ipp b/kernel/kernel/include/function/frame_policy/global.ipp deleted file mode 100644 index 6d3ae94..0000000 --- a/kernel/kernel/include/function/frame_policy/global.ipp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "global.hpp" diff --git a/kernel/kernel/include/function/frame_policy/rely_facade.h b/kernel/kernel/include/function/frame_policy/rely_facade.h new file mode 100644 index 0000000..6d57e3e --- /dev/null +++ b/kernel/kernel/include/function/frame_policy/rely_facade.h @@ -0,0 +1,20 @@ +#pragma once +#include "global.hpp" +#include +#include +#include +#include +#include + +namespace aethera::frame_policy { +using Timer_Id = std::uint64_t; +using Timer_Callback = std::function; +struct Frame : facade_builder::build {}; +using Frame_Completion = std::function&)>; +using Render_Completion = std::function&, std::exception_ptr)>; +enum struct Render_Scene_Result : std::uint8_t { submitted, runtime_not_initialized, task_graph_invalid, frame_missing, completion_missing }; +struct Scene : facade_builder::add_convention<_create_frame, proxy()>::add_convention<_render, Render_Scene_Result(proxy&, Render_Completion)>::support_relocation::build {}; +struct Sink : facade_builder::add_convention<_send, void(proxy&, Frame_Completion)>::support_relocation::build {}; +struct Timer_Service : facade_builder::add_convention<_schedule_every, Timer_Id(std::chrono::nanoseconds, Timer_Callback)>::add_convention<_cancel, void(Timer_Id, Timer_Callback)>::add_convention<_reschedule, void(Timer_Id, std::chrono::nanoseconds)>::support_relocation::build {}; +proxy make_timer_service(); +} // namespace aethera::frame_policy diff --git a/kernel/kernel/include/function/renderable/rely_facade.h b/kernel/kernel/include/function/renderable/rely_facade.h new file mode 100644 index 0000000..da4fe7b --- /dev/null +++ b/kernel/kernel/include/function/renderable/rely_facade.h @@ -0,0 +1,14 @@ +#pragma once +#include "global.hpp" +#include "../scene/rely_facade.h" +#include +#include +#include +#include +#include +namespace aethera::renderable { +enum struct Add_Task_Graph_Result : std::uint8_t { work_missing }; +struct Task_Node : facade_builder::add_skill::build {}; +struct Task_Graph : facade_builder::add_convention<_add, std::expected, Add_Task_Graph_Result>(std::string, std::function)>::add_convention<_clear, void()>::add_convention<_empty, bool() const noexcept>::add_convention<_taskflow, proxy()>::support_relocation::build {}; +proxy make_task_graph(std::string name); +} // namespace aethera::renderable diff --git a/kernel/kernel/include/function/renderable/rely_facade.hpp b/kernel/kernel/include/function/renderable/rely_facade.hpp deleted file mode 100644 index 37ed484..0000000 --- a/kernel/kernel/include/function/renderable/rely_facade.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "../../task_flow/task_flow_facade.hpp" diff --git a/kernel/kernel/include/function/renderable/renderable.hpp b/kernel/kernel/include/function/renderable/renderable.hpp index 9958328..2a0cfab 100644 --- a/kernel/kernel/include/function/renderable/renderable.hpp +++ b/kernel/kernel/include/function/renderable/renderable.hpp @@ -1,12 +1,10 @@ #pragma once #include "model/Model.hpp" -#include "task_flow/task_flow_facade.hpp" +#include "rely_facade.h" namespace aethera { template struct Renderable : Model_Layer { using Renderable_Type = Self; struct Private; - void advance(); - proxy& taskflow(); }; } // namespace aethera #include "renderable.ipp" diff --git a/kernel/kernel/include/function/renderable/renderable.ipp b/kernel/kernel/include/function/renderable/renderable.ipp index c5f337f..aea73a2 100644 --- a/kernel/kernel/include/function/renderable/renderable.ipp +++ b/kernel/kernel/include/function/renderable/renderable.ipp @@ -1,23 +1,15 @@ #pragma once namespace aethera { template struct Renderable::Private : Prev_Private { - void advance(Self& object); - proxy& taskflow(); + void advance(); + proxy taskflow(); + proxy& internal_taskflow() noexcept { return graph; } private: - proxy graph{make_task_graph("renderable")}; /* 唯一拥有本 Renderable 的任务图代理。 */ + proxy graph{renderable::make_task_graph("renderable")}; /* 唯一拥有本 Renderable 的任务图代理。 */ }; -template void Renderable::Private::advance(Self& object) { +template void Renderable::Private::advance() { auto& private_data = static_cast(*this); - if constexpr (requires { private_data.advance_renderable(object); }) private_data.advance_renderable(object); - else if constexpr (requires { private_data.advance_renderable(); }) private_data.advance_renderable(); -} -template proxy& Renderable::Private::taskflow() { return graph; } -template void Renderable::advance() { - auto& object = static_cast(*this); - object.d->advance(object); -} -template proxy& Renderable::taskflow() { - auto& object = static_cast(*this); - return object.d->taskflow(); + if constexpr (requires { private_data.advance_renderable(); }) private_data.advance_renderable(); } +template proxy Renderable::Private::taskflow() { return graph->taskflow(); } } // namespace aethera diff --git a/kernel/kernel/include/function/scene/Scene.cpp b/kernel/kernel/include/function/scene/Scene.cpp index 7ff3d1a..06f63fb 100644 --- a/kernel/kernel/include/function/scene/Scene.cpp +++ b/kernel/kernel/include/function/scene/Scene.cpp @@ -7,41 +7,64 @@ namespace detail { struct Scene_Frame {}; } Scene::Private::Private() = default; -proxy Scene::Private::create_frame() { - return pro::make_proxy(); +proxy Scene::Private::create_frame() { + return pro::make_proxy(); } -proxy& Scene::Private::taskflow() { return graph; } -auto Scene::Private::create_taskflow() -> std::expected, Create_Taskflow_Result> { - auto result = make_task_graph("scene.renderables"); - std::unordered_map> nodes; +proxy& Scene::Private::taskflow() { + return graph; +} +auto Scene::Private::create_taskflow() -> std::expected, Create_Taskflow_Result> { + auto result = scene::make_task_graph("scene.renderables"); + std::unordered_map> nodes; auto& renderables = get().internal.use(); std::optional error; - renderables.for_each_topological([&](Dag_Node_Id id, proxy& renderable) { if (error) return; auto component = renderable->taskflow()->component(); auto composed = result->compose("renderable." + std::to_string(id.value), component); if (!composed) { switch (composed.error()) { case Compose_Task_Graph_Result::component_unavailable: error = Create_Taskflow_Result::component_unavailable; break; case Compose_Task_Graph_Result::dependency_cycle: error = Create_Taskflow_Result::dependency_cycle; break; case Compose_Task_Graph_Result::already_composed: error = Create_Taskflow_Result::already_composed; break; } return; } nodes.emplace(id.value, std::move(*composed)); }); + renderables.for_each_topological([&](Dag_Node_Id id, proxy& renderable) { + if (error) return; + auto taskflow = renderable->taskflow(); + auto component = taskflow->component(); + auto composed = result->compose("renderable." + std::to_string(id.value), component); + if (!composed) { + switch (composed.error()) { + case scene::Compose_Task_Graph_Result::component_unavailable: error = Create_Taskflow_Result::component_unavailable; + break; + case scene::Compose_Task_Graph_Result::dependency_cycle: error = Create_Taskflow_Result::dependency_cycle; + break; + case scene::Compose_Task_Graph_Result::already_composed: error = Create_Taskflow_Result::already_composed; + break; + } + return; + } + nodes.emplace(id.value, std::move(*composed)); + }); if (error) return std::unexpected(*error); - renderables.for_each_dependency([&](Dag_Node_Id target, Dag_Node_Id source) { if (result->precede(nodes.at(source.value), nodes.at(target.value)) != Precede_Task_Graph_Result::preceded) error = Create_Taskflow_Result::dependency_unavailable; }); + renderables.for_each_dependency([&](Dag_Node_Id target, Dag_Node_Id source) { + if (result->precede(nodes.at(source.value), nodes.at(target.value)) != scene::Precede_Task_Graph_Result::preceded) error = Create_Taskflow_Result::dependency_unavailable; + }); if (error) return std::unexpected(*error); return result; } auto Scene::Private::advance() -> std::expected { auto& renderables = get(); renderables.internal.advance(); - renderables.internal.use().for_each_topological([](Dag_Node_Id, proxy& renderable) { renderable->advance(); }); + renderables.internal.use().for_each_topological([](Dag_Node_Id, proxy& renderable) { + renderable->advance(); + }); auto next_graph = create_taskflow(); if (!next_graph) return std::unexpected(next_graph.error()); graph = std::move(*next_graph); return {}; } -Render_Scene_Result Scene::Private::render(proxy& frame, FP_Render_Completion completion) { - if (!frame) return Render_Scene_Result::frame_missing; - if (!completion) return Render_Scene_Result::completion_missing; - if (!advance()) return Render_Scene_Result::task_graph_invalid; +frame_policy::Render_Scene_Result Scene::Private::render(proxy& frame, frame_policy::Render_Completion completion) { + if (!frame) return frame_policy::Render_Scene_Result::frame_missing; + if (!completion) return frame_policy::Render_Scene_Result::completion_missing; + if (!advance()) return frame_policy::Render_Scene_Result::task_graph_invalid; const auto result = graph->run([frame = std::ref(frame), completion = std::move(completion)](std::exception_ptr failure) mutable { completion(frame.get(), std::move(failure)); }); switch (result) { - case Run_Task_Graph_Result::submitted: return Render_Scene_Result::submitted; - case Run_Task_Graph_Result::runtime_not_initialized: return Render_Scene_Result::runtime_not_initialized; - case Run_Task_Graph_Result::completion_missing: return Render_Scene_Result::completion_missing; + case scene::Run_Task_Graph_Result::submitted: return frame_policy::Render_Scene_Result::submitted; + case scene::Run_Task_Graph_Result::runtime_not_initialized: return frame_policy::Render_Scene_Result::runtime_not_initialized; + case scene::Run_Task_Graph_Result::completion_missing: return frame_policy::Render_Scene_Result::completion_missing; } std::terminate(); } diff --git a/kernel/kernel/include/function/scene/Scene.hpp b/kernel/kernel/include/function/scene/Scene.hpp index 04ebd5e..8185afe 100644 --- a/kernel/kernel/include/function/scene/Scene.hpp +++ b/kernel/kernel/include/function/scene/Scene.hpp @@ -1,5 +1,5 @@ #pragma once -#include "../frame_policy/global.hpp" +#include "../frame_policy/rely_facade.h" #include "model/Model.hpp" #include "relation/Dag.hpp" #include diff --git a/kernel/kernel/include/function/scene/Scene.ipp b/kernel/kernel/include/function/scene/Scene.ipp index 2677f25..3d5a5ec 100644 --- a/kernel/kernel/include/function/scene/Scene.ipp +++ b/kernel/kernel/include/function/scene/Scene.ipp @@ -3,12 +3,12 @@ namespace aethera { struct Scene::Private : Prev_Private { enum struct Create_Taskflow_Result : std::uint8_t { component_unavailable, dependency_cycle, already_composed, dependency_unavailable }; Private(); - proxy create_frame(); - Render_Scene_Result render(proxy& frame, FP_Render_Completion completion); - proxy& taskflow(); - auto create_taskflow() -> std::expected, Create_Taskflow_Result>; + proxy create_frame(); + frame_policy::Render_Scene_Result render(proxy& frame, frame_policy::Render_Completion completion); + proxy& taskflow(); + auto create_taskflow() -> std::expected, Create_Taskflow_Result>; auto advance() -> std::expected; private: - proxy graph{make_task_graph("scene")}; /* 唯一拥有当前组合任务图的跨模块代理。 */ + proxy graph{scene::make_task_graph("scene")}; /* 唯一拥有当前组合任务图的跨模块代理。 */ }; } // namespace aethera diff --git a/kernel/kernel/include/function/scene/rely_facade.h b/kernel/kernel/include/function/scene/rely_facade.h index 383854a..bdd7268 100644 --- a/kernel/kernel/include/function/scene/rely_facade.h +++ b/kernel/kernel/include/function/scene/rely_facade.h @@ -1,9 +1,19 @@ #pragma once #include "global.hpp" -#include "../../task_flow/task_flow_facade.hpp" +#include +#include +#include +#include +#include +#include namespace aethera::scene { -struct Renderable : facade_builder -::add_convention<_advance, void()> -::add_convention<_taskflow, proxy&()> -::build {}; +enum struct Compose_Task_Graph_Result : std::uint8_t { component_unavailable, dependency_cycle, already_composed }; +enum struct Precede_Task_Graph_Result : std::uint8_t { preceded, node_unavailable, dependency_cycle }; +enum struct Run_Task_Graph_Result : std::uint8_t { submitted, runtime_not_initialized, completion_missing }; +using Taskflow_Completion = std::function; +struct Task_Node : facade_builder::add_skill::build {}; +struct Task_Graph_Component : facade_builder::add_skill::build {}; +struct Task_Graph : facade_builder::add_convention<_component, proxy()>::add_convention<_compose, std::expected, Compose_Task_Graph_Result>(std::string, proxy&)>::add_convention<_precede, Precede_Task_Graph_Result(proxy&, proxy&)>::add_convention<_empty, bool() const noexcept>::add_convention<_run, Run_Task_Graph_Result(Taskflow_Completion)>::support_relocation::build {}; +proxy make_task_graph(std::string name); +struct Renderable : facade_builder::add_convention<_advance, void()>::add_convention<_taskflow, proxy()>::support_relocation::build {}; } // namespace aethera::scene diff --git a/kernel/kernel/include/global.hpp b/kernel/kernel/include/global.hpp index 62b709d..667979e 100644 --- a/kernel/kernel/include/global.hpp +++ b/kernel/kernel/include/global.hpp @@ -29,7 +29,6 @@ PRO_MEM_DISPATCH(run_observed); PRO_MEM_DISPATCH(use); PRO_MEM_DISPATCH(now); PRO_MEM_DISPATCH(render); -PRO_MEM_DISPATCH(d_ptr); PRO_MEM_DISPATCH(schedule_after); PRO_MEM_DISPATCH(schedule_every); PRO_MEM_DISPATCH(reschedule); diff --git a/kernel/kernel/include/model/Model.hpp b/kernel/kernel/include/model/Model.hpp index e757b52..e377b61 100644 --- a/kernel/kernel/include/model/Model.hpp +++ b/kernel/kernel/include/model/Model.hpp @@ -8,12 +8,10 @@ #include namespace aethera { namespace detail { -template struct Model_Private_Borrow { - template requires pro::proxiable - operator proxy() const { - return proxy{std::addressof(private_data)}; - } - Private& private_data; /* 必填、非拥有;有效期不超过返回它的公共 Model 对象。 */ +template struct Model_Private_Pointer { + using element_type = std::remove_reference_t()->d)>; + decltype(auto) operator*() const noexcept { return *model->d; } + Model_Pointer model; /* Owns or borrows the complete Model; dereference exposes its unique Private. */ }; template struct Model_Type_List {}; template struct Append_Model_Registrations; @@ -68,8 +66,22 @@ template struct Def : template