架构微调
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
struct Frame_Consumer_Feedback {
|
||||
std::uint64_t minimum_frame_interval_ns{};
|
||||
};
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "renderive/base/Concepts.hpp"
|
||||
#include "renderive/base/observer/Observer.hpp"
|
||||
#include "renderive/frame_control/base/Frame_Control_Strategy_Base.hpp"
|
||||
#include "renderive/frame_control/Frame_Consumer_Feedback.hpp"
|
||||
#include "renderive/real_time_data/Observation.hpp"
|
||||
template <class Scene_Frame, Mutex_Type Mutex = std::mutex, class Observer = Observer_State<>>
|
||||
class Low_Latency_Strategy : public Frame_Control_Strategy_Base {
|
||||
@@ -22,7 +23,8 @@ public:
|
||||
enum class Limit_State {
|
||||
frequency_limited,
|
||||
paint_limited,
|
||||
render_limited
|
||||
render_limited,
|
||||
consumer_limited
|
||||
};
|
||||
struct Configuration {
|
||||
double frequency_hz{60.0};
|
||||
@@ -70,6 +72,7 @@ public:
|
||||
std::uint64_t paint_duration_ns{};
|
||||
std::uint64_t render_duration_ns{};
|
||||
std::uint64_t bottleneck_duration_ns{};
|
||||
std::uint64_t consumer_interval_ns{};
|
||||
std::uint64_t end_to_end_ns{};
|
||||
std::uint64_t next_refresh_interval_ns{};
|
||||
std::uint64_t completed_lifecycle_count{};
|
||||
@@ -142,6 +145,7 @@ public:
|
||||
Painter_Lease acquire_painter();
|
||||
Render_Lease acquire_renderer();
|
||||
void set_frequency_hz(double frequency_hz);
|
||||
void set_consumer_feedback(Frame_Consumer_Feedback feedback);
|
||||
void swap() override;
|
||||
double frequency_hz() const noexcept override;
|
||||
std::uint64_t next_refresh_interval_ns() const noexcept override;
|
||||
@@ -155,6 +159,7 @@ public:
|
||||
private:
|
||||
static double checked_frequency_hz(double frequency_hz);
|
||||
std::uint64_t now_ns() const noexcept;
|
||||
void update_refresh_control();
|
||||
void update_state(const Frame& frame);
|
||||
void observe(const Observation& observation) noexcept;
|
||||
bool discard_pending_frame_locked(Observation& observation);
|
||||
|
||||
@@ -207,7 +207,7 @@ Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::Low_Latency_Strategy(Observe
|
||||
: Frame_Control_Strategy_Base(checked_frequency_hz(configuration.frequency_hz), frequency_interval_ns(configuration.frequency_hz)), observer_(std::move(observer)), paint_(&frames_[0]), cache_(&frames_[1]), render_(&frames_[2]) {
|
||||
state_.frequency_hz = configuration.frequency_hz;
|
||||
state_.target_interval_ns = frequency_interval_ns(configuration.frequency_hz);
|
||||
state_.next_refresh_interval_ns = state_.target_interval_ns;
|
||||
update_refresh_control();
|
||||
}
|
||||
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
|
||||
auto Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::acquire_painter() -> Painter_Lease {
|
||||
@@ -223,9 +223,13 @@ void Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::set_frequency_hz(double
|
||||
std::lock_guard<Mutex> lock(state_mutex_);
|
||||
state_.frequency_hz = frequency_hz;
|
||||
state_.target_interval_ns = frequency_interval_ns(frequency_hz);
|
||||
state_.next_refresh_interval_ns = std::max(state_.target_interval_ns,
|
||||
state_.bottleneck_duration_ns);
|
||||
update_frame_control_state(state_.frequency_hz, state_.next_refresh_interval_ns);
|
||||
update_refresh_control();
|
||||
}
|
||||
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
|
||||
void Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::set_consumer_feedback(Frame_Consumer_Feedback feedback) {
|
||||
std::lock_guard<Mutex> lock(state_mutex_);
|
||||
state_.consumer_interval_ns = feedback.minimum_frame_interval_ns;
|
||||
update_refresh_control();
|
||||
}
|
||||
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
|
||||
void Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::swap() {
|
||||
@@ -323,23 +327,33 @@ std::uint64_t Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::now_ns() const
|
||||
return observer_.now_ns();
|
||||
}
|
||||
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
|
||||
void Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::update_state(const Frame& frame) {
|
||||
state_.paint_duration_ns = frame.statistics.timing.paint_duration_ns;
|
||||
state_.render_duration_ns = frame.statistics.timing.render_duration_ns;
|
||||
state_.bottleneck_duration_ns = std::max(state_.paint_duration_ns, state_.render_duration_ns);
|
||||
state_.end_to_end_ns = frame.statistics.timing.end_to_end_ns;
|
||||
state_.next_refresh_interval_ns = std::max(state_.target_interval_ns, state_.bottleneck_duration_ns);
|
||||
if (state_.target_interval_ns != 0 && state_.bottleneck_duration_ns <= state_.target_interval_ns) {
|
||||
void Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::update_refresh_control() {
|
||||
state_.next_refresh_interval_ns = std::max({state_.target_interval_ns,
|
||||
state_.bottleneck_duration_ns,
|
||||
state_.consumer_interval_ns});
|
||||
if (state_.consumer_interval_ns > state_.target_interval_ns &&
|
||||
state_.consumer_interval_ns > state_.bottleneck_duration_ns) {
|
||||
state_.limit_state = Limit_State::consumer_limited;
|
||||
} else if (state_.target_interval_ns != 0 &&
|
||||
state_.bottleneck_duration_ns <= state_.target_interval_ns) {
|
||||
state_.limit_state = Limit_State::frequency_limited;
|
||||
} else if (state_.paint_duration_ns >= state_.render_duration_ns) {
|
||||
state_.limit_state = Limit_State::paint_limited;
|
||||
} else {
|
||||
state_.limit_state = Limit_State::render_limited;
|
||||
}
|
||||
update_frame_control_state(state_.frequency_hz, state_.next_refresh_interval_ns);
|
||||
}
|
||||
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
|
||||
void Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::update_state(const Frame& frame) {
|
||||
state_.paint_duration_ns = frame.statistics.timing.paint_duration_ns;
|
||||
state_.render_duration_ns = frame.statistics.timing.render_duration_ns;
|
||||
state_.bottleneck_duration_ns = std::max(state_.paint_duration_ns, state_.render_duration_ns);
|
||||
state_.end_to_end_ns = frame.statistics.timing.end_to_end_ns;
|
||||
update_refresh_control();
|
||||
++state_.completed_lifecycle_count;
|
||||
state_.frame_sequence = frame.statistics.sequence;
|
||||
state_.completed_frame_real_time_data_update_sequence = frame.statistics.real_time_data_update_sequence;
|
||||
update_frame_control_state(state_.frequency_hz, state_.next_refresh_interval_ns);
|
||||
}
|
||||
template <class Scene_Frame, Mutex_Type Mutex, class Observer>
|
||||
void Low_Latency_Strategy<Scene_Frame, Mutex, Observer>::observe(const Observation& observation) noexcept {
|
||||
|
||||
+19
@@ -61,6 +61,25 @@ TEST(low_latency_pipeline_test, classifies_frequency_paint_and_render_limits_acr
|
||||
EXPECT_EQ(state.frame_sequence, 3u);
|
||||
}
|
||||
|
||||
TEST(low_latency_pipeline_test, consumer_feedback_limits_refresh_without_knowing_the_consumer_type) {
|
||||
Low_Latency_Test_Time_Source time_source;
|
||||
Low_Latency_Test_Observer observer;
|
||||
auto strategy = make_low_latency_test_strategy(time_source, observer);
|
||||
strategy.set_frequency_hz(100.0);
|
||||
strategy.set_consumer_feedback({40'000'000});
|
||||
complete_pipeline(strategy, time_source, 1, 2'000'000, 0, 3'000'000);
|
||||
auto state = strategy.state();
|
||||
EXPECT_EQ(state.limit_state, Low_Latency_Test_Strategy::Limit_State::consumer_limited);
|
||||
EXPECT_EQ(state.target_interval_ns, 10'000'000u);
|
||||
EXPECT_EQ(state.consumer_interval_ns, 40'000'000u);
|
||||
EXPECT_EQ(state.next_refresh_interval_ns, 40'000'000u);
|
||||
strategy.set_consumer_feedback({});
|
||||
state = strategy.state();
|
||||
EXPECT_EQ(state.limit_state, Low_Latency_Test_Strategy::Limit_State::frequency_limited);
|
||||
EXPECT_EQ(state.consumer_interval_ns, 0u);
|
||||
EXPECT_EQ(state.next_refresh_interval_ns, 10'000'000u);
|
||||
}
|
||||
|
||||
TEST(low_latency_pipeline_test, applies_frequency_and_equal_bottleneck_boundaries_deterministically) {
|
||||
Low_Latency_Test_Time_Source time_source;
|
||||
Low_Latency_Test_Observer observer;
|
||||
|
||||
+2
@@ -40,6 +40,7 @@ struct Low_Latency_Recorded_Observation {
|
||||
int limit_state{};
|
||||
std::uint64_t target_interval_ns{};
|
||||
std::uint64_t bottleneck_duration_ns{};
|
||||
std::uint64_t consumer_interval_ns{};
|
||||
std::uint64_t next_refresh_interval_ns{};
|
||||
std::uint64_t completed_lifecycle_count{};
|
||||
};
|
||||
@@ -74,6 +75,7 @@ struct Low_Latency_Test_Observer {
|
||||
static_cast<int>(observation.state.limit_state),
|
||||
observation.state.target_interval_ns,
|
||||
observation.state.bottleneck_duration_ns,
|
||||
observation.state.consumer_interval_ns,
|
||||
observation.state.next_refresh_interval_ns,
|
||||
observation.state.completed_lifecycle_count
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user