架构微调

This commit is contained in:
2026-08-11 09:24:12 +08:00
parent 14a6e97b64
commit 462baeca76
14 changed files with 179 additions and 110 deletions
@@ -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 {
@@ -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;
@@ -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
});