91 lines
2.9 KiB
C++
91 lines
2.9 KiB
C++
#include "Latency_Eager_Refresh_Strategy.h"
|
|
#include "../architecture/Render_Time.h"
|
|
|
|
namespace renderive {
|
|
|
|
struct Latency_Eager_Refresh_Strategy::Private {
|
|
std::atomic<double> 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<Private>()) {}
|
|
|
|
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_Lifecycle_Record&>(*frame));
|
|
break;
|
|
case Refresh_Trigger::Frame_Returned:
|
|
if (frame->outcome == Frame_Outcome::Superseded)
|
|
d->feedback.on_frame_superseded(const_cast<Frame_Lifecycle_Record&>(*frame));
|
|
else
|
|
d->feedback.on_frame_presented(const_cast<Frame_Lifecycle_Record&>(*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
|