策略抽离
This commit is contained in:
@@ -1,37 +1,8 @@
|
||||
#include "Frame_Scheduler.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
namespace renderive {
|
||||
namespace {
|
||||
constexpr double Ratio_Threshold = 1.03;
|
||||
constexpr int Switch_Samples = 3;
|
||||
}
|
||||
|
||||
void Smoothed_Interval::update(double sample_ms) {
|
||||
if (sample_ms <= 0.0 || !std::isfinite(sample_ms))
|
||||
return;
|
||||
if (!sample_count) {
|
||||
srtt_ms = sample_ms;
|
||||
jitter_ms = sample_ms * 0.5;
|
||||
sample_count = 1;
|
||||
return;
|
||||
}
|
||||
double error = std::abs(sample_ms - srtt_ms);
|
||||
jitter_ms += 0.25 * (error - jitter_ms);
|
||||
srtt_ms += 0.125 * (sample_ms - srtt_ms);
|
||||
++sample_count;
|
||||
}
|
||||
|
||||
double Smoothed_Interval::safe_ms(double jitter_factor) const {
|
||||
return sample_count ? srtt_ms + jitter_factor * jitter_ms : 0.0;
|
||||
}
|
||||
|
||||
bool Smoothed_Interval::valid() const {
|
||||
return sample_count > 0;
|
||||
}
|
||||
|
||||
void Frame_Lifecycle_Record::record_renderable_render(const std::string& object_name, const std::string& parent_object_name, int tree_depth, Renderable_Cache_Mode cache_mode, std::uint64_t render_time_ns) {
|
||||
Renderable_Frame_Stat& stat = renderable_stat(object_name, parent_object_name, tree_depth);
|
||||
stat.cache_enabled = cache_mode == Renderable_Cache_Mode::Local_Pixel;
|
||||
@@ -110,169 +81,4 @@ Renderable_Cache_Frame_Stats& Frame_Lifecycle_Record::cache_stat(const std::stri
|
||||
return renderable_cache_stats.back();
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::reset() {
|
||||
std::uint64_t user_period = state_value.user_period_ns;
|
||||
*this = Frame_Feedback_Controller();
|
||||
state_value.user_period_ns = user_period;
|
||||
refresh_control_snapshot();
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::set_max_render_fps(double fps) {
|
||||
state_value.user_period_ns = fps > 0.0 ? ms_to_ns(1000.0 / fps) : 0;
|
||||
refresh_control_snapshot();
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::on_input_changed(std::uint64_t, std::uint64_t input_version) {
|
||||
if (input_version)
|
||||
latest_input_version = input_version;
|
||||
else
|
||||
++latest_input_version;
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::on_render_started(Frame_Lifecycle_Record& frame, std::uint64_t now_ns) {
|
||||
last_render_begin_ns = now_ns;
|
||||
frame.render_begin_ns = now_ns;
|
||||
frame.wait_21_ns = now_ns > frame.render_role_enter_ns ? now_ns - frame.render_role_enter_ns : 0;
|
||||
refresh_control_snapshot();
|
||||
write_state(frame);
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::on_render_completed(Frame_Lifecycle_Record& frame) {
|
||||
std::uint64_t render_duration_ns = frame.render_end_ns > frame.render_begin_ns ? frame.render_end_ns - frame.render_begin_ns : 0;
|
||||
last_render_begin_ns = frame.render_begin_ns;
|
||||
render_period.update(static_cast<double>(render_duration_ns + frame.wait_21_ns) / 1000000.0);
|
||||
refresh_control_snapshot();
|
||||
write_state(frame);
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::on_frame_presented(Frame_Lifecycle_Record& frame) {
|
||||
std::uint64_t paint_duration_ns = frame.paint_end_ns > frame.paint_begin_ns ? frame.paint_end_ns - frame.paint_begin_ns : 0;
|
||||
paint_period.update(static_cast<double>(paint_duration_ns + frame.wait_23_ns) / 1000000.0);
|
||||
frame.outcome = Frame_Outcome::Presented;
|
||||
refresh_control_snapshot();
|
||||
write_state(frame);
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::on_frame_superseded(Frame_Lifecycle_Record& frame) {
|
||||
frame.outcome = Frame_Outcome::Superseded;
|
||||
refresh_control_snapshot();
|
||||
write_state(frame);
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::on_frame_dropped(Frame_Lifecycle_Record& frame, Frame_Outcome outcome) {
|
||||
frame.outcome = outcome;
|
||||
refresh_control_snapshot();
|
||||
write_state(frame);
|
||||
}
|
||||
|
||||
bool Frame_Feedback_Controller::rate_limit_ready(std::uint64_t now_ns) const {
|
||||
return now_ns >= next_render_time;
|
||||
}
|
||||
|
||||
std::uint64_t Frame_Feedback_Controller::next_render_time_ns() const {
|
||||
return next_render_time;
|
||||
}
|
||||
|
||||
const Refresh_Control_Snapshot& Frame_Feedback_Controller::state() const {
|
||||
return state_value;
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::write_state(Frame_Lifecycle_Record& frame) const {
|
||||
frame.refresh = state_value;
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::refresh_control_snapshot() {
|
||||
std::uint64_t render_period_ns = render_period.valid() ? ms_to_ns(render_period.safe_ms(0.5)) : 0;
|
||||
std::uint64_t paint_period_ns = paint_period.valid() ? ms_to_ns(paint_period.safe_ms(0.5)) : 0;
|
||||
std::uint64_t user_period_ns = state_value.user_period_ns;
|
||||
Refresh_Limit_Source candidate = classify_limit_source(render_period_ns, paint_period_ns, user_period_ns);
|
||||
std::uint64_t candidate_period = 0;
|
||||
switch (candidate) {
|
||||
case Refresh_Limit_Source::Render:
|
||||
candidate_period = render_period_ns;
|
||||
break;
|
||||
case Refresh_Limit_Source::Paint:
|
||||
candidate_period = paint_period_ns;
|
||||
break;
|
||||
case Refresh_Limit_Source::User:
|
||||
candidate_period = user_period_ns;
|
||||
break;
|
||||
case Refresh_Limit_Source::Unknown:
|
||||
break;
|
||||
}
|
||||
update_limit_source(candidate, candidate_period);
|
||||
std::uint64_t target_period = std::max({render_period_ns, paint_period_ns, user_period_ns});
|
||||
state_value.render_period_ns = render_period_ns;
|
||||
state_value.paint_period_ns = paint_period_ns;
|
||||
state_value.target_period_ns = target_period;
|
||||
if (state_value.source == Refresh_Limit_Source::Unknown)
|
||||
state_value.source = candidate;
|
||||
if (state_value.source == Refresh_Limit_Source::User && last_render_begin_ns)
|
||||
next_render_time = last_render_begin_ns + user_period_ns;
|
||||
else
|
||||
next_render_time = 0;
|
||||
}
|
||||
|
||||
Refresh_Limit_Source Frame_Feedback_Controller::classify_limit_source(std::uint64_t render_period_ns, std::uint64_t paint_period_ns, std::uint64_t user_period_ns) const {
|
||||
if (!render_period_ns && !paint_period_ns)
|
||||
return user_period_ns ? Refresh_Limit_Source::User : Refresh_Limit_Source::Unknown;
|
||||
std::uint64_t max_period = std::max({render_period_ns, paint_period_ns, user_period_ns});
|
||||
if (max_period == user_period_ns && user_period_ns)
|
||||
return Refresh_Limit_Source::User;
|
||||
if (max_period == paint_period_ns && paint_period_ns)
|
||||
return Refresh_Limit_Source::Paint;
|
||||
if (max_period == render_period_ns && render_period_ns)
|
||||
return Refresh_Limit_Source::Render;
|
||||
return Refresh_Limit_Source::Unknown;
|
||||
}
|
||||
|
||||
void Frame_Feedback_Controller::update_limit_source(Refresh_Limit_Source candidate, std::uint64_t candidate_period_ns) {
|
||||
if (candidate == Refresh_Limit_Source::Unknown)
|
||||
return;
|
||||
if (state_value.source == Refresh_Limit_Source::Unknown) {
|
||||
state_value.source = candidate;
|
||||
candidate_source = candidate;
|
||||
candidate_count = 0;
|
||||
return;
|
||||
}
|
||||
std::uint64_t current_period = 0;
|
||||
switch (state_value.source) {
|
||||
case Refresh_Limit_Source::Render:
|
||||
current_period = state_value.render_period_ns;
|
||||
break;
|
||||
case Refresh_Limit_Source::Paint:
|
||||
current_period = state_value.paint_period_ns;
|
||||
break;
|
||||
case Refresh_Limit_Source::User:
|
||||
current_period = state_value.user_period_ns;
|
||||
break;
|
||||
case Refresh_Limit_Source::Unknown:
|
||||
break;
|
||||
}
|
||||
if (candidate == state_value.source || (current_period && static_cast<double>(candidate_period_ns) <= static_cast<double>(current_period) * Ratio_Threshold)) {
|
||||
candidate_source = candidate;
|
||||
candidate_count = 0;
|
||||
return;
|
||||
}
|
||||
if (candidate != candidate_source) {
|
||||
candidate_source = candidate;
|
||||
candidate_count = 1;
|
||||
return;
|
||||
}
|
||||
if (++candidate_count >= Switch_Samples) {
|
||||
state_value.source = candidate;
|
||||
candidate_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double Frame_Feedback_Controller::duration_ms(std::uint64_t begin_ns, std::uint64_t end_ns) {
|
||||
return end_ns > begin_ns ? static_cast<double>(end_ns - begin_ns) / 1000000.0 : 0.0;
|
||||
}
|
||||
|
||||
std::uint64_t Frame_Feedback_Controller::ms_to_ns(double ms) {
|
||||
if (ms <= 0.0 || !std::isfinite(ms))
|
||||
return 0;
|
||||
return static_cast<std::uint64_t>(ms * 1000000.0);
|
||||
}
|
||||
|
||||
} // namespace renderive
|
||||
|
||||
Reference in New Issue
Block a user