提升观测系统
隔离taskflow
This commit is contained in:
@@ -185,7 +185,8 @@ void Async_Render_Backend::Implementation::enqueue(Command command) {
|
||||
}
|
||||
if (!schedule) return;
|
||||
auto self = shared_from_this();
|
||||
aethera::schedule_task([self] { self->drain(); });
|
||||
aethera::schedule_task("render_3d.backend.drain",
|
||||
[self] { self->drain(); });
|
||||
}
|
||||
void Async_Render_Backend::Implementation::drain() noexcept {
|
||||
for (;;) {
|
||||
|
||||
@@ -10,7 +10,7 @@ bool Render_Scene_3D::Prop::operator==(const Prop&) const = default;
|
||||
bool Render_Scene_3D::State::operator==(const State&) const = default;
|
||||
Render_Scene_3D::Render_Result Render_Scene_3D::render(Frame_3D* frame) { return static_cast<Private&>(*d).dispatch->render(this, frame); }
|
||||
void Render_Scene_3D::set_frame_callback(Frame_Callback callback) { static_cast<Private&>(*d).dispatch->set_frame_callback(this, std::move(callback)); }
|
||||
tf::Taskflow& Render_Scene_3D::completion_taskflow() {
|
||||
Task_Graph& Render_Scene_3D::completion_taskflow() {
|
||||
return static_cast<Private&>(*d).completion_graph;
|
||||
}
|
||||
void Render_Scene_3D::reset_frame_statistics() {
|
||||
|
||||
@@ -70,7 +70,7 @@ struct Render_Scene_3D : Def<Render_Scene_3D, Scene, Dependency_Graph_Type<Submi
|
||||
* completion Taskflow 完成前调用方必须保持本帧像素所有权;节点若启动更晚结束的异步工作,
|
||||
* 必须捕获 share_pixels() 等拥有像素所有权的对象,禁止只捕获会被下一帧复用的裸 Frame_3D*。
|
||||
*/
|
||||
[[nodiscard]] tf::Taskflow& completion_taskflow();
|
||||
[[nodiscard]] Task_Graph& completion_taskflow();
|
||||
void activate_view();
|
||||
void deactivate_view();
|
||||
void reset_frame_statistics();
|
||||
|
||||
@@ -30,7 +30,7 @@ struct Render_Scene_3D::Private : Prev_Private {
|
||||
std::mutex render_mutex{}; /* 只保护完成回调和单帧准入。 */
|
||||
bool frame_in_flight{}; /* render 准入到异步完成回调返回的唯一状态源。 */
|
||||
Frame_Callback frame_callback{}; /* Scene 的唯一对外完成出口。 */
|
||||
tf::Taskflow completion_graph{}; /* GPU 像素完成后、发布回调前执行的外部续写图。 */
|
||||
Task_Graph completion_graph{"render_3d.completion"}; /* GPU 像素完成后、发布回调前执行的外部续写图。 */
|
||||
std::mutex completion_mutex{}; /* 只保护 completion 图拓扑的在途生命周期。 */
|
||||
std::condition_variable completion_condition{};
|
||||
bool completion_running{}; /* 析构等待异步 completion 图结束的唯一状态源。 */
|
||||
@@ -177,6 +177,7 @@ void Render_Scene_3D::Private::initialize_backend(
|
||||
callback = frame_callback;
|
||||
}
|
||||
auto finish = [this, object, frame, callback = std::move(callback)]() mutable {
|
||||
aethera::detail::finish_taskflow_trace(*frame);
|
||||
frame->mark(Frame_Trace_Marker::callback_started);
|
||||
if (callback) callback(frame);
|
||||
frame->mark(Frame_Trace_Marker::callback_finished);
|
||||
@@ -211,7 +212,11 @@ void Render_Scene_3D::Private::initialize_backend(
|
||||
* GPU 完成线程只触发 Taskflow topology,不等待编码/发送节点;最终回调在 topology 完成后执行。
|
||||
* 帧准入在 finish() 之前始终有效,因此 completion 图运行期间该外部 Frame 不会被下一帧复用。
|
||||
*/
|
||||
aethera::detail::run_taskflow(completion_graph, std::move(finish));
|
||||
if (frame->taskflow_trace_requested())
|
||||
aethera::detail::run_taskflow(completion_graph, *frame,
|
||||
"render_3d.completion", std::move(finish));
|
||||
else
|
||||
aethera::detail::run_taskflow(completion_graph, std::move(finish));
|
||||
});
|
||||
paint_context = std::make_shared<detail::Scene_Paint_Context<Object>>(
|
||||
detail::Scene_Paint_Context<Object>{
|
||||
@@ -290,14 +295,27 @@ void Render_Scene_3D::Private::process(Object* object, Callback&& callback) requ
|
||||
if (!state.paint_executed) return;
|
||||
const auto paint_started = std::chrono::steady_clock::now();
|
||||
if (dispatch->paint.builder) {
|
||||
if (!data->paint_graph) data->paint_graph = std::make_unique<tf::Taskflow>();
|
||||
if (!data->paint_graph) data->paint_graph = std::make_unique<Task_Graph>(
|
||||
std::string(dispatch->business_name) + ".paint");
|
||||
const bool rebuild = dispatch->paint.rebuild_predicate(root);
|
||||
if (!data->paint_graph_built || rebuild) { *data->paint_graph = dispatch->paint.builder(root); data->paint_graph_built = true; state.paint_graph_rebuilt = true; }
|
||||
state.paint_task_count = data->paint_graph->num_tasks();
|
||||
if (!data->paint_graph->empty()) aethera::detail::run_taskflow(*data->paint_graph);
|
||||
state.paint_task_count = data->paint_graph->size();
|
||||
if (!data->paint_graph->empty()) {
|
||||
if (frame->taskflow_trace_requested())
|
||||
aethera::detail::run_taskflow(
|
||||
*data->paint_graph, *frame,
|
||||
std::string(dispatch->business_name) + ".paint");
|
||||
else
|
||||
aethera::detail::run_taskflow(*data->paint_graph);
|
||||
}
|
||||
} else { state.paint_task_count = dispatch->paint.run ? 1 : 0; if (dispatch->paint.run) dispatch->paint.run(root); }
|
||||
if (!data->paint_extension.empty())
|
||||
aethera::detail::run_taskflow(data->paint_extension);
|
||||
if (frame->taskflow_trace_requested())
|
||||
aethera::detail::run_taskflow(
|
||||
data->paint_extension, *frame,
|
||||
std::string(dispatch->business_name) + ".paint.extension");
|
||||
else
|
||||
aethera::detail::run_taskflow(data->paint_extension);
|
||||
root->template take_dirty<Submit_Tag>();
|
||||
state.paint_execution_time_ns = static_cast<std::uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
@@ -336,6 +354,14 @@ Render_Scene_3D::Render_Result Render_Scene_3D::Private::render(Object* object,
|
||||
}
|
||||
} admission{*this, submitted};
|
||||
frame->mark(Frame_Trace_Marker::scene_render_requested);
|
||||
const bool trace_started = aethera::detail::begin_taskflow_trace(*frame);
|
||||
struct Trace_Scope {
|
||||
Frame_3D* frame{}; /* 提交前异常或拒绝时关闭 Observer 写入窗口。 */
|
||||
bool active{}; /* 提交成功后所有权转交异步完成回调。 */
|
||||
~Trace_Scope() {
|
||||
if (active) aethera::detail::finish_taskflow_trace(*frame);
|
||||
}
|
||||
} trace_scope{frame, trace_started};
|
||||
struct Active_Frame_Scope {
|
||||
Frame_3D*& target; /* 最终 Private 的同步 process 帧槽位。 */
|
||||
Frame_3D* previous{}; /* 嵌套调用前的帧;析构时恢复。 */
|
||||
@@ -343,7 +369,10 @@ Render_Scene_3D::Render_Result Render_Scene_3D::Private::render(Object* object,
|
||||
} active_frame_scope{active_frame, active_frame};
|
||||
active_frame = frame;
|
||||
object->process([&] { submitted = true; frame->mark(Frame_Trace_Marker::scene_render_finished); });
|
||||
if (submitted) return Render_Result::submitted;
|
||||
if (submitted) {
|
||||
trace_scope.active = false;
|
||||
return Render_Result::submitted;
|
||||
}
|
||||
const auto& prop = object->template read_prop<Render_Scene_3D::Base_Tag>();
|
||||
if (!prop.view_active) return Render_Result::view_inactive;
|
||||
if (prop.viewport.empty()) return Render_Result::empty_viewport;
|
||||
|
||||
@@ -19,7 +19,7 @@ struct Basic_Visual<Spec>::Private : Basic_Visual::Prev_Private {
|
||||
void prepare_data(Object* object);
|
||||
/* CRTP 子图能力:提交本 Visual 最近一次 Prepare 生成的唯一产物。 */
|
||||
template <Attached Object>
|
||||
[[nodiscard]] tf::Taskflow build_paint_graph(Object* object, const Prop& prop);
|
||||
[[nodiscard]] Task_Graph build_paint_graph(Object* object, const Prop& prop);
|
||||
/* CRTP 覆盖:绑定 Scene 后每帧执行 Paint;dirty 只表示 Prepared 数据是否更新,不控制帧生成。 */
|
||||
template <Attached Object>
|
||||
[[nodiscard]] bool should_paint(Object* object, const State& state, bool dirty);
|
||||
@@ -67,13 +67,13 @@ void Basic_Visual<Spec>::Private::prepare_data(Object* object) {
|
||||
}
|
||||
template <typename Spec>
|
||||
template <Attached Object>
|
||||
tf::Taskflow Basic_Visual<Spec>::Private::build_paint_graph(Object* object, const Prop&) {
|
||||
tf::Taskflow graph;
|
||||
graph.emplace([this, object] {
|
||||
Task_Graph Basic_Visual<Spec>::Private::build_paint_graph(Object* object, const Prop&) {
|
||||
Task_Graph graph{"render_3d.visual.paint"};
|
||||
graph.add("publish", [this, object] {
|
||||
if (auto context = paint_target.context.lock(); context && paint_target.enqueue) {
|
||||
paint_target.enqueue(context.get(), object, prepared);
|
||||
}
|
||||
}).name("render_3d.paint.publish");
|
||||
});
|
||||
return graph;
|
||||
}
|
||||
template <typename Spec>
|
||||
|
||||
@@ -68,9 +68,9 @@ TEST(Render_3D_Scene, Paint_Submits_Without_Waiting_For_Gpu) {
|
||||
Frame_3D exchanged_unchanged_frame{Frame_Identity{3, 0}};
|
||||
Frame_3D* completed_frame{};
|
||||
std::atomic_size_t completion_calls{};
|
||||
scene->completion_taskflow().emplace([&] {
|
||||
scene->completion_taskflow().add("test.scene_3d.completion", [&] {
|
||||
completion_calls.fetch_add(1, std::memory_order_release);
|
||||
}).name("test.scene_3d.completion");
|
||||
});
|
||||
scene->set_frame_callback([&](Frame_3D* value) {
|
||||
EXPECT_GT(completion_calls.load(std::memory_order_acquire), 0u);
|
||||
completed_frame = value;
|
||||
|
||||
Reference in New Issue
Block a user