blob: 9ab31aa81a22f4adb508594875b2cc91dc5363f8 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/prediction/linear_resampling.h"
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/prediction/input_predictor_unittest_helpers.h"
#include "ui/base/ui_base_features.h"
namespace ui {
namespace test {
class LinearResamplingTest : public InputPredictorTest {
public:
explicit LinearResamplingTest() {}
void SetUp() override { predictor_ = std::make_unique<LinearResampling>(); }
void ValidatePredictorFrameBased(
const std::vector<double>& events_x,
const std::vector<double>& events_y,
const std::vector<double>& events_time_ms,
const std::vector<double>& prediction_time_ms,
const std::vector<double>& predicted_x,
const std::vector<double>& predicted_y,
const double vsync_frequency) {
// LinearResampling* predictor =
// dynamic_cast<LinearResampling*>(predictor_.get());
base::TimeDelta frame_interval =
base::TimeDelta::FromSecondsD(1.0f / vsync_frequency);
predictor_->Reset();
std::vector<double> computed_x;
std::vector<double> computed_y;
size_t current_prediction_index = 0;
for (size_t i = 0; i < events_time_ms.size(); i++) {
InputPredictor::InputData data = {gfx::PointF(events_x[i], events_y[i]),
FromMilliseconds(events_time_ms[i])};
predictor_->Update(data);
if (predictor_->HasPrediction()) {
auto result = predictor_->GeneratePrediction(
FromMilliseconds(prediction_time_ms[current_prediction_index]),
frame_interval);
EXPECT_TRUE(result);
computed_x.push_back(result->pos.x());
computed_y.push_back(result->pos.y());
EXPECT_GT(result->time_stamp, base::TimeTicks());
current_prediction_index++;
}
}
EXPECT_TRUE(computed_x.size() == predicted_x.size());
if (computed_x.size() == predicted_x.size()) {
for (size_t i = 0; i < predicted_x.size(); i++) {
EXPECT_NEAR(computed_x[i], predicted_x[i], kEpsilon);
EXPECT_NEAR(computed_y[i], predicted_y[i], kEpsilon);
}
}
}
base::test::ScopedFeatureList feature_list;
DISALLOW_COPY_AND_ASSIGN(LinearResamplingTest);
};
// Test if the output name of the predictor is taking account of the
// equation order
TEST_F(LinearResamplingTest, GetName) {
EXPECT_EQ(predictor_->GetName(), features::kPredictorNameLinearResampling);
}
// Test that the number of events required to compute a prediction is correct
TEST_F(LinearResamplingTest, ShouldHavePrediction) {
LinearResampling predictor;
EXPECT_FALSE(predictor.HasPrediction());
// 1st event.
predictor.Update(
InputPredictor::InputData({gfx::PointF(0, 0), FromMilliseconds(0)}));
EXPECT_FALSE(predictor.HasPrediction());
// 2nd event.
predictor.Update(
InputPredictor::InputData({gfx::PointF(0, 0), FromMilliseconds(8)}));
EXPECT_TRUE(predictor.HasPrediction());
predictor.Reset();
EXPECT_FALSE(predictor.HasPrediction());
}
TEST_F(LinearResamplingTest, ResampleMinDelta) {
EXPECT_FALSE(predictor_->HasPrediction());
predictor_->Update(
InputPredictor::InputData({gfx::PointF(0, 0), FromMilliseconds(0)}));
predictor_->Update(
InputPredictor::InputData({gfx::PointF(0, 0), FromMilliseconds(1)}));
// No prediction when last_dt < kResampleMinDelta.
EXPECT_FALSE(predictor_->HasPrediction());
// Has prediction when last_dt >= kResampleMinDelta.
predictor_->Update(
InputPredictor::InputData({gfx::PointF(0, 0), FromMilliseconds(3)}));
EXPECT_TRUE(predictor_->HasPrediction());
predictor_->Update(
InputPredictor::InputData({gfx::PointF(0, 0), FromMilliseconds(15)}));
EXPECT_TRUE(predictor_->HasPrediction());
// Predictor is reset when dt > kMaxTimeDelta.
predictor_->Update(
InputPredictor::InputData({gfx::PointF(0, 0), FromMilliseconds(36)}));
EXPECT_FALSE(predictor_->HasPrediction());
}
TEST_F(LinearResamplingTest, ResamplingValue) {
std::vector<double> x = {10, 20, 30};
std::vector<double> y = {5, 25, 35};
std::vector<double> t = {15, 24, 32};
// Resample at frame_time = 33 ms, sample_time = 33-5 = 28ms.
// Resample at frame_time = 41 ms, sample_time = 41-5 = 36ms.
std::vector<double> pred_ts = {33, 41};
std::vector<double> pred_x = {24.44, 35};
std::vector<double> pred_y = {33.89, 40};
ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y);
}
TEST_F(LinearResamplingTest, ResamplingMaxPrediction) {
std::vector<double> x = {10, 20};
std::vector<double> y = {5, 10};
std::vector<double> t = {10, 30};
// Resample at frame_time = 45 ms, with max_prediction =
// kResampleMaxPrediction, sample_time = 30 + 8ms = 38ms.
std::vector<double> pred_ts = {45};
std::vector<double> pred_x = {24};
std::vector<double> pred_y = {12};
ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y);
}
TEST_F(LinearResamplingTest, ResamplingBoundLastDelta) {
std::vector<double> x = {10, 20};
std::vector<double> y = {5, 10};
std::vector<double> t = {10, 14};
// Resample at frame_time = 20 ms, sample time is bounded by 50% of the
// last time delta, result in 14 + 2ms = 16ms.
std::vector<double> pred_ts = {20};
std::vector<double> pred_x = {22.5};
std::vector<double> pred_y = {11.25};
ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y);
}
// Test time interval in first order
TEST_F(LinearResamplingTest, TimeInterval) {
EXPECT_EQ(predictor_->TimeInterval(), kExpectedDefaultTimeInterval);
std::vector<double> x = {10, 20};
std::vector<double> y = {5, 25};
std::vector<double> t = {17, 33};
for (size_t i = 0; i < t.size(); i++) {
predictor_->Update({gfx::PointF(x[i], y[i]), FromMilliseconds(t[i])});
}
EXPECT_EQ(predictor_->TimeInterval(),
base::TimeDelta::FromMilliseconds(t[1] - t[0]));
}
// Tests resampling with the experimental latency if +3.3ms instead of
// the default -5ms.
TEST_F(LinearResamplingTest, ResamplingValueWithExperimentalLatencyTimeBased) {
base::FieldTrialParams params;
params["mode"] = ::features::kPredictionTypeTimeBased;
feature_list.Reset();
feature_list.InitAndEnableFeatureWithParameters(
features::kResamplingScrollEventsExperimentalPrediction, params);
std::vector<double> x = {10, 20, 30};
std::vector<double> y = {5, 25, 35};
std::vector<double> t = {15, 24, 32};
// Resample at `frame_time` = 24.7 ms, `sample_time` = 24.7+3.3 = 28ms.
// Resample at `frame_time` = 32.7 ms, `sample_time` = 32.7+3.3 = 36ms.
std::vector<double> pred_ts = {24.7, 32.7};
std::vector<double> pred_x = {24.44, 35};
std::vector<double> pred_y = {33.89, 40};
ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y);
}
// Tests resampling with the experimental latency if +1ms (using switch) instead
// of the default -5ms.
TEST_F(LinearResamplingTest,
ResamplingValueWithExperimentalLatencyTimeBasedSwitch) {
base::FieldTrialParams params;
params["mode"] = ::features::kPredictionTypeTimeBased;
params["latency"] = "1.0";
feature_list.Reset();
feature_list.InitAndEnableFeatureWithParameters(
features::kResamplingScrollEventsExperimentalPrediction, params);
std::vector<double> x = {10, 20, 30};
std::vector<double> y = {5, 25, 35};
std::vector<double> t = {15, 24, 32};
// Resample at `frame_time` = 27 ms, `sample_time` = 27+1 = 28ms.
// Resample at `frame_time` = 35 ms, `sample_time` = 35+1 = 36ms.
std::vector<double> pred_ts = {27, 35};
std::vector<double> pred_x = {24.44, 35};
std::vector<double> pred_y = {33.89, 40};
ValidatePredictor(x, y, t, pred_ts, pred_x, pred_y);
}
// Tests resampling with the experimental latency if +0.5*`frame_interval`
// instead of the default -5ms.
TEST_F(LinearResamplingTest, ResamplingValueWithExperimentalLatencyFrameBased) {
base::FieldTrialParams params;
params["mode"] = ::features::kPredictionTypeFramesBased;
feature_list.Reset();
feature_list.InitAndEnableFeatureWithParameters(
features::kResamplingScrollEventsExperimentalPrediction, params);
std::vector<double> x = {10, 20, 30};
std::vector<double> y = {5, 25, 35};
std::vector<double> t = {15, 24, 32};
// Using 100Hz frequency => `frame_interval` = 10ms
// Resample at `frame_time` = 33 ms, `sample_time` = 28-5+0.5*10 = 28ms.
// Resample at `frame_time` = 41 ms, `sample_time` = 36-5+0.5*10 = 36ms.
std::vector<double> pred_ts = {28, 36};
std::vector<double> pred_x = {24.44, 35};
std::vector<double> pred_y = {33.89, 40};
ValidatePredictorFrameBased(x, y, t, pred_ts, pred_x, pred_y, 100);
}
// Tests resampling with the experimental latency if +0.5*`frame_interval`
// (using switch) instead of the default -5ms.
TEST_F(LinearResamplingTest,
ResamplingValueWithExperimentalLatencyFrameBasedSwitch) {
base::FieldTrialParams params;
params["mode"] = ::features::kPredictionTypeFramesBased;
params["latency"] = "1.0";
feature_list.Reset();
feature_list.InitAndEnableFeatureWithParameters(
features::kResamplingScrollEventsExperimentalPrediction, params);
std::vector<double> x = {10, 20, 30};
std::vector<double> y = {5, 25, 35};
std::vector<double> t = {15, 24, 32};
// Using 200Hz frequency => `frame_interval` = 5ms
// Resample at `frame_time` = 33 ms, `sample_time` = 28-5+1*5 = 28ms.
// Resample at `frame_time` = 41 ms, `sample_time` = 36-5+1*5 = 36ms.
std::vector<double> pred_ts = {28, 36};
std::vector<double> pred_x = {24.44, 35};
std::vector<double> pred_y = {33.89, 40};
ValidatePredictorFrameBased(x, y, t, pred_ts, pred_x, pred_y, 200);
}
} // namespace test
} // namespace ui