优化了 还是卡
This commit is contained in:
+84
-33
@@ -1,5 +1,6 @@
|
||||
#include "Plot.hpp"
|
||||
#include "Renderable_Adapter.hpp"
|
||||
#include "Taskflow_Trace_Json.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <render_2D/plottable/Plottables.hpp>
|
||||
@@ -202,6 +203,8 @@ void append_event_statistics_json(nlohmann::json& output,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nlohmann::json taskflow_trace_json(const Taskflow_Frame_Trace& trace) {
|
||||
nlohmann::json markers = nlohmann::json::object();
|
||||
for (const auto& marker : trace.markers)
|
||||
@@ -265,6 +268,7 @@ nlohmann::json taskflow_trace_json(const Taskflow_Frame_Trace& trace) {
|
||||
{"executions", std::move(executions)}};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Scene_Object>
|
||||
void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input) {
|
||||
@@ -372,6 +376,8 @@ struct Plot::Private {
|
||||
mutable std::mutex taskflow_trace_mutex{}; /* 只保护低频请求结果的交换。 */
|
||||
std::size_t taskflow_trace_requested_count{}; /* 当前批次请求总帧数。 */
|
||||
std::vector<Taskflow_Frame_Trace> taskflow_traces{}; /* 已完成帧直接发布的 DAG 与 Observer 结果。 */
|
||||
Task_Node completion_tail{}; /* Scene 完成图中当前最后一个业务阶段。 */
|
||||
std::vector<std::unique_ptr<Task_Graph>> completion_extensions{}; /* 生命周期覆盖 Scene 对子图的借用。 */
|
||||
|
||||
template <typename Scene_Object>
|
||||
Private(std::unique_ptr<Scene_Object> value_scene,
|
||||
@@ -383,6 +389,15 @@ struct Plot::Private {
|
||||
else
|
||||
slot.frame = std::make_unique<Frame_3D>(Frame_Identity{});
|
||||
}
|
||||
auto& completion = std::visit(
|
||||
[](auto& scene_value) -> Task_Graph& {
|
||||
return scene_value->completion_taskflow();
|
||||
}, scene);
|
||||
completion_tail = completion.add("plot.frame.publish", [this] {
|
||||
publish_completed_frame();
|
||||
});
|
||||
completion_tail.describe("owner", "plot")
|
||||
.describe("stage", "completed pixels publish");
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json schema() const;
|
||||
@@ -391,7 +406,9 @@ struct Plot::Private {
|
||||
void consume_tick(std::weak_ptr<Plot> lifetime);
|
||||
void clock_tick(const Plot_Render_Tick& tick);
|
||||
void render_frame(Plot_Render_Tick tick);
|
||||
void queue_completed_frame(Render_Frame* frame);
|
||||
void publish_completed_frame();
|
||||
void retire_completed_frame(Render_Frame* frame);
|
||||
void attach_completion(std::unique_ptr<Task_Graph> completion);
|
||||
[[nodiscard]] bool mark_taskflow_trace(Render_Frame& frame);
|
||||
void fail(std::exception_ptr failure) noexcept;
|
||||
};
|
||||
@@ -598,9 +615,7 @@ void Plot::Private::render_frame(Plot_Render_Tick tick) {
|
||||
const Frame_Identity identity{sequence, tick.sequence == 0 ? sequence : tick.sequence};
|
||||
if (auto* scene_2d = std::get_if<std::unique_ptr<Scene_2D>>(&scene)) {
|
||||
auto& output = *std::get<std::unique_ptr<Frame_2D>>(managed->frame);
|
||||
output.begin(identity, pacing.video_enabled
|
||||
? render_2d::Pixel_Format::rgba8
|
||||
: Frame_2D::native_pixel_format);
|
||||
output.begin(identity, Frame_2D::native_pixel_format);
|
||||
taskflow_trace_claimed = mark_taskflow_trace(output);
|
||||
record_plot_measurements(output);
|
||||
(*scene_2d)->set<&Render_Scene_2D::Prop::viewport>(
|
||||
@@ -644,10 +659,8 @@ void Plot::Private::render_frame(Plot_Render_Tick tick) {
|
||||
}
|
||||
|
||||
|
||||
void Plot::Private::queue_completed_frame(Render_Frame* frame) {
|
||||
if (!frame)
|
||||
throw std::invalid_argument("Plot received a null completed frame");
|
||||
std::size_t slot_index{scene_frame_capacity};
|
||||
void Plot::Private::publish_completed_frame() {
|
||||
Render_Frame* frame{};
|
||||
Managed_Frame* managed{};
|
||||
{
|
||||
std::lock_guard lock(frame_mutex);
|
||||
@@ -665,42 +678,29 @@ void Plot::Private::queue_completed_frame(Render_Frame* frame) {
|
||||
callback_retired_slot.reset();
|
||||
}
|
||||
for (std::size_t index = 0; index < frame_slots.size(); ++index) {
|
||||
Render_Frame* address = std::visit(
|
||||
if (frame_slots[index].state != Frame_State::in_flight) continue;
|
||||
if (managed)
|
||||
throw std::logic_error("Plot has multiple active Scene frames");
|
||||
frame = std::visit(
|
||||
[](const auto& value) -> Render_Frame* { return value.get(); },
|
||||
frame_slots[index].frame);
|
||||
if (address != frame) continue;
|
||||
slot_index = index;
|
||||
managed = &frame_slots[index];
|
||||
break;
|
||||
}
|
||||
if (!managed || managed->state != Frame_State::in_flight)
|
||||
throw std::logic_error("frame callback has no externally owned active frame");
|
||||
throw std::logic_error("Scene completion graph has no active Plot frame");
|
||||
}
|
||||
|
||||
const auto retire = [this, slot_index] {
|
||||
std::lock_guard lock(frame_mutex);
|
||||
auto& completed = frame_slots[slot_index];
|
||||
if (completed.state != Frame_State::in_flight) return;
|
||||
if (callback_retired_slot)
|
||||
throw std::logic_error("Plot has more than one callback-retired frame");
|
||||
completed.state = Frame_State::callback_retired;
|
||||
callback_retired_slot = slot_index;
|
||||
};
|
||||
|
||||
try {
|
||||
if (frame->taskflow_trace_requested()) {
|
||||
auto trace = frame->taskflow_trace();
|
||||
std::lock_guard lock(taskflow_trace_mutex);
|
||||
taskflow_traces.push_back(std::move(trace));
|
||||
}
|
||||
const auto pacing = frame_policy.snapshot();
|
||||
const auto identity = frame->identity();
|
||||
Frame_Identity rendered_identity = identity;
|
||||
std::shared_ptr<const std::vector<std::byte>> pixel_storage;
|
||||
Plot_Pixel_Layout pixel_layout{Plot_Pixel_Layout::rgba8};
|
||||
std::uint32_t width{};
|
||||
std::uint32_t height{};
|
||||
if (auto* frame_2d =
|
||||
std::get_if<std::unique_ptr<Frame_2D>>(&managed->frame)) {
|
||||
pixel_layout = Plot_Pixel_Layout::bgra8;
|
||||
const auto image = (*frame_2d)->image();
|
||||
width = static_cast<std::uint32_t>(image.width);
|
||||
height = static_cast<std::uint32_t>(image.height);
|
||||
@@ -725,7 +725,7 @@ void Plot::Private::queue_completed_frame(Render_Frame* frame) {
|
||||
}
|
||||
|
||||
auto pixels = std::make_shared<const Plot_Pixel_Frame>(Plot_Pixel_Frame{
|
||||
std::move(pixel_storage), managed->presentation_time,
|
||||
std::move(pixel_storage), pixel_layout, managed->presentation_time,
|
||||
identity.sequence, identity.correlation_id,
|
||||
rendered_identity.sequence, rendered_identity.correlation_id,
|
||||
width, height});
|
||||
@@ -738,14 +738,60 @@ void Plot::Private::queue_completed_frame(Render_Frame* frame) {
|
||||
static_cast<std::uint64_t>(std::max<std::int64_t>(0,
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now() - publish_started).count())));
|
||||
retire();
|
||||
}
|
||||
catch (...) {
|
||||
retire();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void Plot::Private::retire_completed_frame(Render_Frame* frame) {
|
||||
if (!frame)
|
||||
throw std::invalid_argument("Plot received a null completed frame");
|
||||
std::size_t slot_index{scene_frame_capacity};
|
||||
{
|
||||
std::lock_guard lock(frame_mutex);
|
||||
for (std::size_t index = 0; index < frame_slots.size(); ++index) {
|
||||
auto* address = std::visit(
|
||||
[](const auto& value) -> Render_Frame* { return value.get(); },
|
||||
frame_slots[index].frame);
|
||||
if (address != frame) continue;
|
||||
if (frame_slots[index].state != Frame_State::in_flight)
|
||||
throw std::logic_error("completed Plot frame is not in flight");
|
||||
slot_index = index;
|
||||
break;
|
||||
}
|
||||
if (slot_index == scene_frame_capacity)
|
||||
throw std::logic_error(
|
||||
"frame callback has no externally owned active frame");
|
||||
if (callback_retired_slot)
|
||||
throw std::logic_error("Plot has more than one callback-retired frame");
|
||||
frame_slots[slot_index].state = Frame_State::callback_retired;
|
||||
callback_retired_slot = slot_index;
|
||||
}
|
||||
if (frame->taskflow_trace_requested()) {
|
||||
auto trace = frame->taskflow_trace();
|
||||
std::lock_guard lock(taskflow_trace_mutex);
|
||||
taskflow_traces.push_back(std::move(trace));
|
||||
}
|
||||
}
|
||||
|
||||
void Plot::Private::attach_completion(
|
||||
std::unique_ptr<Task_Graph> completion) {
|
||||
if (!completion || completion->empty())
|
||||
throw std::invalid_argument("Plot completion pipeline is empty");
|
||||
auto& scene_completion = std::visit(
|
||||
[](auto& scene_value) -> Task_Graph& {
|
||||
return scene_value->completion_taskflow();
|
||||
}, scene);
|
||||
completion_extensions.push_back(std::move(completion));
|
||||
auto extension = scene_completion.compose(
|
||||
completion_extensions.back()->name(), *completion_extensions.back());
|
||||
extension.describe("owner", "scene")
|
||||
.describe("stage", "frame pipeline extension");
|
||||
completion_tail.precede(extension);
|
||||
completion_tail = std::move(extension);
|
||||
}
|
||||
|
||||
Plot::Plot(std::unique_ptr<Scene_2D> scene,
|
||||
std::unique_ptr<Scene_View> view)
|
||||
: d(std::make_unique<Private>(std::move(scene), std::move(view))) {}
|
||||
@@ -754,6 +800,11 @@ Plot::Plot(std::unique_ptr<Scene_3D> scene,
|
||||
: d(std::make_unique<Private>(std::move(scene), std::move(view))) {}
|
||||
Plot::~Plot() = default;
|
||||
|
||||
void Plot::attach_scene_completion(
|
||||
std::unique_ptr<Task_Graph> completion) {
|
||||
d->attach_completion(std::move(completion));
|
||||
}
|
||||
|
||||
void Plot::ensure_started() {
|
||||
std::call_once(d->start_once, [this] {
|
||||
/*
|
||||
@@ -765,7 +816,7 @@ void Plot::ensure_started() {
|
||||
(*scene)->set_frame_callback(
|
||||
[weak = weak_from_this()](Frame_2D* frame) {
|
||||
if (auto owner = weak.lock()) {
|
||||
try { owner->d->queue_completed_frame(frame); }
|
||||
try { owner->d->retire_completed_frame(frame); }
|
||||
catch (...) { owner->d->fail(std::current_exception()); }
|
||||
}
|
||||
});
|
||||
@@ -773,7 +824,7 @@ void Plot::ensure_started() {
|
||||
std::get<std::unique_ptr<Scene_3D>>(d->scene)->set_frame_callback(
|
||||
[weak = weak_from_this()](Frame_3D* frame) {
|
||||
if (auto owner = weak.lock()) {
|
||||
try { owner->d->queue_completed_frame(frame); }
|
||||
try { owner->d->retire_completed_frame(frame); }
|
||||
catch (...) { owner->d->fail(std::current_exception()); }
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user