This commit is contained in:
2026-09-01 11:01:00 +08:00
parent 2fd60398c5
commit 55e2f63313
6 changed files with 142 additions and 90 deletions
@@ -1,14 +1,11 @@
#pragma once
#include "concurrent/base/Concurrent_Struct.hpp"
#include "model/Model.hpp"
#include "statistics/Sliding_Statistics.hpp"
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <optional>
namespace aethera {
/* 所有帧策略共享的自适应限速配置、公开状态和统计实现,不拥有具体调度状态。 */
struct Frame_Policy : Model_Layer<
@@ -16,28 +13,26 @@ struct Frame_Policy : Model_Layer<
Storage_Registration<Prop_Tag, Import_Struct_With_Dirty>,
Storage_Registration<State_Tag, Export_Struct>> {
static constexpr double Default_Frames_Per_Second{30.0};
struct Prop : Prev<Prop_Tag> {
std::optional<double> 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 State : Prev<State_Tag> {
std::uint64_t timer_ticks{}; /* 已处理的调度到期次数。 */
std::uint64_t dropped_timer_ticks{}; /* 到期时三帧均忙而丢弃的次数。 */
std::uint64_t completed_frames{}; /* 已完成媒体发送的帧数。 */
std::optional<double> render_capacity_fps; /* 有渲染样本时推导出的理论最大生成帧率。 */
std::optional<double> send_capacity_fps; /* 有发送样本时推导出的理论最大发送帧率。 */
std::uint64_t timer_ticks{}; /* 已处理的调度到期次数。 */
std::uint64_t dropped_timer_ticks{}; /* 到期时三帧均忙而丢弃的次数。 */
std::uint64_t completed_frames{}; /* 已完成媒体发送的帧数。 */
std::optional<double> render_capacity_fps; /* 有渲染样本时推导出的理论最大生成帧率。 */
std::optional<double> send_capacity_fps; /* 有发送样本时推导出的理论最大发送帧率。 */
double effective_frames_per_second{Default_Frames_Per_Second}; /* 当前有效限速来源的最小值。 */
Statistics_Summary render_time_ns; /* 渲染耗时滑动统计,单位纳秒。 */
Statistics_Summary send_time_ns; /* 发送耗时滑动统计,单位纳秒。 */
Statistics_Summary end_to_end_time_ns; /* 渲染开始至发送完成耗时统计,单位纳秒。 */
Statistics_Summary render_time_ns; /* 渲染耗时滑动统计,单位纳秒。 */
Statistics_Summary send_time_ns; /* 发送耗时滑动统计,单位纳秒。 */
Statistics_Summary end_to_end_time_ns; /* 渲染开始至发送完成耗时统计,单位纳秒。 */
};
struct Private;
struct Builder : Prev_Builder {};
};
}
#include "Frame_Policy.ipp"
@@ -8,8 +8,7 @@ namespace aethera {
* 自适应限速、最多三帧在途的 latest-only 策略。Scene 创建三个具体帧;策略轮转复用,
* 三槽均忙时丢弃本次 tickstop completion 前排空 Scene/Sink 借用并销毁全部帧。
*/
struct Throttled_Latest_only :
Def<Throttled_Latest_only, Frame_Policy> {
struct Throttled_Latest_only : Def<Throttled_Latest_only, Frame_Policy> {
enum struct Start_Result : std::uint8_t {
started,
already_running,
+57 -29
View File
@@ -3,33 +3,60 @@
#include "../concurrent/storage/Tagged_Storage.hpp"
#include <memory>
#include <type_traits>
#include <utility>
namespace aethera {
namespace detail {
template <typename... Types> struct Model_Type_List {};
template <typename List, typename... Registrations> struct Append_Model_Registrations;
template <typename Tag, typename List> struct Model_Tag_Registered;
template <typename Tag, typename Base, bool Registered> struct Previous_Model_Value;
struct Empty_Prop {};
struct Empty_State {};
template <typename Tag, typename Layer, typename = void> struct Model_Tag_Value;
template <typename Tag, typename List> struct Model_Registration;
template <typename Tag, typename Layer, typename List> struct Model_Value;
template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename Layer,
typename... Args>
concept Writable_Model_Value = requires(
Concurrent_Storage<typename Model_Value<
Tag,
Layer,
typename Layer::Storage_Registrations>::Type>& storage,
Args&&... args) {
storage.write(std::forward<Args>(args)...);
};
template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename Layer,
typename... Args>
concept Readable_Model_Value = requires(
const Concurrent_Storage<typename Model_Value<
Tag,
Layer,
typename Layer::Storage_Registrations>::Type>& storage,
Args&&... args) {
storage.read(std::forward<Args>(args)...);
};
struct Empty_Model_Value {};
}
/* Tag 负责选择各定义层的 Prop 类型;同一个 Tag 在注册表中只允许出现一次。 */
struct Prop_Tag {
using Root_Type = detail::Empty_Prop;
template <typename Layer> using Value = typename Layer::Prop;
};
/* Tag 负责选择各定义层的 State 类型。 */
struct State_Tag {
using Root_Type = detail::Empty_State;
template <typename Layer> using Value = typename Layer::State;
};
/* 把一个业务 Tag 注册到接受单个值类型的 Concurrent Storage 模板。 */
template <typename Tag, template <typename...> typename Concurrent_Storage> struct Storage_Registration {
template <
typename Tag,
template <typename...> typename Concurrent_Storage>
struct Storage_Registration {
using Tag_Type = Tag;
template <typename Value> using Storage = Concurrent_Storage<Value>;
template <typename Layer>
using Value = typename detail::Model_Tag_Value<Tag, Layer>::Type;
};
struct Root {
using Storage_Registrations = detail::Model_Type_List<>;
template <typename Tag> using Prev = typename Tag::Root_Type;
struct Private {};
struct Builder {};
};
@@ -40,12 +67,10 @@ template <typename Base, typename... Registrations> struct Model_Layer : Base {
using Storage_Registrations = typename detail::Append_Model_Registrations<
typename Base::Storage_Registrations,
Registrations...>::Type;
template <typename Tag> using Prev = typename detail::Previous_Model_Value<
template <typename Tag> using Prev = typename detail::Model_Value<
Tag,
Base,
detail::Model_Tag_Registered<
Tag,
typename Base::Storage_Registrations>::value>::Type;
Storage_Registrations>::Type;
using Prev_Private = typename Base::Private;
using Prev_Builder = typename Base::Builder;
};
@@ -61,31 +86,34 @@ template <typename Self, typename Base, typename... Registrations> struct Def :
template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename... Args> requires requires(
Concurrent_Storage<typename Tag::template Value<Self>>& storage,
Args&&... args) {
storage.write(std::forward<Args>(args)...);
}
typename... Args>
requires detail::Writable_Model_Value<
Concurrent_Storage,
Tag,
Self,
Args...>
Builder& set(Args&&... args);
std::unique_ptr<Self> ret; /* 构建期间唯一拥有尚未发布的对象。 */
};
template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename... Args> requires requires(
Concurrent_Storage<typename Tag::template Value<Self>>& storage,
Args&&... args) {
storage.write(std::forward<Args>(args)...);
}
typename... Args>
requires detail::Writable_Model_Value<
Concurrent_Storage,
Tag,
Self,
Args...>
Self& write(Args&&... args);
template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename... Args> requires requires(
const Concurrent_Storage<typename Tag::template Value<Self>>& storage,
Args&&... args) {
storage.read(std::forward<Args>(args)...);
}
typename... Args>
requires detail::Readable_Model_Value<
Concurrent_Storage,
Tag,
Self,
Args...>
const Self& read(Args&&... args) const;
template <typename... Args> explicit Def(Args&&... args);
std::unique_ptr<Private> d; /* 唯一拥有最终 Private 和完整 Tagged Storage 集。 */
+61 -33
View File
@@ -28,13 +28,18 @@ struct Append_Model_Registrations<
using Type = Model_Type_List<Existing..., Registrations...>;
};
template <typename Tag, typename List>
struct Model_Tag_Registered;
template <typename Tag, typename Layer, typename>
struct Model_Tag_Value {
using Type = Empty_Model_Value;
};
template <typename Tag, typename... Registrations>
struct Model_Tag_Registered<Tag, Model_Type_List<Registrations...>> :
std::bool_constant<(
std::same_as<Tag, typename Registrations::Tag_Type> || ...)> {};
template <typename Tag, typename Layer>
struct Model_Tag_Value<
Tag,
Layer,
std::void_t<typename Tag::template Value<Layer>>> {
using Type = typename Tag::template Value<Layer>;
};
template <typename List>
struct Unique_Model_Tags;
@@ -50,23 +55,37 @@ struct Unique_Model_Tags<Model_Type_List<Registration, Rest...>> :
typename Rest::Tag_Type> && ...) &&
Unique_Model_Tags<Model_Type_List<Rest...>>::value> {};
template <typename Tag, typename Base, bool Registered>
struct Previous_Model_Value;
template <typename Tag, typename List>
struct Model_Registration;
template <typename Tag, typename Base>
struct Previous_Model_Value<Tag, Base, false> {
using Type = typename Tag::Root_Type;
template <typename Tag, typename Registration, typename... Rest>
struct Model_Registration<
Tag,
Model_Type_List<Registration, Rest...>> :
Model_Registration<Tag, Model_Type_List<Rest...>> {};
template <
typename Tag,
template <typename...> typename Concurrent_Storage,
typename... Rest>
struct Model_Registration<
Tag,
Model_Type_List<
Storage_Registration<Tag, Concurrent_Storage>,
Rest...>> {
using Type = Storage_Registration<Tag, Concurrent_Storage>;
};
template <typename Tag, typename Base>
struct Previous_Model_Value<Tag, Base, true> {
using Type = typename Tag::template Value<Base>;
template <typename Tag, typename Layer, typename List>
struct Model_Value {
using Registration = typename Model_Registration<Tag, List>::Type;
using Type = typename Registration::template Value<Layer>;
};
template <typename Self, typename Registration>
struct Attached_Model_Storage {
using Tag = typename Registration::Tag_Type;
using Value = typename Tag::template Value<Self>;
using Value = typename Registration::template Value<Self>;
using Type = Tagged_Storage<
Tag,
typename Registration::template Storage<Value>>;
@@ -115,15 +134,18 @@ template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename... Args>
requires requires(
Concurrent_Storage<typename Tag::template Value<Self>>& storage,
Args&&... args) {
storage.write(std::forward<Args>(args)...);
}
requires detail::Writable_Model_Value<
Concurrent_Storage,
Tag,
Self,
Args...>
typename Def<Self, Base, Registrations...>::Builder&
Def<Self, Base, Registrations...>::Builder::set(Args&&... args) {
auto& storage = ret->d->template get<Tag>();
using Value = typename Tag::template Value<Self>;
using Value = typename detail::Model_Value<
Tag,
Self,
Storage_Registrations>::Type;
static_assert(std::same_as<
std::remove_cvref_t<decltype(storage)>,
Concurrent_Storage<Value>>,
@@ -147,14 +169,17 @@ template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename... Args>
requires requires(
Concurrent_Storage<typename Tag::template Value<Self>>& storage,
Args&&... args) {
storage.write(std::forward<Args>(args)...);
}
requires detail::Writable_Model_Value<
Concurrent_Storage,
Tag,
Self,
Args...>
Self& Def<Self, Base, Registrations...>::write(Args&&... args) {
auto& storage = d->template get<Tag>();
using Value = typename Tag::template Value<Self>;
using Value = typename detail::Model_Value<
Tag,
Self,
Storage_Registrations>::Type;
static_assert(std::same_as<
std::remove_cvref_t<decltype(storage)>,
Concurrent_Storage<Value>>,
@@ -168,14 +193,17 @@ template <
template <typename...> typename Concurrent_Storage,
typename Tag,
typename... Args>
requires requires(
const Concurrent_Storage<typename Tag::template Value<Self>>& storage,
Args&&... args) {
storage.read(std::forward<Args>(args)...);
}
requires detail::Readable_Model_Value<
Concurrent_Storage,
Tag,
Self,
Args...>
const Self& Def<Self, Base, Registrations...>::read(Args&&... args) const {
const auto& storage = d->template get<Tag>();
using Value = typename Tag::template Value<Self>;
using Value = typename detail::Model_Value<
Tag,
Self,
Storage_Registrations>::Type;
static_assert(std::same_as<
std::remove_cvref_t<decltype(storage)>,
Concurrent_Storage<Value>>,
+1 -1
View File
@@ -5,7 +5,7 @@
| `Model.hpp/.ipp` | 按 Tag 组合定义链,并在最终 `Def` 挂接注册存储。 |
| `../concurrent/` | Model 使用的并发存储机制;拥有独立设计文档。 |
`Model_Layer` 通过 `Storage_Registration<Tag, Concurrent_Storage>` 注册一条业务值链。每个定义层用 `Prev<Tag>` 取得前一层值类型并继承;最终 `Def::Private` 根据完整注册表只创建一次 `Tagged_Storage_Set`。同一 Tag 重复注册属于编译期错误。
`Model_Layer` 通过 `Storage_Registration<Tag, Concurrent_Storage>` 注册一条业务值链。Tag 只定义如何从 Layer 选择对应业务类型;选择不到时,模型统一使用默认空类型。每个定义层用 `Prev<Tag>` 取得前一层值类型并继承;最终 `Def::Private` 根据完整注册表只创建一次 `Tagged_Storage_Set`。同一 Tag 重复注册属于编译期错误。
Builder 使用 `set<Concurrent_Storage, Tag>(...)`,最终模型使用 `write<Concurrent_Storage, Tag>(...)``read<Concurrent_Storage, Tag>(...)`。两个模板参数必须命中同一注册项,参数能力直接由对应并发存储的 `write/read(...)` 重载约束:Struct 可以整对象或按成员读写,List 保留自身批次语义。Builder 对 Struct 同时建立内部读面和外部写面且不产生 dirty;其他存储保留自身写入/消费语义。
+10 -8
View File
@@ -6,25 +6,27 @@
#include <concepts>
#include <vector>
namespace {
struct Number_List_Root : std::vector<int> {};
namespace model_test {
struct Number_List_Tag {
using Root_Type = Number_List_Root;
template <typename Layer>
using Value = typename Layer::Numbers;
template <typename Layer> using Value = typename Layer::Numbers;
};
}
namespace {
using model_test::Number_List_Tag;
struct Test_Model_Base : aethera::Model_Layer<
aethera::Root,
aethera::Storage_Registration<
aethera::Prop_Tag,
aethera::Import_Struct_With_Dirty>,
aethera::Storage_Registration<Number_List_Tag, aethera::Import_List>> {
aethera::Storage_Registration<
Number_List_Tag,
aethera::Import_List>> {
struct Prop : Prev<aethera::Prop_Tag> {
int base_number{};
};
struct Numbers : Prev<Number_List_Tag> {};
struct Numbers : Prev<Number_List_Tag>, std::vector<int> {};
struct Private : Prev_Private {};
struct Builder : Prev_Builder {};
};