Files
Renderive/Core/architecture/Frame_Scheduler.h
T
2026-08-03 11:22:22 +08:00

241 lines
11 KiB
C++

#pragma once
#include "Render_Config.h"
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
namespace renderive {
struct Frame_Lifecycle_Record;
struct Frame_Feedback_Event_Record;
struct Frame_Lifecycle_Observer {
virtual ~Frame_Lifecycle_Observer() = default;
virtual bool enabled() const = 0;
virtual bool capture_enabled() const {
return enabled();
}
virtual void collect_frame(std::shared_ptr<const Frame_Lifecycle_Record> frame) = 0;
virtual void collect_feedback_event(std::shared_ptr<const Frame_Feedback_Event_Record>) {}
};
struct Refresh_Control_Snapshot {
Refresh_Limit_Source source = Refresh_Limit_Source::Unknown;
Refresh_Limit_Source candidate_source = Refresh_Limit_Source::Unknown;
Low_Latency_Bottleneck_State bottleneck = Low_Latency_Bottleneck_State::Unknown;
Low_Latency_Bottleneck_State stable_bottleneck = Low_Latency_Bottleneck_State::Unknown;
Low_Latency_Bottleneck_State candidate_bottleneck = Low_Latency_Bottleneck_State::Unknown;
Low_Latency_Production_Mode production_mode = Low_Latency_Production_Mode::Latency_Eager;
Low_Latency_Limit_Reason limit_reason = Low_Latency_Limit_Reason::User_Fps;
Consumer_Confidence consumer_confidence = Consumer_Confidence::Low;
Consumer_Sample_Result last_consumer_sample_result = Consumer_Sample_Result::Rejected_No_New_Frame;
Low_Latency_Feedback_Decision last_decision = Low_Latency_Feedback_Decision::Hold_User_Period;
std::string decision_reason;
std::uint64_t decision_timestamp_ns{};
std::uint64_t candidate_age_ns{};
std::uint64_t candidate_samples{};
std::uint64_t producer_interval_ns{};
std::uint64_t producer_interval_current_ns{};
std::uint64_t producer_interval_srtt_ns{};
std::uint64_t producer_interval_jitter_ns{};
std::uint64_t input_period_ns{};
std::uint64_t input_interval_current_ns{};
std::uint64_t input_interval_srtt_ns{};
std::uint64_t input_jitter_ns{};
std::uint64_t render_period_ns{};
std::uint64_t render_service_current_ns{};
std::uint64_t render_service_srtt_ns{};
std::uint64_t render_jitter_ns{};
std::uint64_t paint_period_ns{};
std::uint64_t paint_jitter_ns{};
std::uint64_t ready_queue_srtt_ns{};
std::uint64_t ready_queue_jitter_ns{};
std::uint64_t gui_srtt_ns{};
std::uint64_t gui_jitter_ns{};
std::uint64_t consumption_srtt_ns{};
std::uint64_t consumption_jitter_ns{};
std::uint64_t request_to_update_post_current_ns{};
std::uint64_t request_to_update_post_srtt_ns{};
std::uint64_t request_to_update_post_jitter_ns{};
std::uint64_t update_to_paint_begin_ns{};
std::uint64_t update_post_to_paint_current_ns{};
std::uint64_t update_post_to_paint_srtt_ns{};
std::uint64_t update_to_paint_jitter_ns{};
std::uint64_t paint_service_ns{};
std::uint64_t paint_service_current_ns{};
std::uint64_t paint_service_srtt_ns{};
std::uint64_t paint_service_jitter_ns{};
std::uint64_t display_frame_interval_ns{};
std::uint64_t display_frame_interval_jitter_ns{};
std::uint64_t raw_display_interval_current_ns{};
std::uint64_t raw_display_interval_srtt_ns{};
std::uint64_t raw_display_interval_jitter_ns{};
std::uint64_t accepted_consumer_interval_current_ns{};
std::uint64_t accepted_consumer_interval_srtt_ns{};
std::uint64_t accepted_consumer_interval_jitter_ns{};
std::uint64_t frame_age_srtt_ns{};
std::uint64_t frame_age_jitter_ns{};
std::uint64_t user_period_ns{};
std::uint64_t target_period_ns{};
std::uint64_t effective_min_render_interval_ns{};
std::uint64_t next_render_time_ns{};
std::uint64_t admission_wait_elapsed_ns{};
std::uint64_t admission_wait_remaining_ns{};
std::uint64_t executor_queue_wait_ns{};
std::uint64_t present_wait_ns{};
std::uint64_t consumer_sample_accepted_count{};
std::uint64_t consumer_sample_rejected_no_backlog_count{};
std::uint64_t consumer_sample_rejected_starved_count{};
std::uint64_t consumer_sample_rejected_no_new_frame_count{};
std::uint64_t consumer_sample_rejected_invalid_timestamp_count{};
std::uint64_t consumer_sample_total_count{};
double consumer_sample_accepted_ratio{};
std::uint64_t consumer_window_size{};
std::uint64_t consumer_window_accepted{};
std::uint64_t consumer_window_rejected_no_backlog{};
std::uint64_t consumer_window_rejected_starved{};
std::uint64_t consumer_window_rejected_no_new_frame{};
std::uint64_t consumer_window_rejected_invalid{};
double consumer_window_accepted_ratio{};
std::uint64_t producer_starvation_count{};
std::uint64_t producer_starvation_epoch_id{};
bool producer_starvation_active{};
std::uint64_t mode_enter_count{};
std::uint64_t mode_exit_count{};
std::uint64_t update_posted_count{};
std::uint64_t duplicate_present_request_suppressed_count{};
std::uint64_t update_ack_count{};
std::uint64_t update_repost_count{};
std::uint64_t paint_without_posted_update_count{};
std::uint64_t middle_published_count{};
std::uint64_t middle_superseded_count{};
std::uint64_t painting_advanced_count{};
std::uint64_t presented_frame_count{};
std::uint64_t superseded_frame_count{};
std::uint64_t repeated_frame_count{};
std::uint64_t underrun_count{};
double display_efficiency = 1.0;
};
inline std::uint32_t dirty_reason_bit(Dirty_Reason reason) {
return 1u << static_cast<std::uint8_t>(reason);
}
struct Renderable_Cache_Frame_Stats {
std::uint64_t node_id{};
std::uint64_t parent_node_id{};
std::string object_name;
std::string parent_object_name;
int tree_depth{};
std::uint64_t hit_count{};
std::uint64_t miss_count{};
std::uint64_t rebuild_count{};
std::uint64_t rebuild_time_ns{};
std::uint64_t compose_time_ns{};
std::uint64_t last_rebuild_time_ns{};
std::uint64_t last_compose_time_ns{};
std::uint64_t last_image_bytes{};
std::uint64_t last_image_area{};
std::uint64_t last_edit_version{};
std::uint64_t last_ready_version{};
};
struct Renderable_Frame_Stat {
std::uint64_t node_id{};
std::uint64_t parent_node_id{};
std::string object_name;
std::string parent_object_name;
int tree_depth{};
bool cache_enabled{};
std::uint64_t render_count{};
std::uint64_t self_draw_count{};
std::uint64_t total_render_time_ns{};
std::uint64_t self_draw_time_ns{};
std::uint64_t last_total_render_time_ns{};
std::uint64_t last_self_draw_time_ns{};
};
struct Frame_Lifecycle_Record {
std::uint64_t frame_id{};
std::uint64_t input_version{};
std::uint64_t core_data_time_ns{};
std::uint64_t render_request_ns{};
std::uint64_t render_role_enter_ns{};
std::uint64_t render_begin_ns{};
std::uint64_t prepare_begin_ns{};
std::uint64_t prepare_end_ns{};
std::uint64_t draw_begin_ns{};
std::uint64_t draw_end_ns{};
std::uint64_t render_end_ns{};
std::uint64_t transition_12_ns{};
std::uint64_t update_request_id{};
std::uint64_t update_request_time_ns{};
std::uint64_t update_posted_ns{};
std::uint64_t transition_23_ns{};
std::uint64_t paint_begin_ns{};
std::uint64_t paint_end_ns{};
std::uint64_t presented_frame_id{};
std::uint64_t transition_32_ns{};
std::uint64_t render_slot_idle_wait_ns{};
std::uint64_t executor_queue_wait_ns{};
std::uint64_t ready_queue_wait_ns{};
std::uint64_t present_queue_wait_ns{};
std::uint64_t paint_return_wait_ns{};
std::uint64_t superseded_time_ns{};
Frame_Outcome outcome = Frame_Outcome::Render_Acquire_Dropped;
Refresh_Control_Snapshot refresh;
Frame_Worker_Stats worker;
std::uint64_t raw_input_count{};
std::uint64_t prepared_output_count{};
std::uint64_t renderable_cache_hit_count{};
std::uint64_t renderable_cache_miss_count{};
std::uint64_t renderable_cache_rebuild_count{};
std::uint64_t renderable_cache_rebuild_time_ns{};
std::uint64_t renderable_cache_compose_time_ns{};
std::uint64_t renderable_cache_image_bytes{};
std::uint64_t renderable_cache_image_area{};
std::uint64_t pixel_width{};
std::uint64_t pixel_height{};
std::uint64_t viewport_version{};
std::uint32_t dirty_reason_mask{};
std::vector<Renderable_Frame_Stat> renderable_stats;
std::vector<Renderable_Cache_Frame_Stats> renderable_cache_stats;
void record_renderable_render(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth, Renderable_Cache_Mode cache_mode, std::uint64_t render_time_ns);
void record_renderable_self_draw(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth, Renderable_Cache_Mode cache_mode, std::uint64_t draw_time_ns);
void record_renderable_cache_hit(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth);
void record_renderable_cache_miss(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth);
void record_renderable_cache_rebuild(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth, std::uint64_t rebuild_time_ns, std::uint64_t image_bytes, std::uint64_t image_area, std::uint64_t edit_version, std::uint64_t ready_version);
void record_renderable_cache_compose(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth, std::uint64_t compose_time_ns, std::uint64_t image_bytes, std::uint64_t image_area, std::uint64_t edit_version, std::uint64_t ready_version);
private:
Renderable_Frame_Stat& renderable_stat(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth);
Renderable_Cache_Frame_Stats& cache_stat(std::uint64_t node_id, std::uint64_t parent_node_id, std::string_view object_name, std::string_view parent_object_name, int tree_depth);
};
struct Frame_Feedback_Event_Record {
std::string event;
Frame_Lifecycle_Record frame;
std::uint64_t timestamp_ns{};
Low_Latency_Production_Mode mode_before = Low_Latency_Production_Mode::Latency_Eager;
Low_Latency_Production_Mode mode_after = Low_Latency_Production_Mode::Latency_Eager;
std::uint64_t effective_interval_before_ns{};
std::uint64_t effective_interval_after_ns{};
bool dirty{};
bool render_active{};
bool middle_has_new_frame{};
bool paint_active{};
bool paint_update_posted{};
bool backlog_epoch_active{};
bool continuously_backlogged{};
bool producer_starved{};
std::uint64_t backlog_epoch_id{};
std::uint64_t backlog_rendered_frames{};
std::uint64_t backlog_superseded_frames{};
bool flush{};
};
inline std::uint64_t renderable_cache_subtree_compose_time(const std::vector<Renderable_Cache_Frame_Stats>& stats, const Renderable_Cache_Frame_Stats& node) {
std::uint64_t compose_time_ns = node.compose_time_ns;
for (const auto& stat : stats) {
if (stat.parent_node_id == node.node_id && stat.tree_depth == node.tree_depth + 1)
compose_time_ns += renderable_cache_subtree_compose_time(stats, stat);
}
return compose_time_ns;
}
} // namespace renderive