#include "Latency_Eager_Refresh_Strategy.h" #include "../architecture/Render_Time.h" namespace renderive { struct Latency_Eager_Refresh_Strategy::Private { std::atomic max_render_fps{60.0}; Frame_Feedback_Controller feedback; }; static constexpr double k_default_max_fps = 60.0; Latency_Eager_Refresh_Strategy::Latency_Eager_Refresh_Strategy() : d(std::make_unique()) {} Latency_Eager_Refresh_Strategy::~Latency_Eager_Refresh_Strategy() = default; double Latency_Eager_Refresh_Strategy::max_render_fps() const { return d->max_render_fps.load(std::memory_order_acquire); } void Latency_Eager_Refresh_Strategy::set_max_render_fps(double fps) { if (fps <= 0.0) fps = k_default_max_fps; d->max_render_fps.store(fps, std::memory_order_release); } Refresh_Control_Snapshot Latency_Eager_Refresh_Strategy::feedback_state() const { return d->feedback.state(); } Refresh_Action Latency_Eager_Refresh_Strategy::on_trigger( Refresh_Trigger trigger, const Refresh_Runtime_Snapshot& runtime, const Frame_Lifecycle_Record* frame) { d->feedback.set_max_render_fps(max_render_fps()); if (trigger == Refresh_Trigger::Started) d->feedback.reset(); if (trigger == Refresh_Trigger::Input_Dirty) d->feedback.on_input_changed(runtime.now_ns); if (frame) { switch (trigger) { case Refresh_Trigger::Render_Finished: d->feedback.on_render_completed(const_cast(*frame)); break; case Refresh_Trigger::Frame_Returned: if (frame->outcome == Frame_Outcome::Superseded) d->feedback.on_frame_superseded(const_cast(*frame)); else d->feedback.on_frame_presented(const_cast(*frame)); break; default: break; } } Refresh_Action action; if (!runtime.enabled || runtime.destroying || trigger == Refresh_Trigger::Paused) return action; if (runtime.middle_has_new_frame && !runtime.paint_active) action.request_paint = true; if (!runtime.dirty || runtime.render_job_active) return action; Refresh_Control_Snapshot control = d->feedback.state(); switch (control.source) { case Refresh_Limit_Source::Paint: if (!runtime.middle_has_new_frame) action.try_render = true; break; case Refresh_Limit_Source::User: { std::uint64_t next_ns = d->feedback.next_render_time_ns(); if (next_ns && !d->feedback.rate_limit_ready(runtime.now_ns)) action.render_deadline_ns = next_ns; else action.try_render = true; break; } case Refresh_Limit_Source::Render: case Refresh_Limit_Source::Unknown: action.try_render = true; break; } return action; } } // namespace renderive