diff --git a/kernel/kernel/include/observation/Tracy.hpp b/kernel/kernel/include/observation/Tracy.hpp index 6542781..3a230f9 100644 --- a/kernel/kernel/include/observation/Tracy.hpp +++ b/kernel/kernel/include/observation/Tracy.hpp @@ -97,6 +97,13 @@ inline void end_tracy_task_zone(Tracy_Task_Zone zone) noexcept { if (zone.context.active == 0) return; TracyCZoneEnd(zone.context) } +template +void attach_tracy_task_tags(Tracy_Task_Zone zone, const Tags& tags) { + if (zone.context.active == 0) return; + Tracy_Text_Sink sink; + serialize(sink, tags); + if (!sink.empty()) TracyCZoneText(zone.context, sink.data(), sink.size()) +} template void attach_tracy_tags(tracy::ScopedZone& zone, Make_Tags&& make_tags) { if (!zone.IsActive()) return; @@ -122,10 +129,12 @@ inline void end_tracy_task_zone(Tracy_Task_Zone) noexcept {} #define AETHERA_TRACE_PLOT_I(name, value) do { if (::aethera::observation::tracy_connected()) TracyCPlotI(name, static_cast(value)) } while (false) #define AETHERA_TRACE_THREAD_NAME(name) do { ::aethera::observation::set_tracy_thread_name(name); } while (false) #define AETHERA_TRACE_FRAME(name) FrameMarkNamed(name) +#define AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame, generation) , ::aethera::Taskflow_Trace_Context{frame, generation} #else #define AETHERA_TRACE_ZONE(name) #define AETHERA_TRACE_ZONE_TAGS(name, ...) #define AETHERA_TRACE_PLOT_I(name, value) #define AETHERA_TRACE_THREAD_NAME(name) #define AETHERA_TRACE_FRAME(name) +#define AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame, generation) #endif diff --git a/kernel/kernel/module/task_flow/export/export.h b/kernel/kernel/module/task_flow/export/export.h index ab96100..063e755 100644 --- a/kernel/kernel/module/task_flow/export/export.h +++ b/kernel/kernel/module/task_flow/export/export.h @@ -52,6 +52,10 @@ enum struct Initialize_Task_Runtime_Result : std::uint8_t { }; using Taskflow_Completion = std::function; using Taskflow_Exception_Boundary = std::function; +struct Taskflow_Trace_Context { + std::uint64_t frame{}; + std::uint64_t generation{}; +}; namespace task_flow { struct Task_Node : facade_builder ::add_convention<_describe_node, Describe_Task_Graph_Node_Result(std::string, std::string)> @@ -70,8 +74,8 @@ struct Task_Graph_Compose_Facade : facade_builder ::add_facade_with_substitution ::add_convention<_compose, std::expected, Compose_Task_Graph_Result>(std::string, proxy &)> ::add_convention<_precede, Precede_Task_Graph_Result(proxy &, proxy &)> -::add_convention<_run, Run_Taskflow_Result(Taskflow_Completion)> -::add_convention<_run_observed, Run_Taskflow_Result(Taskflow_Completion, Taskflow_Observation)> +::add_convention<_run, Run_Taskflow_Result(Taskflow_Completion), Run_Taskflow_Result(Taskflow_Completion, Taskflow_Trace_Context)> +::add_convention<_run_observed, Run_Taskflow_Result(Taskflow_Completion, Taskflow_Observation), Run_Taskflow_Result(Taskflow_Completion, Taskflow_Observation, Taskflow_Trace_Context)> ::add_convention<_corun_until, void(std::function)> ::build {}; struct Task_Graph_Facade : facade_builder::add_facade_with_substitution::add_facade_with_substitution::build {}; diff --git a/kernel/kernel/module/task_flow/src/Task_Graph_Model.hpp b/kernel/kernel/module/task_flow/src/Task_Graph_Model.hpp index 0475591..3554703 100644 --- a/kernel/kernel/module/task_flow/src/Task_Graph_Model.hpp +++ b/kernel/kernel/module/task_flow/src/Task_Graph_Model.hpp @@ -19,7 +19,9 @@ struct Task_Graph_Model::Private : Prev_Private { void clear(); bool empty() const noexcept; Run_Taskflow_Result run(Taskflow_Completion completion); + Run_Taskflow_Result run(Taskflow_Completion completion, Taskflow_Trace_Context trace_context); Run_Taskflow_Result run_observed(Taskflow_Completion completion, Taskflow_Observation observation); + Run_Taskflow_Result run_observed(Taskflow_Completion completion, Taskflow_Observation observation, Taskflow_Trace_Context trace_context); void corun_until(std::function predicate); private: std::shared_ptr graph; /* 所有消费 facade 共享的唯一权威任务图。 */ diff --git a/kernel/kernel/module/task_flow/src/Task_Runtime.cpp b/kernel/kernel/module/task_flow/src/Task_Runtime.cpp index 2a60a69..3bcf73a 100644 --- a/kernel/kernel/module/task_flow/src/Task_Runtime.cpp +++ b/kernel/kernel/module/task_flow/src/Task_Runtime.cpp @@ -52,7 +52,7 @@ using Clock = std::chrono::steady_clock; * 升级 Taskflow 时必须重新审核版本、字段布局、对齐以及 topology/on_exit 完成顺序。 */ static_assert(TF_VERSION == 400100); -void* task_observation(const tf::TaskView& task) noexcept { +detail::Taskflow_Observation_Execution* task_observer_execution(const tf::TaskView& task) noexcept { static_assert(sizeof(tf::TaskView) == sizeof(tf::Node*)); static_assert(alignof(tf::TaskView) == alignof(tf::Node*)); static_assert(sizeof(tf::Task) == sizeof(tf::Node*)); @@ -60,7 +60,7 @@ void* task_observation(const tf::TaskView& task) noexcept { auto* node = *reinterpret_cast(std::addressof(task)); tf::Task handle{}; *reinterpret_cast(std::addressof(handle)) = node; - return handle.data(); + return static_cast(handle.data()); } const tf::Worker& task_worker(const tf::WorkerView& worker) noexcept { static_assert(sizeof(tf::WorkerView) == sizeof(tf::Worker*)); @@ -71,6 +71,13 @@ const tf::Worker& task_worker(const tf::WorkerView& worker) noexcept { struct Task_Observer final : tf::ObserverInterface { #ifdef TRACY_ENABLE static constexpr std::size_t Tracy_Zone_Depth = 128; + struct Frame_Task_Trace_Tags { + std::uint64_t frame{}; + std::uint64_t generation{}; + std::string_view graph{}; + std::size_t worker{}; + std::uint64_t task{}; + }; struct Tracy_Worker_State { std::array zones{}; std::size_t depth{}; @@ -88,7 +95,7 @@ struct Task_Observer final : tf::ObserverInterface { observation::set_tracy_thread_name(name.data()); state.named = true; } - void trace_entry(const tf::Worker& worker, const tf::TaskView& task, std::uint64_t native_id) noexcept { + void trace_entry(const tf::Worker& worker, const tf::TaskView& task, std::uint64_t native_id, const detail::Taskflow_Observation_Execution* execution) noexcept { auto& state = tracy_worker_states[worker.id()]; name_worker(state, worker.id()); if (state.ignored_depth != 0) { @@ -104,7 +111,13 @@ struct Task_Observer final : tf::ObserverInterface { return; } const std::string_view name{task.name()}; - state.zones[state.depth++] = observation::begin_tracy_task_zone(name, native_id); + auto& zone = state.zones[state.depth++]; + zone = observation::begin_tracy_task_zone(name, native_id); + if (execution == nullptr) return; + std::string_view graph; + const auto* context = execution->trace_context(graph); + if (context == nullptr) return; + observation::attach_tracy_task_tags(zone, Frame_Task_Trace_Tags{context->frame, context->generation, graph, worker.id(), native_id}); } void trace_exit(const tf::Worker& worker) noexcept { auto& state = tracy_worker_states[worker.id()]; @@ -125,34 +138,28 @@ struct Task_Observer final : tf::ObserverInterface { #endif } void on_entry(tf::WorkerView worker, tf::TaskView task) override { - auto* observation_execution = task_observation(task); + auto* observation_execution = task_observer_execution(task); #ifdef TRACY_ENABLE const auto& native_worker = task_worker(worker); const auto native_id = static_cast(task.hash_value()); - if (observation_execution != nullptr) { - auto& execution = *static_cast(observation_execution); - execution.observe_entry(native_worker, native_id, Clock::now()); - } - trace_entry(native_worker, task, native_id); + if (observation_execution != nullptr && observation_execution->records_observation()) observation_execution->observe_entry(native_worker, native_id, Clock::now()); + trace_entry(native_worker, task, native_id, observation_execution); #else - if (observation_execution == nullptr) return; - auto& execution = *static_cast(observation_execution); - execution.observe_entry(task_worker(worker), static_cast(task.hash_value()), Clock::now()); + if (observation_execution == nullptr || !observation_execution->records_observation()) return; + observation_execution->observe_entry(task_worker(worker), static_cast(task.hash_value()), Clock::now()); #endif } void on_exit(tf::WorkerView worker, tf::TaskView task) override { - auto* observation_execution = task_observation(task); + auto* observation_execution = task_observer_execution(task); #ifdef TRACY_ENABLE const auto& native_worker = task_worker(worker); const auto native_id = static_cast(task.hash_value()); trace_exit(native_worker); - if (observation_execution == nullptr) return; - auto& execution = *static_cast(observation_execution); - execution.observe_exit(native_worker, native_id, Clock::now()); + if (observation_execution == nullptr || !observation_execution->records_observation()) return; + observation_execution->observe_exit(native_worker, native_id, Clock::now()); #else - if (observation_execution == nullptr) return; - auto& execution = *static_cast(observation_execution); - execution.observe_exit(task_worker(worker), static_cast(task.hash_value()), Clock::now()); + if (observation_execution == nullptr || !observation_execution->records_observation()) return; + observation_execution->observe_exit(task_worker(worker), static_cast(task.hash_value()), Clock::now()); #endif } }; @@ -188,7 +195,7 @@ public: if (!predicate) throw std::invalid_argument("task graph cooperative predicate is empty"); executor->corun_until(std::move(predicate)); } - Run_Taskflow_Result run(Task_Graph& graph, Taskflow_Completion completion, std::optional observation) { + Run_Taskflow_Result run(Task_Graph& graph, Taskflow_Completion completion, std::optional observation, std::optional trace_context) { if (!ready()) { return Run_Taskflow_Result::runtime_not_initialized; } @@ -215,6 +222,11 @@ public: if (!observation_execution) { return Run_Taskflow_Result::observation_unavailable; } +#ifdef TRACY_ENABLE + if (trace_context && observation::tracy_connected()) observation_execution->set_trace_context(*trace_context, graph_execution->native_taskflow().name()); +#else + (void)trace_context; +#endif auto execution = std::make_shared(std::move(graph_execution), std::move(*observation_execution), std::move(completion), *completion_boundary); execution->graph->bind_observation(execution->observation.binding()); (void)executor->run(execution->graph->native_taskflow(), [execution] { @@ -260,10 +272,16 @@ Initialize_Task_Runtime_Result initialize_task_runtime(std::size_t workers, Unkn return Task_Resource::instance().initialize(workers, failure_policy, std::move(exception_boundary)); } Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion) { - return Task_Resource::instance().run(graph, std::move(completion), std::nullopt); + return Task_Resource::instance().run(graph, std::move(completion), std::nullopt, std::nullopt); +} +Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion, Taskflow_Trace_Context trace_context) { + return Task_Resource::instance().run(graph, std::move(completion), std::nullopt, trace_context); } Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion, Taskflow_Observation observation) { - return Task_Resource::instance().run(graph, std::move(completion), std::move(observation)); + return Task_Resource::instance().run(graph, std::move(completion), std::move(observation), std::nullopt); +} +Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion, Taskflow_Observation observation, Taskflow_Trace_Context trace_context) { + return Task_Resource::instance().run(graph, std::move(completion), std::move(observation), trace_context); } void detail::corun_taskflow_until(std::function predicate) { diff --git a/kernel/kernel/module/task_flow/src/Task_Runtime.hpp b/kernel/kernel/module/task_flow/src/Task_Runtime.hpp index 9f16fd7..a20b098 100644 --- a/kernel/kernel/module/task_flow/src/Task_Runtime.hpp +++ b/kernel/kernel/module/task_flow/src/Task_Runtime.hpp @@ -14,6 +14,8 @@ void corun_taskflow_until(std::function predicate); } /* 完成回调接收业务任务传播出的 Unknown Failure;本次执行不记录观察数据。 */ Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion); +Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion, Taskflow_Trace_Context trace_context); /* 完成回调接收业务任务传播出的 Unknown Failure;observation 记录本次执行。 */ Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion, Taskflow_Observation observation); +Run_Taskflow_Result run_taskflow(Task_Graph& graph, Taskflow_Completion completion, Taskflow_Observation observation, Taskflow_Trace_Context trace_context); } diff --git a/kernel/kernel/module/task_flow/src/Taskflow_Observation.cpp b/kernel/kernel/module/task_flow/src/Taskflow_Observation.cpp index 0289c43..1579523 100644 --- a/kernel/kernel/module/task_flow/src/Taskflow_Observation.cpp +++ b/kernel/kernel/module/task_flow/src/Taskflow_Observation.cpp @@ -161,8 +161,20 @@ detail::Taskflow_Observation_Execution::~Taskflow_Observation_Execution() { } detail::Taskflow_Observation_Execution::Taskflow_Observation_Execution( Taskflow_Observation_Execution&&) noexcept = default; +bool detail::Taskflow_Observation_Execution::records_observation() const noexcept { + return observation != nullptr; +} +void detail::Taskflow_Observation_Execution::set_trace_context(Taskflow_Trace_Context context, std::string_view graph) noexcept { + trace_context_data = context; + trace_graph = graph; +} +const Taskflow_Trace_Context* detail::Taskflow_Observation_Execution::trace_context(std::string_view& graph) const noexcept { + if (!trace_context_data) return nullptr; + graph = trace_graph; + return std::addressof(*trace_context_data); +} detail::Taskflow_Observation_Execution* detail::Taskflow_Observation_Execution::binding() noexcept { - return observation ? this : nullptr; + return observation || trace_context_data ? this : nullptr; } void detail::Taskflow_Observation_Execution::observe_entry( const tf::Worker& worker, diff --git a/kernel/kernel/module/task_flow/src/detail/Taskflow_Execution.ipp b/kernel/kernel/module/task_flow/src/detail/Taskflow_Execution.ipp index fea7773..17ae239 100644 --- a/kernel/kernel/module/task_flow/src/detail/Taskflow_Execution.ipp +++ b/kernel/kernel/module/task_flow/src/detail/Taskflow_Execution.ipp @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include namespace tf { class Taskflow; @@ -73,6 +75,9 @@ public: const Taskflow_Observation_Execution&) = delete; Taskflow_Observation_Execution& operator=( const Taskflow_Observation_Execution&) = delete; + bool records_observation() const noexcept; + void set_trace_context(Taskflow_Trace_Context context, std::string_view graph) noexcept; + const Taskflow_Trace_Context* trace_context(std::string_view& graph) const noexcept; Taskflow_Observation_Execution* binding() noexcept; void observe_entry( const tf::Worker& worker, @@ -89,5 +94,7 @@ private: std::shared_ptr observation) noexcept; void cancel() noexcept; std::shared_ptr observation; /* 可空记录所有权;空表示本次执行未请求观察。 */ + std::optional trace_context_data{}; + std::string_view trace_graph{}; }; } diff --git a/kernel/kernel/module/task_flow/src/task_flow_facade.cpp b/kernel/kernel/module/task_flow/src/task_flow_facade.cpp index de5a947..81d5197 100644 --- a/kernel/kernel/module/task_flow/src/task_flow_facade.cpp +++ b/kernel/kernel/module/task_flow/src/task_flow_facade.cpp @@ -45,9 +45,15 @@ bool Task_Graph_Model::Private::empty() const noexcept { Run_Taskflow_Result Task_Graph_Model::Private::run(Taskflow_Completion completion) { return run_taskflow(*graph, std::move(completion)); } +Run_Taskflow_Result Task_Graph_Model::Private::run(Taskflow_Completion completion, Taskflow_Trace_Context trace_context) { + return run_taskflow(*graph, std::move(completion), trace_context); +} Run_Taskflow_Result Task_Graph_Model::Private::run_observed(Taskflow_Completion completion, Taskflow_Observation observation) { return run_taskflow(*graph, std::move(completion), std::move(observation)); } +Run_Taskflow_Result Task_Graph_Model::Private::run_observed(Taskflow_Completion completion, Taskflow_Observation observation, Taskflow_Trace_Context trace_context) { + return run_taskflow(*graph, std::move(completion), std::move(observation), trace_context); +} void Task_Graph_Model::Private::corun_until(std::function predicate) { aethera::detail::corun_taskflow_until(std::move(predicate)); } diff --git a/render_2D/render_2D/module/scene/Render_Scene_2D.cpp b/render_2D/render_2D/module/scene/Render_Scene_2D.cpp index 3274aa5..1f66320 100644 --- a/render_2D/render_2D/module/scene/Render_Scene_2D.cpp +++ b/render_2D/render_2D/module/scene/Render_Scene_2D.cpp @@ -1,4 +1,5 @@ #include "Render_Scene_2D.hpp" +#include "observation/Tracy.hpp" #include #include #include @@ -63,6 +64,7 @@ void Render_Scene_2D::Private::dispatch_events(Event_Batch& events) { Render_Scene_2D_Result Render_Scene_2D::Private::render(Frame_2D* frame, Completion completion) { if (!frame) return std::unexpected(Render_Scene_2D_Error{Render_Scene_2D_State_Result::frame_missing}); if (!completion) return std::unexpected(Render_Scene_2D_Error{Render_Scene_2D_State_Result::completion_missing}); + AETHERA_TRACE_FRAME("Render2D"); auto properties = concurrent(); properties.internal.advance(); commit(); @@ -77,9 +79,10 @@ Render_Scene_2D_Result Render_Scene_2D::Private::render(Frame_2D* frame, Complet const auto built = build_frame(target, current.viewport, current.background); if (!built) return built; auto completed = [frame, completion = std::move(completion)](std::exception_ptr failure) mutable { + AETHERA_TRACE_ZONE_TAGS("Render2D.Completion", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation}); completion(frame, std::move(failure)); }; - const auto submitted = frame->taskflow_trace_requested() ? taskflow()->run_observed(std::move(completed), detail::Frame_2D_Access::taskflow_observation(frame)) : taskflow()->run(std::move(completed)); + const auto submitted = frame->taskflow_trace_requested() ? taskflow()->run_observed(std::move(completed), detail::Frame_2D_Access::taskflow_observation(frame) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)) : taskflow()->run(std::move(completed) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)); if (submitted != Run_Taskflow_Result::submitted) return std::unexpected(Render_Scene_2D_Error{submitted}); return {}; } diff --git a/render_3D/render_3D/scene/Render_Scene_3D_Model.ipp b/render_3D/render_3D/scene/Render_Scene_3D_Model.ipp index e03599e..cdb1faa 100644 --- a/render_3D/render_3D/scene/Render_Scene_3D_Model.ipp +++ b/render_3D/render_3D/scene/Render_Scene_3D_Model.ipp @@ -2,6 +2,7 @@ #include "../detail/Exception.hpp" #include "../detail/Gpu_Completion_Service.hpp" #include "Error_handling_specification/Failure_Policy.hpp" +#include "observation/Tracy.hpp" #include #include #include @@ -237,6 +238,7 @@ inline void Render_Scene_3D::Private::render_datoviz(const Shared_Render_Executi frame->mark(Frame_Trace_Marker::backend_submit_queued); auto shared_reservation = std::make_shared(std::move(reservation.reservation)); submit(*execution->datoviz_frame, [this, execution, frame, shared_reservation = std::move(shared_reservation)](std::exception_ptr submission_failure) mutable { + AETHERA_TRACE_ZONE_TAGS("Render3D.Submit.Callback", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation}); try { frame->mark(Frame_Trace_Marker::backend_queue_left); if (submission_failure) { @@ -272,6 +274,7 @@ inline void Render_Scene_3D::Private::render_datoviz(const Shared_Render_Executi } inline void Render_Scene_3D::Private::observe_datoviz_completion(const Shared_Render_Execution& execution, std::optional result, std::exception_ptr failure) noexcept { + AETHERA_TRACE_ZONE_TAGS("Render3D.GPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation}); execution->frame->mark(Frame_Trace_Marker::gpu_completed); execution->completion_result = std::move(result); execution->backend_failure = std::move(failure); @@ -291,7 +294,7 @@ inline void Render_Scene_3D::Private::try_complete(const Shared_Render_Execution if (!task) throw std::logic_error("failed to create 3D completion task"); const auto submitted = graph->run([execution](std::exception_ptr runtime_failure) mutable { complete_execution(std::move(execution), std::move(runtime_failure)); - }); + } AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(execution->frame->identity().sequence, execution->frame->identity().generation)); if (submitted != Run_Taskflow_Result::submitted) throw std::runtime_error("3D completion task runtime is unavailable"); } catch (...) { @@ -330,6 +333,7 @@ inline std::exception_ptr Render_Scene_3D::Private::collect_datoviz(Render_Execu inline void Render_Scene_3D::Private::complete_execution(Shared_Render_Execution execution, std::exception_ptr runtime_failure) { auto* frame = execution->frame; + AETHERA_TRACE_ZONE_TAGS("Render3D.Frame.Completion", Taskflow_Trace_Context{frame->identity().sequence, frame->identity().generation}); auto callback = std::move(execution->completion); auto failure = execution->cpu_failure ? std::move(execution->cpu_failure) : std::move(execution->backend_failure); if (!failure) failure = std::move(execution->collection_failure); @@ -360,6 +364,7 @@ inline void Render_Scene_3D::Private::fail_datoviz(std::exception_ptr failure) n inline Render_Scene_3D::Render_Result Render_Scene_3D::Private::render(Frame_3D* frame, Completion completion) { if (!frame) return Render_Result::frame_missing; if (!completion) return Render_Result::completion_missing; + AETHERA_TRACE_FRAME("Render3D"); frame->mark(Frame_Trace_Marker::scene_render_entered); try { frame->mark(Frame_Trace_Marker::scene_advance_started); @@ -376,12 +381,13 @@ inline Render_Scene_3D::Render_Result Render_Scene_3D::Private::render(Frame_3D* auto graph = build_frame_graph(execution, parameters); frame->mark(Frame_Trace_Marker::scene_render_requested); auto completed = [this, execution](std::exception_ptr failure) { + AETHERA_TRACE_ZONE_TAGS("Render3D.CPU.Completion", Taskflow_Trace_Context{execution->frame->identity().sequence, execution->frame->identity().generation}); execution->cpu_failure = std::move(failure); if (execution->cpu_failure && !execution->backend_started.load(std::memory_order_acquire)) execution->backend_finished.store(true, std::memory_order_release); execution->cpu_finished.store(true, std::memory_order_release); try_complete(execution); }; - const auto submitted = frame->taskflow_trace_requested() ? graph->run_observed(std::move(completed), detail::Frame_3D_Access::taskflow_observation(frame)) : graph->run(std::move(completed)); + const auto submitted = frame->taskflow_trace_requested() ? graph->run_observed(std::move(completed), detail::Frame_3D_Access::taskflow_observation(frame) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)) : graph->run(std::move(completed) AETHERA_TRACE_TASKFLOW_CONTEXT_ARG(frame->identity().sequence, frame->identity().generation)); if (submitted != Run_Taskflow_Result::submitted) return Render_Result::backend_unavailable; return Render_Result::submitted; }