策略抽离

This commit is contained in:
2026-08-02 14:20:27 +08:00
parent 6d000f43b4
commit 2df8959ed6
87 changed files with 2454 additions and 1390 deletions
+112 -145
View File
@@ -1,5 +1,4 @@
#include "Plot_Core.h"
#include "Plot_Frame_Pipeline.h"
#include "../architecture/Renderable.h"
#include "../architecture/Render_Time.h"
#include "../architecture/Update_Completion.h"
@@ -13,37 +12,26 @@ class Plot_Core_Private;
struct Frame_Render_Job {
std::shared_ptr<Plot_Core_Private> owner;
std::uint64_t generation{};
Plot_Frame_Lease frame_lease;
Plot_Frame* buffer{};
Render_Frame_Surface frame_surface;
Render_Output* buffer{};
std::shared_ptr<Frame_Lifecycle_Record> lifecycle;
Plot_Render_Snapshot render_snapshot;
Renderable_Tree_Snapshot renderables;
Render_Frame_Snapshot render_snapshot;
Renderable_Frame_Tree renderables;
std::shared_ptr<Frame_Worker_Stats> worker_stat;
};
class Plot_Core_Private final : public std::enable_shared_from_this<Plot_Core_Private> {
class Plot_Core_Private final : public std::enable_shared_from_this<Plot_Core_Private>, public Frame_Flow_Host {
public:
explicit Plot_Core_Private(std::unique_ptr<Refresh_Strategy> s)
: strategy(std::move(s)) {}
explicit Plot_Core_Private(std::unique_ptr<Frame_Flow> selected_flow)
: flow(std::move(selected_flow)) {}
~Plot_Core_Private() = default;
bool render_enabled() const {
return rendering.load(std::memory_order_acquire);
}
bool destroying() const {
return !context || context->destroying.load(std::memory_order_acquire);
}
Refresh_Runtime_Snapshot refresh_runtime_snapshot(std::uint64_t now_ns = steady_now_ns()) const {
return {
render_enabled(),
destroying(),
pipeline.has_unrendered_edit(),
pipeline.render_job_state != Frame_Job_State::Idle,
pipeline.middle_frame_ready(),
pipeline.painting_frame_in_use(),
now_ns
};
Frame_Flow_Runtime_Snapshot runtime_snapshot(std::uint64_t now_ns) const override {
return flow ? flow->runtime_snapshot(now_ns, destroying()) : Frame_Flow_Runtime_Snapshot{destroying(), false, false, false, false, now_ns};
}
bool submit_render_once() {
if (!rendering.load(std::memory_order_acquire) || destroying())
if (destroying())
return false;
if (!root)
return false;
@@ -53,18 +41,20 @@ public:
};
if (size.empty())
return false;
auto frame_lease = pipeline.try_acquire_render_frame();
if (!frame_lease)
auto frame_surface = flow ? flow->begin_render_frame() : Render_Frame_Surface{};
if (!frame_surface)
return false;
Plot_Frame* buffer = frame_lease.frame;
Render_Output* buffer = frame_surface.output;
cancel_update_states(buffer->presented_update_states);
if (flow)
flow->drain_frame_update_states(buffer->presented_update_states);
std::uint64_t render_role_enter_ns = buffer->metadata ? buffer->metadata->render_role_enter_ns : 0;
buffer->metadata = std::make_shared<Frame_Lifecycle_Record>();
auto frame_record = buffer->metadata;
Frame_Lifecycle_Record& frame = *frame_record;
std::uint64_t submit_time = steady_now_ns();
frame.frame_id = ++next_frame_id;
frame.input_version = pipeline.edit_version.load(std::memory_order_acquire);
frame.input_version = frame_surface.input_version;
frame.render_request_ns = submit_time;
frame.render_role_enter_ns = render_role_enter_ns ? render_role_enter_ns : submit_time;
frame.core_data_time_ns = latest_input_time_ns.load(std::memory_order_acquire);
@@ -72,15 +62,12 @@ public:
frame.pixel_width = static_cast<std::uint64_t>(size.width);
frame.pixel_height = static_cast<std::uint64_t>(size.height);
frame.viewport_version = context->viewport_version.load(std::memory_order_acquire);
frame.wait_21_ns = submit_time > frame.render_role_enter_ns ? submit_time - frame.render_role_enter_ns : 0;
frame.render_queue_wait_ns = submit_time > frame.render_role_enter_ns ? submit_time - frame.render_role_enter_ns : 0;
frame.render_begin_ns = submit_time;
std::uint64_t previous_render_state_version = pipeline.rendered_edit_version;
pipeline.render_job_state = Frame_Job_State::Running;
pipeline.rendered_edit_version = frame.input_version;
auto job = std::make_shared<Frame_Render_Job>();
job->owner = shared_from_this();
job->generation = generation.load(std::memory_order_acquire);
job->frame_lease = std::move(frame_lease);
job->frame_surface = std::move(frame_surface);
job->buffer = buffer;
job->lifecycle = frame_record;
job->worker_stat = std::make_shared<Frame_Worker_Stats>();
@@ -127,11 +114,10 @@ public:
return true;
frame.outcome = Frame_Outcome::Worker_Budget_Dropped;
frame.worker.rejected_task_count++;
job->frame_lease.reset();
pipeline.rendered_edit_version = previous_render_state_version;
pipeline.render_job_state = Frame_Job_State::Idle;
if (flow)
flow->discard_render_frame(std::move(job->frame_surface));
collect_frame(frame_record);
trigger_refresh_strategy(Refresh_Trigger::Render_Finished, &frame);
notify_render_finished(frame);
return false;
}
static bool frame_job_valid(const std::shared_ptr<Frame_Render_Job>& job) {
@@ -169,7 +155,6 @@ public:
if (!frame_job_valid(job) || !job->lifecycle->render_end_ns)
return;
Frame_Lifecycle_Record& frame = *job->lifecycle;
job->buffer->version.store(frame.frame_id, std::memory_order_release);
for (const auto& update_state : job->buffer->presented_update_states) {
if (update_state)
update_state->complete_until(Update_Stage::Rendered);
@@ -191,25 +176,23 @@ public:
bool valid_generation = job->generation == generation.load(std::memory_order_acquire);
bool valid_context = !destroying();
if (!valid_generation || !valid_context || !frame.render_end_ns) {
job->frame_lease.reset();
if (flow)
flow->cancel_render_frame(std::move(job->frame_surface));
frame.outcome = Frame_Outcome::Cancelled;
pipeline.render_job_state = Frame_Job_State::Idle;
supersede_update_states(job->buffer->presented_update_states);
trigger_refresh_strategy(Refresh_Trigger::Render_Finished, &frame);
notify_render_finished(frame);
return;
}
auto publish_result = pipeline.try_publish_rendered_frame(std::move(job->frame_lease), steady_now_ns());
auto publish_result = flow ? flow->publish_rendered_frame(std::move(job->frame_surface), steady_now_ns()) : Render_Surface_Publish_Result{};
if (publish_result.superseded_frame_record) {
trigger_refresh_strategy(Refresh_Trigger::Frame_Returned, publish_result.superseded_frame_record.get());
collect_frame(publish_result.superseded_frame_record);
notify_frame_returned(publish_result.superseded_frame_record);
}
if (publish_result.dropped_frame_record) {
collect_frame(publish_result.dropped_frame_record);
}
pipeline.render_job_state = Frame_Job_State::Idle;
if (publish_result.request_present)
request_present(publish_result.dirty_rect);
trigger_refresh_strategy(Refresh_Trigger::Render_Finished, &frame);
notify_render_finished(frame);
}
void post_scheduler_action(Task task) {
if (!task)
@@ -227,85 +210,72 @@ public:
}
scheduler.post(std::move(action));
}
void trigger_refresh_strategy(Refresh_Trigger trigger, Frame_Lifecycle_Record* frame = nullptr) {
if (!strategy)
return;
std::uint64_t now_ns = steady_now_ns();
Refresh_Runtime_Snapshot runtime = refresh_runtime_snapshot(now_ns);
Refresh_Action action = strategy->on_trigger(trigger, runtime, frame);
apply_refresh_action(action, runtime);
bool try_render_once() override {
cancel_render_deadline();
return submit_render_once();
}
void notify_input_changed(std::uint64_t now_ns) {
if (!strategy)
return;
Refresh_Runtime_Snapshot runtime = refresh_runtime_snapshot(now_ns);
Refresh_Action action = strategy->on_trigger(Refresh_Trigger::Input_Dirty, runtime, nullptr);
apply_refresh_action(action, runtime);
void request_paint_from_middle() override {
auto update_result = flow ? flow->request_present(steady_now_ns()) : Render_Surface_Publish_Result{};
if (update_result.request_present)
request_present(update_result.dirty_rect);
}
void notify_model_dirty(std::uint64_t now_ns) {
if (flow)
flow->notify_model_dirty(now_ns);
}
void notify_viewport_changed(Size viewport, std::uint64_t now_ns) {
if (flow)
flow->notify_viewport_changed(viewport, now_ns);
}
void notify_render_finished(Frame_Lifecycle_Record& frame) {
if (flow)
flow->notify_render_finished(frame, steady_now_ns());
}
void notify_started() {
if (!strategy_started) {
strategy_started = true;
trigger_refresh_strategy(Refresh_Trigger::Started);
}
else {
trigger_refresh_strategy(Refresh_Trigger::Input_Dirty);
}
if (flow)
flow->activate_view(steady_now_ns());
}
void notify_paused() {
invalidate_refresh_deadline();
if (!strategy_started)
return;
strategy_started = false;
trigger_refresh_strategy(Refresh_Trigger::Paused);
if (flow)
flow->deactivate_view();
}
void notify_frame_returned(std::shared_ptr<Frame_Lifecycle_Record> frame) {
if (!frame)
return;
trigger_refresh_strategy(Refresh_Trigger::Frame_Returned, frame.get());
if (flow)
flow->notify_frame_returned(*frame, steady_now_ns());
collect_frame(frame);
}
void apply_refresh_action(Refresh_Action action, const Refresh_Runtime_Snapshot& runtime) {
if (action.request_paint) {
auto update_result = pipeline.request_present(steady_now_ns());
if (update_result.request_present)
request_present(update_result.dirty_rect);
}
if (action.try_render) {
invalidate_refresh_deadline();
submit_render_once();
return;
}
if (action.render_deadline_ns) {
schedule_refresh_deadline(action.render_deadline_ns);
return;
}
if (!runtime.enabled || runtime.destroying || !runtime.dirty)
invalidate_refresh_deadline();
void notify_paint_finished() {
if (flow)
flow->notify_paint_finished(steady_now_ns());
}
void schedule_refresh_deadline(std::uint64_t deadline_ns) {
void schedule_render_deadline(std::uint64_t deadline_ns) override {
if (deadline_ns <= steady_now_ns()) {
invalidate_refresh_deadline();
trigger_refresh_strategy(Refresh_Trigger::Timer_Fired);
cancel_render_deadline();
if (flow)
flow->notify_timer_fired(steady_now_ns());
return;
}
if (scheduled_refresh_deadline_ns && scheduled_refresh_deadline_ns <= deadline_ns)
if (scheduled_flow_deadline_ns && scheduled_flow_deadline_ns <= deadline_ns)
return;
scheduled_refresh_deadline_ns = deadline_ns;
std::uint64_t generation = ++refresh_deadline_generation;
scheduled_flow_deadline_ns = deadline_ns;
std::uint64_t generation = ++flow_deadline_generation;
auto guard = context;
auto self = shared_from_this();
Global::instance()->render_scheduler().post_at(deadline_ns, [guard, self, generation, deadline_ns]() {
if (!guard || guard->destroying.load(std::memory_order_acquire))
return;
if (self->refresh_deadline_generation != generation || self->scheduled_refresh_deadline_ns != deadline_ns)
if (self->flow_deadline_generation != generation || self->scheduled_flow_deadline_ns != deadline_ns)
return;
self->scheduled_refresh_deadline_ns = 0;
self->trigger_refresh_strategy(Refresh_Trigger::Timer_Fired);
self->scheduled_flow_deadline_ns = 0;
if (self->flow)
self->flow->notify_timer_fired(steady_now_ns());
});
}
void invalidate_refresh_deadline() {
scheduled_refresh_deadline_ns = 0;
++refresh_deadline_generation;
void cancel_render_deadline() override {
scheduled_flow_deadline_ns = 0;
++flow_deadline_generation;
}
void dispatch_event(const Event& event) {
if (!root)
@@ -346,8 +316,8 @@ public:
append_renderable_snapshot(result, root);
return result;
}
Renderable_Tree_Snapshot renderable_tree_snapshot() const {
Renderable_Tree_Snapshot result;
Renderable_Frame_Tree renderable_tree_snapshot() const {
Renderable_Frame_Tree result;
if (root)
root->append_tree_snapshot(result);
return result;
@@ -413,18 +383,15 @@ public:
Pixel p = context->background_rgba.load(std::memory_order_acquire);
return premultiplied_to_color(p);
}
std::unique_ptr<Refresh_Strategy> strategy;
std::unique_ptr<Frame_Flow> flow;
std::shared_ptr<Plot_Render_Context> context = std::make_shared<Plot_Render_Context>();
std::shared_ptr<Renderable> root;
std::vector<std::weak_ptr<Renderable>> hover_targets;
Plot_Frame_Pipeline pipeline;
std::weak_ptr<Presentation_Sink> sink;
std::atomic_bool rendering{false};
std::atomic<std::uint64_t> latest_input_time_ns{0};
std::atomic<std::uint64_t> pending_input_count{0};
bool strategy_started{};
std::uint64_t refresh_deadline_generation{};
std::uint64_t scheduled_refresh_deadline_ns{};
std::uint64_t flow_deadline_generation{};
std::uint64_t scheduled_flow_deadline_ns{};
std::uint64_t next_frame_id{};
std::uint64_t previous_frame_time_ns{};
Plot_Execution_Id plot_execution_id{};
@@ -436,17 +403,22 @@ Plot_Execution_Id next_plot_execution_id() {
return next_id.fetch_add(1, std::memory_order_acq_rel);
}
} // namespace
Plot_Core::Plot_Core(std::unique_ptr<Refresh_Strategy> strategy)
: d(std::make_shared<Plot_Core_Private>(std::move(strategy))) {
Plot_Core::Plot_Core(std::unique_ptr<Frame_Flow> flow)
: d(std::make_shared<Plot_Core_Private>(std::move(flow))) {
d->plot_execution_id = next_plot_execution_id();
d->context->owner.store(this, std::memory_order_release);
if (d->flow)
d->flow->attach(*d);
Global::instance()->render_scheduler().register_plot(this);
}
Plot_Core::~Plot_Core() {
d->context->destroying.store(true, std::memory_order_release);
d->generation.fetch_add(1, std::memory_order_acq_rel);
if (d->flow)
d->flow->shutdown();
Global::instance()->render_scheduler().remove_plot(this);
d->pipeline.cancel_all_update_states();
if (d->flow)
d->flow->cancel_all_update_states();
d->context->owner.store(nullptr, std::memory_order_release);
}
void Plot_Core::init() {
@@ -479,11 +451,11 @@ void Plot_Core::remove_renderable(const std::shared_ptr<Renderable>& renderable)
d->root.reset();
else
renderable->detach_from_parent();
mark_render_state_dirty();
notify_model_dirty();
}
void Plot_Core::set_background_color(Color color) {
d->context->background_rgba.store(premultiply(color), std::memory_order_release);
mark_render_state_dirty();
notify_model_dirty();
}
Color Plot_Core::background_color() const {
return d->background_color();
@@ -499,6 +471,11 @@ void Plot_Core::set_viewport_size(Size size) {
d->context->viewport_version.fetch_add(1, std::memory_order_acq_rel);
if (!size.empty())
d->context->first_resize.store(false, std::memory_order_release);
if (previous != size) {
d->post_scheduler_action([data = d, size]() {
data->notify_viewport_changed(size, steady_now_ns());
});
}
}
Size Plot_Core::viewport_size() const {
return {
@@ -509,78 +486,68 @@ Size Plot_Core::viewport_size() const {
void Plot_Core::dispatch_event(const Event& event) {
d->dispatch_event(event);
}
void Plot_Core::mark_render_state_dirty() {
void Plot_Core::notify_model_dirty() {
if (d->destroying())
return;
std::uint64_t now_ns = steady_now_ns();
d->pipeline.advance_edit_version();
if (d->flow)
d->flow->advance_edit_version();
d->latest_input_time_ns.store(now_ns, std::memory_order_release);
d->pending_input_count.fetch_add(1, std::memory_order_relaxed);
d->post_scheduler_action([data = d, now_ns]() {
data->notify_input_changed(now_ns);
data->notify_model_dirty(now_ns);
});
}
void Plot_Core::request_manual_refresh() {
void Plot_Core::request_explicit_render() {
if (d->destroying())
return;
d->post_scheduler_action([data = d]() {
data->trigger_refresh_strategy(Refresh_Trigger::Manual_Request);
data->notify_model_dirty(steady_now_ns());
});
}
void Plot_Core::start_render() {
void Plot_Core::activate_view() {
if (d->destroying())
return;
d->rendering.store(true, std::memory_order_release);
d->post_scheduler_action([data = d]() {
data->notify_started();
});
}
void Plot_Core::pause_render() {
d->rendering.store(false, std::memory_order_release);
void Plot_Core::deactivate_view() {
d->post_scheduler_action([data = d]() {
data->notify_paused();
});
}
bool Plot_Core::is_rendering() const {
return d->rendering.load(std::memory_order_acquire);
bool Plot_Core::view_active() const {
return d->flow && d->flow->view_active();
}
void Plot_Core::set_presentation_sink(std::weak_ptr<Presentation_Sink> sink) {
d->sink = std::move(sink);
}
Present_Frame_Lease Plot_Core::begin_present() {
Present_Frame_Lease result;
if (!d->root)
Present_Surface_Lease Plot_Core::begin_present() {
Present_Surface_Lease result;
if (!d->root || !d->flow)
return result;
auto consumed = d->pipeline.try_acquire_paint_frame(steady_now_ns());
if (consumed.returned_frame_record) {
d->post_scheduler_action([data = d, frame = consumed.returned_frame_record]() mutable {
std::shared_ptr<Frame_Lifecycle_Record> returned_frame;
result = d->flow->begin_present(steady_now_ns(), returned_frame);
if (returned_frame) {
d->post_scheduler_action([data = d, frame = std::move(returned_frame)]() mutable {
data->notify_frame_returned(frame);
});
}
result.is_new_frame = consumed.has_new_frame;
result.update_was_pending = consumed.present_request_was_pending;
if (consumed.lease)
result.lease_.emplace(std::move(consumed.lease));
if (!result.new_frame() && result.request_was_pending()) {
d->post_scheduler_action([data = d]() {
data->trigger_refresh_strategy(Refresh_Trigger::Paint_Finished);
data->notify_paint_finished();
});
}
return result;
}
void Plot_Core::end_present(Present_Frame_Lease&& frame, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns) {
if (frame.lease_ && frame.lease_->frame) {
auto* rendered_frame = frame.lease_->frame;
if (rendered_frame->metadata) {
rendered_frame->metadata->paint_begin_ns = paint_begin_ns;
rendered_frame->metadata->paint_end_ns = paint_end_ns;
rendered_frame->metadata->wait_23_ns = paint_begin_ns > rendered_frame->metadata->transition_12_ns ? paint_begin_ns - rendered_frame->metadata->transition_12_ns : 0;
}
complete_update_states(rendered_frame->presented_update_states, Update_Stage::Presented);
void Plot_Core::end_present(Present_Surface_Lease&& frame, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns) {
if (d->flow) {
if (auto returned = d->flow->end_present(std::move(frame), paint_begin_ns, paint_end_ns))
d->collect_frame(returned);
}
frame.lease_.reset();
d->post_scheduler_action([data = d]() mutable {
data->trigger_refresh_strategy(Refresh_Trigger::Paint_Finished);
data->notify_paint_finished();
});
}
} // namespace renderive