[scenic] Allow setting frame time lower bound on scheduler via config
This CL allows us to specify a lower bound for frame time predictions
made in WindowedFramePredictor. This can be set via
/config/data/frame_scheduler_min_frame_time_in_us. Default is kept as
0 so that there is no change in current behavior.
Bug: 24710, 24606
Change-Id: I4cc274a63c30c7def851f3ab6aa05c7e027740c0
diff --git a/src/ui/scenic/bin/app.cc b/src/ui/scenic/bin/app.cc
index 58b8b6e..24dd95f 100644
--- a/src/ui/scenic/bin/app.cc
+++ b/src/ui/scenic/bin/app.cc
@@ -18,6 +18,7 @@
#endif
#include "src/lib/cobalt/cpp/cobalt_logger.h"
+#include "src/lib/files/file.h"
#include "src/ui/scenic/lib/gfx/api/internal_snapshot_impl.h"
#include "src/ui/scenic/lib/scheduling/default_frame_scheduler.h"
#include "src/ui/scenic/lib/scheduling/frame_metrics_registry.cb.h"
@@ -47,6 +48,23 @@
return nullptr;
};
};
+
+zx::duration GetMinimumPredictedFrameDuration() {
+ std::string frame_scheduler_min_predicted_frame_duration;
+ int frame_scheduler_min_predicted_frame_duration_in_us = 0;
+ if (files::ReadFileToString("/config/data/frame_scheduler_min_predicted_frame_duration_in_us",
+ &frame_scheduler_min_predicted_frame_duration)) {
+ frame_scheduler_min_predicted_frame_duration_in_us =
+ atoi(frame_scheduler_min_predicted_frame_duration.c_str());
+ FXL_DCHECK(frame_scheduler_min_predicted_frame_duration_in_us >= 0);
+ FXL_LOG(INFO) << "min_predicted_frame_duration(us): "
+ << frame_scheduler_min_predicted_frame_duration_in_us;
+ }
+ return frame_scheduler_min_predicted_frame_duration_in_us > 0
+ ? zx::usec(frame_scheduler_min_predicted_frame_duration_in_us)
+ : scheduling::DefaultFrameScheduler::kMinPredictedFrameDuration;
+}
+
} // namespace
namespace scenic_impl {
@@ -147,9 +165,11 @@
if (cobalt_logger == nullptr) {
FX_LOGS(ERROR) << "CobaltLogger creation failed!";
}
+
frame_scheduler_ = std::make_shared<scheduling::DefaultFrameScheduler>(
display->vsync_timing(),
std::make_unique<scheduling::WindowedFramePredictor>(
+ GetMinimumPredictedFrameDuration(),
scheduling::DefaultFrameScheduler::kInitialRenderDuration,
scheduling::DefaultFrameScheduler::kInitialUpdateDuration),
scenic_.inspect_node()->CreateChild("FrameScheduler"), std::move(cobalt_logger));
diff --git a/src/ui/scenic/bin/meta/scenic.cmx b/src/ui/scenic/bin/meta/scenic.cmx
index b301e71..ae3cea3 100644
--- a/src/ui/scenic/bin/meta/scenic.cmx
+++ b/src/ui/scenic/bin/meta/scenic.cmx
@@ -7,6 +7,7 @@
"class/display-controller"
],
"features": [
+ "config-data",
"vulkan",
"isolated-temp"
],
diff --git a/src/ui/scenic/lib/gfx/tests/gfx_test.cc b/src/ui/scenic/lib/gfx/tests/gfx_test.cc
index 3e1f502..8201d0b 100644
--- a/src/ui/scenic/lib/gfx/tests/gfx_test.cc
+++ b/src/ui/scenic/lib/gfx/tests/gfx_test.cc
@@ -26,6 +26,7 @@
frame_scheduler_ = std::make_shared<scheduling::DefaultFrameScheduler>(
std::make_shared<scheduling::VsyncTiming>(),
std::make_unique<scheduling::WindowedFramePredictor>(
+ scheduling::DefaultFrameScheduler::kMinPredictedFrameDuration,
scheduling::DefaultFrameScheduler::kInitialRenderDuration,
scheduling::DefaultFrameScheduler::kInitialUpdateDuration));
engine_ = std::make_unique<Engine>(context_provider_.context(), frame_scheduler_,
diff --git a/src/ui/scenic/lib/scheduling/default_frame_scheduler.h b/src/ui/scenic/lib/scheduling/default_frame_scheduler.h
index 399c342..bb05773 100644
--- a/src/ui/scenic/lib/scheduling/default_frame_scheduler.h
+++ b/src/ui/scenic/lib/scheduling/default_frame_scheduler.h
@@ -69,6 +69,7 @@
void ClearCallbacksForSession(SessionId session_id) override;
+ constexpr static zx::duration kMinPredictedFrameDuration = zx::msec(0);
constexpr static zx::duration kInitialRenderDuration = zx::msec(5);
constexpr static zx::duration kInitialUpdateDuration = zx::msec(1);
diff --git a/src/ui/scenic/lib/scheduling/tests/frame_predictor_unittest.cc b/src/ui/scenic/lib/scheduling/tests/frame_predictor_unittest.cc
index 72281c4..657b1c8 100644
--- a/src/ui/scenic/lib/scheduling/tests/frame_predictor_unittest.cc
+++ b/src/ui/scenic/lib/scheduling/tests/frame_predictor_unittest.cc
@@ -24,14 +24,13 @@
protected:
// | ::testing::Test |
void SetUp() override {
- predictor_ = std::make_unique<WindowedFramePredictor>(kInitialRenderTimePrediction,
- kInitialUpdateTimePrediction);
+ predictor_ = std::make_unique<WindowedFramePredictor>(
+ kMinPredictedFrameDuration, kInitialRenderTimePrediction, kInitialUpdateTimePrediction);
}
// | ::testing::Test |
- void TearDown() override {
- predictor_.reset();
- }
+ void TearDown() override { predictor_.reset(); }
+ static constexpr zx::duration kMinPredictedFrameDuration = zx::msec(0);
static constexpr zx::duration kInitialRenderTimePrediction = zx::msec(4);
static constexpr zx::duration kInitialUpdateTimePrediction = zx::msec(2);
@@ -257,6 +256,63 @@
EXPECT_LE(prediction.latch_point_time.get(), now.get() + vsync_interval.get());
}
+TEST(WindowedFramePredictorMinFrameDurationTest, BasicPredictions_ShouldRespectMinFrameTime) {
+ zx::duration kMinPredictedFrameDuration = zx::msec(14);
+ zx::duration kInitialRenderTimePrediction = zx::msec(2);
+ zx::duration kInitialUpdateTimePrediction = zx::msec(2);
+ auto predictor = std::make_unique<WindowedFramePredictor>(
+ kMinPredictedFrameDuration, kInitialRenderTimePrediction, kInitialUpdateTimePrediction);
+
+ PredictionRequest request = {.now = ms_to_time(1),
+ .requested_presentation_time = ms_to_time(16),
+ .last_vsync_time = ms_to_time(0),
+ .vsync_interval = zx::msec(16)};
+
+ auto prediction = predictor->GetPrediction(request);
+ EXPECT_EQ(prediction.presentation_time - prediction.latch_point_time, kMinPredictedFrameDuration);
+}
+
+TEST(WindowedFramePredictorMinFrameDurationTest, BasicPredictions_CanPassMinFrameTime) {
+ zx::duration kMinPredictedFrameDuration = zx::msec(5);
+ zx::duration kInitialRenderTimePrediction = zx::msec(3);
+ zx::duration kInitialUpdateTimePrediction = zx::msec(3);
+ auto predictor = std::make_unique<WindowedFramePredictor>(
+ kMinPredictedFrameDuration, kInitialRenderTimePrediction, kInitialUpdateTimePrediction);
+
+ PredictionRequest request = {.now = ms_to_time(1),
+ .requested_presentation_time = ms_to_time(16),
+ .last_vsync_time = ms_to_time(0),
+ .vsync_interval = zx::msec(16)};
+
+ auto prediction = predictor->GetPrediction(request);
+ EXPECT_GT(prediction.presentation_time - prediction.latch_point_time, kMinPredictedFrameDuration);
+}
+
+TEST(WindowedFramePredictorMinFrameDurationTest,
+ PredictionsAfterUpdating_ShouldRespectMinFrameTime) {
+ zx::duration kMinPredictedFrameDuration = zx::msec(13);
+ zx::duration kInitialRenderTimePrediction = zx::msec(2);
+ zx::duration kInitialUpdateTimePrediction = zx::msec(2);
+ auto predictor = std::make_unique<WindowedFramePredictor>(
+ kMinPredictedFrameDuration, kInitialRenderTimePrediction, kInitialUpdateTimePrediction);
+
+ const zx::duration update_duration = zx::msec(3);
+ const zx::duration render_duration = zx::msec(3);
+ const size_t kBiggerThanAllPredictionWindows = 5;
+ for (size_t i = 0; i < kBiggerThanAllPredictionWindows; ++i) {
+ predictor->ReportRenderDuration(render_duration);
+ predictor->ReportUpdateDuration(update_duration);
+ }
+
+ PredictionRequest request = {.now = ms_to_time(1),
+ .requested_presentation_time = ms_to_time(16),
+ .last_vsync_time = ms_to_time(0),
+ .vsync_interval = zx::msec(16)};
+
+ auto prediction = predictor->GetPrediction(request);
+ EXPECT_EQ(prediction.presentation_time - prediction.latch_point_time, kMinPredictedFrameDuration);
+}
+
// ---------------------------------------------------------------------------
// ConstantFramePredictor tests
// ---------------------------------------------------------------------------
diff --git a/src/ui/scenic/lib/scheduling/tests/frame_scheduler_test.cc b/src/ui/scenic/lib/scheduling/tests/frame_scheduler_test.cc
index ca9ef83..8fa3551 100644
--- a/src/ui/scenic/lib/scheduling/tests/frame_scheduler_test.cc
+++ b/src/ui/scenic/lib/scheduling/tests/frame_scheduler_test.cc
@@ -28,7 +28,8 @@
std::unique_ptr<DefaultFrameScheduler> FrameSchedulerTest::CreateDefaultFrameScheduler() {
auto scheduler = std::make_unique<DefaultFrameScheduler>(
vsync_timing_,
- std::make_unique<WindowedFramePredictor>(DefaultFrameScheduler::kInitialRenderDuration,
+ std::make_unique<WindowedFramePredictor>(DefaultFrameScheduler::kMinPredictedFrameDuration,
+ DefaultFrameScheduler::kInitialRenderDuration,
DefaultFrameScheduler::kInitialUpdateDuration));
scheduler->SetFrameRenderer(mock_renderer_->GetWeakPtr());
scheduler->AddSessionUpdater(mock_updater_->GetWeakPtr());
diff --git a/src/ui/scenic/lib/scheduling/windowed_frame_predictor.cc b/src/ui/scenic/lib/scheduling/windowed_frame_predictor.cc
index 33c221a..34ec286 100644
--- a/src/ui/scenic/lib/scheduling/windowed_frame_predictor.cc
+++ b/src/ui/scenic/lib/scheduling/windowed_frame_predictor.cc
@@ -10,9 +10,11 @@
namespace scheduling {
-WindowedFramePredictor::WindowedFramePredictor(zx::duration initial_render_duration_prediction,
+WindowedFramePredictor::WindowedFramePredictor(zx::duration min_predicted_frame_duration,
+ zx::duration initial_render_duration_prediction,
zx::duration initial_update_duration_prediction)
- : render_duration_predictor_(kRenderPredictionWindowSize, initial_render_duration_prediction),
+ : min_predicted_frame_duration_(min_predicted_frame_duration),
+ render_duration_predictor_(kRenderPredictionWindowSize, initial_render_duration_prediction),
update_duration_predictor_(kUpdatePredictionWindowSize, initial_update_duration_prediction) {}
WindowedFramePredictor::~WindowedFramePredictor() {}
@@ -31,8 +33,10 @@
const zx::duration predicted_time_to_update = update_duration_predictor_.GetPrediction();
const zx::duration predicted_time_to_render = render_duration_predictor_.GetPrediction();
- const zx::duration predicted_frame_duration = std::min(
- kMaxFrameTime, predicted_time_to_update + predicted_time_to_render + kHardcodedMargin);
+ const zx::duration predicted_frame_duration =
+ std::max(min_predicted_frame_duration_,
+ std::min(kMaxPredictedFrameDuration,
+ predicted_time_to_update + predicted_time_to_render + kHardcodedMargin));
// Pretty print the times in milliseconds.
TRACE_INSTANT("gfx", "WindowedFramePredictor::GetPrediction", TRACE_SCOPE_PROCESS,
diff --git a/src/ui/scenic/lib/scheduling/windowed_frame_predictor.h b/src/ui/scenic/lib/scheduling/windowed_frame_predictor.h
index 85453cb..7c19005 100644
--- a/src/ui/scenic/lib/scheduling/windowed_frame_predictor.h
+++ b/src/ui/scenic/lib/scheduling/windowed_frame_predictor.h
@@ -13,7 +13,8 @@
class WindowedFramePredictor : public FramePredictor {
public:
- WindowedFramePredictor(zx::duration initial_render_duration_prediction,
+ WindowedFramePredictor(zx::duration min_predicted_frame_duration,
+ zx::duration initial_render_duration_prediction,
zx::duration initial_update_duration_prediction);
~WindowedFramePredictor();
@@ -39,7 +40,11 @@
// Rarely, it is possible for abnormally long GPU contexts to occur, and
// when they occur we do not want them to mess up future predictions by
// too much. We therefore clamp RenderDurations by this much.
- const zx::duration kMaxFrameTime = zx::usec(16'667); // 16.667ms
+ const zx::duration kMaxPredictedFrameDuration = zx::usec(16'667); // 16.667ms
+
+ // Lower bound for frame time prediction. It is useful when we want to set a fixed offset for
+ // certain cases. It can be set specifically for the board via config.
+ const zx::duration min_predicted_frame_duration_;
// Render time prediction.
const size_t kRenderPredictionWindowSize = 3;