Renderive Scene 与 Taskflow 任务图
Scene 类型层次
Scene 不再使用维度枚举。运行时类型关系为:
Scene_Base
├── Scene_2D_Base
└── Scene_3D_Base
Scene2D_Context 通过 Triple_State_Strategy<Scene_2D_Base, ...> 继承 Scene_2D_Base,Scene3D_Context 通过 Triple_State_Strategy<Scene_3D_Base, ...> 继承 Scene_3D_Base。调用方通过类型系统、概念或 dynamic_cast 区分 2D 与 3D Scene。
Scene 三缓冲状态
Scene2D_Context 与 Scene3D_Context 都公开类型别名 Scene_State_Strategy。状态访问使用基类名限定,避免多继承时成员歧义:
scene.Scene_State_Strategy::set<&Scene_State::value>(value);
scene.Scene_State_Strategy::publish();
scene.Scene_State_Strategy::render_use_state();
三缓冲分别承担正在渲染、已发布待获取、前台写入三种职责。render() 提交任务前调用 acquire_render_state(),后台帧获得稳定的状态版本。
Scene 观察者
Scene 状态观察者记录状态缓存修改、发布和渲染获取事件。Scene 生命周期观察者记录:
render_submittedrender_startedrender_completedrender_failed
观察器和时间源沿用 Observer_State。
单一 Renderable
Renderable 不再拆分为 Scene 持有缓存和独立持有缓存两类。所有对象统一继承 Renderable_Base:
struct Spectrum : Renderable_Base {
explicit Spectrum(Scene_Base& scene)
: Renderable_Base(scene, {.cache_enabled = true}) {}
};
Renderable_Configuration::cache_enabled 只控制渲染结果是否跨帧复用。默认关闭,以保持每次 Scene 提交都重新渲染的旧语义。Scene2D 仍为每个 Renderable 维护颜色缓存,以支持渲染依赖顺序和显示合成顺序相互独立。
缓存开启后,首次渲染或调用 invalidate_cache() 后执行任务图;缓存有效时跳过内部任务图,直接参与最终颜色合成。缓存关闭时每帧执行。
Renderable 内部任务图
每个 Renderable 通过 build_task_graph(Renderable_Task_Graph&) 定义自己的 DAG。公开接口只暴露 Renderive 的任务句柄,不暴露 tf::Taskflow、tf::Task 或任何 Taskflow 头文件:
void build_task_graph(Renderable_Task_Graph& graph) override {
auto prepare = graph.emplace([this](const Scene_Render_Context&) {
prepare_data();
}, "prepare");
auto rasterize = graph.emplace([this](const Scene_Render_Context&) {
rasterize_cache();
}, "rasterize");
graph.precede(prepare, rasterize);
}
未覆盖 build_task_graph 时,基类自动创建一个调用虚函数 render() 的单节点图。
外部依赖与总图组合
dependency_node 表达 Renderable 之间的外部依赖,父节点先于子节点。每次后台渲染会:
- 为每个 Renderable 构造或复用其内部图描述。
- 将内部图转换为一个 Taskflow module task。
- 按
dependency_node连接 module task。 - 将所有 module task 连接到最终颜色缓存生成任务。
- 交给
tf::Executor执行并等待完成。
Taskflow 只在 Scene_Base.cpp 中包含。renderive_scene 对 Taskflow include 路径使用 PRIVATE,外部头文件不会受到 Taskflow 宏、类型或包含链污染。
显示树与依赖树
display_root 只决定最终颜色缓存合成顺序。dependency_root 只决定 Renderable module task 的执行依赖。两棵树继续保持独立,轴可以先计算但最后合成。
主程序入口
同一个 main() 支持两种模式:
renderive_scene_app
renderive_scene_app --gtest
不带参数执行主流程;传入 --gtest 后初始化 GTest 并运行测试。其他 GTest 参数可以放在 --gtest 后面。
Taskflow 查找
CMake 通过 RENDERIVE_TASKFLOW_ROOT 或系统 include 路径查找 taskflow/taskflow.hpp。Taskflow 不存在时,仅测试和沙盒构建使用 tests/compat/taskflow/taskflow.hpp 验证图生成与依赖语义;正式集成时把 RENDERIVE_TASKFLOW_ROOT 指向 Taskflow 4.1.0 根目录或 include 目录。
Scene 内存域
Scene_Base 接受外部 std::pmr::memory_resource 作为上游资源。Scene 内部建立 std::pmr::synchronized_pool_resource,所有可能跨线程访问的持久容器都使用该线程安全内存域:
std::pmr::unsynchronized_pool_resource application_resource;
Scene2D_Context<> scene(application_resource);
外部资源决定最终的上游分配机制。Scene 内部的同步池负责将来自调用线程、后台 Scene 线程和 Renderable 构图路径的分配串行化。外部资源必须比 Scene 以及由 Scene 工厂创建后仍存活的 Renderable 更长寿。
可通过以下接口访问两个层级:
scene.upstream_memory_resource();
scene.memory_resource();
upstream_memory_resource() 返回构造时传入的资源;memory_resource() 返回 Scene 实际使用的线程安全同步池。
单次渲染构图不长期占用同步池。Scene_Base::execute_taskflow() 和 Scene2D 树顺序生成使用局部 std::pmr::monotonic_buffer_resource,返回后整体释放临时索引、标记和任务句柄容器。
Renderable 两种构造模式
Scene 工厂模式同时控制 Renderable 对象、shared_ptr 控制块以及 Renderable 内部树和任务图分配:
Scene2D_Context<> scene(memory_resource);
auto renderable = scene.make_renderable<Spectrum_Renderable>(configuration);
scene.attach_renderable(renderable);
工厂只构造对象,不自动挂载,attach_renderable() 的原有语义不变。工厂分配器持有 Scene 内存域的共享所有权,因此 Renderable 析构时内存域仍然有效。
独立构造模式继续保留:
auto renderable = std::make_shared<Spectrum_Renderable>(scene, configuration);
Spectrum_Renderable stack_renderable(scene, configuration);
独立模式下,Renderable 对象本身和 shared_ptr 控制块由调用方选择的机制分配;Multiway_Node、Renderable_Task_Graph、任务名称和依赖边仍使用所属 Scene 的内存域。
独立 allocator-aware 组件
以下组件可脱离 Scene 独立注入资源:
Multiway_NodeRenderable_Task_GraphRecording_Color_CacheFlow_Refresh_StrategyHistory_Real_Time_DataProperty_Builder::build_with_resource()Property_Builder::build_unique_with_resource()
History_Real_Time_Data 的时间戳容器始终使用传入资源。历史值容器只有在 Container 本身支持 PMR allocator 时才使用该资源:
History_Real_Time_Data<int, std::pmr::vector<int>> history(memory_resource);
不受 Scene PMR 控制的分配
以下内存不属于 Renderive 自己的 allocator-aware 场景域:
- Taskflow 4.1.0 内部任务节点、执行队列和 executor 工作资源
std::function超出小对象优化后的内部存储std::thread的系统线程对象和线程栈- 异常运行时对象
- 用户自定义 State、Frame、Observer、Renderable 成员内部自行使用的非 PMR 容器
- 第三方渲染后端内部资源
Scene PMR 的语义是控制 Renderive 明确实现为 allocator-aware 的核心对象,不承诺接管第三方库和用户类型的全部动态分配。