OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "services/gfx/compositor/backend/vsync_scheduler.h" |
| 6 |
| 7 #include <queue> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/test/test_mock_time_task_runner.h" |
| 11 #include "base/time/tick_clock.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 namespace compositor { |
| 15 |
| 16 static constexpr int64_t kVsyncTimebase = -5000; |
| 17 static constexpr int64_t kVsyncInterval = 10000; |
| 18 static constexpr int64_t kUpdatePhase = -9000; |
| 19 static constexpr int64_t kSnapshotPhase = -1000; |
| 20 static constexpr int64_t kPresentationPhase = 2000; |
| 21 |
| 22 class VsyncSchedulerTest : public testing::Test { |
| 23 protected: |
| 24 void SetUp() override { Reset(); } |
| 25 |
| 26 void TearDown() override { |
| 27 task_runner_->FastForwardUntilNoTasksRemain(); |
| 28 EXPECT_TRUE(expected_callbacks_.empty()); |
| 29 } |
| 30 |
| 31 void ExpectUpdateCallback(int64_t frame_time, |
| 32 uint64_t frame_interval, |
| 33 int64_t frame_deadline, |
| 34 int64_t presentation_time) { |
| 35 expected_callbacks_.emplace(CallbackType::kUpdate, frame_time, frame_time, |
| 36 frame_interval, frame_deadline, |
| 37 presentation_time); |
| 38 } |
| 39 |
| 40 void ExpectSnapshotCallback(int64_t frame_time, |
| 41 uint64_t frame_interval, |
| 42 int64_t frame_deadline, |
| 43 int64_t presentation_time) { |
| 44 expected_callbacks_.emplace(CallbackType::kSnapshot, frame_deadline, |
| 45 frame_time, frame_interval, frame_deadline, |
| 46 presentation_time); |
| 47 } |
| 48 |
| 49 MojoTimeTicks GetTimeTicksNow() { |
| 50 return task_runner_->NowTicks().ToInternalValue(); |
| 51 } |
| 52 |
| 53 void Reset() { |
| 54 task_runner_ = new base::TestMockTimeTaskRunner(); |
| 55 SchedulerCallbacks callbacks( |
| 56 base::Bind(&VsyncSchedulerTest::OnUpdate, base::Unretained(this)), |
| 57 base::Bind(&VsyncSchedulerTest::OnSnapshot, base::Unretained(this))); |
| 58 scheduler_.reset( |
| 59 new VsyncScheduler(task_runner_, callbacks, |
| 60 base::Bind(&VsyncSchedulerTest::GetTimeTicksNow, |
| 61 base::Unretained(this)))); |
| 62 |
| 63 std::queue<ExpectedCallback> victim; |
| 64 expected_callbacks_.swap(victim); |
| 65 } |
| 66 |
| 67 void FastForwardTo(int64_t time) { |
| 68 DCHECK(time >= GetTimeTicksNow()); |
| 69 task_runner_->FastForwardBy( |
| 70 base::TimeDelta::FromMicroseconds(time - GetTimeTicksNow())); |
| 71 } |
| 72 |
| 73 std::unique_ptr<VsyncScheduler> scheduler_; |
| 74 |
| 75 private: |
| 76 enum class CallbackType { |
| 77 kUpdate, |
| 78 kSnapshot, |
| 79 }; |
| 80 |
| 81 struct ExpectedCallback { |
| 82 ExpectedCallback(CallbackType type, |
| 83 int64_t delivery_time, |
| 84 int64_t frame_time, |
| 85 uint64_t frame_interval, |
| 86 int64_t frame_deadline, |
| 87 int64_t presentation_time) |
| 88 : type(type), |
| 89 delivery_time(delivery_time), |
| 90 frame_time(frame_time), |
| 91 frame_interval(frame_interval), |
| 92 frame_deadline(frame_deadline), |
| 93 presentation_time(presentation_time) {} |
| 94 |
| 95 CallbackType type; |
| 96 int64_t delivery_time; |
| 97 int64_t frame_time; |
| 98 uint64_t frame_interval; |
| 99 int64_t frame_deadline; |
| 100 int64_t presentation_time; |
| 101 }; |
| 102 |
| 103 void OnUpdate(const mojo::gfx::composition::FrameInfo& frame_info) { |
| 104 VerifyCallback(CallbackType::kUpdate, frame_info); |
| 105 } |
| 106 |
| 107 void OnSnapshot(const mojo::gfx::composition::FrameInfo& frame_info) { |
| 108 VerifyCallback(CallbackType::kSnapshot, frame_info); |
| 109 } |
| 110 |
| 111 void VerifyCallback(CallbackType type, |
| 112 const mojo::gfx::composition::FrameInfo& frame_info) { |
| 113 EXPECT_FALSE(expected_callbacks_.empty()); |
| 114 if (!expected_callbacks_.empty()) { |
| 115 const ExpectedCallback& c = expected_callbacks_.front(); |
| 116 EXPECT_EQ(static_cast<int>(c.type), static_cast<int>(type)); |
| 117 EXPECT_EQ(c.delivery_time, GetTimeTicksNow()); |
| 118 EXPECT_EQ(c.frame_time, frame_info.frame_time); |
| 119 EXPECT_EQ(c.frame_interval, frame_info.frame_interval); |
| 120 EXPECT_EQ(c.frame_deadline, frame_info.frame_deadline); |
| 121 EXPECT_EQ(c.presentation_time, frame_info.presentation_time); |
| 122 expected_callbacks_.pop(); |
| 123 } |
| 124 } |
| 125 |
| 126 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| 127 std::queue<ExpectedCallback> expected_callbacks_; |
| 128 }; |
| 129 |
| 130 TEST_F(VsyncSchedulerTest, StartValidatesArguments) { |
| 131 // Vsync timebase is in the past. |
| 132 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 133 kSnapshotPhase, kPresentationPhase)); |
| 134 Reset(); |
| 135 |
| 136 // Vsync timebase is now. (current time == 0) |
| 137 EXPECT_TRUE(scheduler_->Start(0, kVsyncInterval, kUpdatePhase, kSnapshotPhase, |
| 138 kPresentationPhase)); |
| 139 Reset(); |
| 140 |
| 141 // Vsync timebase in the future. (current time == 0) |
| 142 EXPECT_FALSE(scheduler_->Start(1, kVsyncInterval, kUpdatePhase, |
| 143 kSnapshotPhase, kPresentationPhase)); |
| 144 |
| 145 // Vsync interval too small. |
| 146 EXPECT_FALSE( |
| 147 scheduler_->Start(0, VsyncScheduler::kMinVsyncInterval - 1, 0, 0, 0)); |
| 148 |
| 149 // Vsync interval at minimum. |
| 150 EXPECT_TRUE(scheduler_->Start(0, VsyncScheduler::kMinVsyncInterval, 0, 0, 0)); |
| 151 Reset(); |
| 152 |
| 153 // Vsync interval at maximum. |
| 154 EXPECT_TRUE(scheduler_->Start(0, VsyncScheduler::kMaxVsyncInterval, 0, 0, 0)); |
| 155 Reset(); |
| 156 |
| 157 // Vsync interval too large. |
| 158 EXPECT_FALSE( |
| 159 scheduler_->Start(0, VsyncScheduler::kMaxVsyncInterval + 1, 0, 0, 0)); |
| 160 |
| 161 // Snapshot phase earlier than update phase. |
| 162 EXPECT_FALSE(scheduler_->Start(0, kVsyncInterval, kUpdatePhase, |
| 163 kUpdatePhase - 1, kPresentationPhase)); |
| 164 |
| 165 // Snapshot phase more than one frame behind update phase. |
| 166 EXPECT_FALSE(scheduler_->Start(0, kVsyncInterval, kUpdatePhase, |
| 167 kUpdatePhase + kVsyncInterval + 1, |
| 168 kPresentationPhase)); |
| 169 |
| 170 // Presentation phase earlier than snapshot phase. |
| 171 EXPECT_FALSE(scheduler_->Start(0, kVsyncInterval, kUpdatePhase, |
| 172 kSnapshotPhase, kSnapshotPhase - 1)); |
| 173 |
| 174 // Minimum and maximum update vs. snapshot phase delta. |
| 175 EXPECT_TRUE(scheduler_->Start(0, kVsyncInterval, kUpdatePhase, kUpdatePhase, |
| 176 kUpdatePhase)); |
| 177 Reset(); |
| 178 EXPECT_TRUE(scheduler_->Start(0, kVsyncInterval, kUpdatePhase, |
| 179 kUpdatePhase + kVsyncInterval, |
| 180 kUpdatePhase + kVsyncInterval)); |
| 181 Reset(); |
| 182 } |
| 183 |
| 184 TEST_F(VsyncSchedulerTest, ScheduleRedundantSnapshot) { |
| 185 // Start immediately schedules work. |
| 186 ExpectSnapshotCallback(-4000, kVsyncInterval, 4000, 7000); |
| 187 ExpectUpdateCallback(6000, kVsyncInterval, 14000, 17000); |
| 188 ExpectSnapshotCallback(6000, kVsyncInterval, 14000, 17000); |
| 189 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 190 kSnapshotPhase, kPresentationPhase)); |
| 191 |
| 192 // Shortly after the first update, schedule another snapshot. |
| 193 // Nothing happens because a snapshot is still due at 14000. |
| 194 FastForwardTo(8000); |
| 195 scheduler_->ScheduleFrame(SchedulingMode::kSnapshot); |
| 196 } |
| 197 |
| 198 TEST_F(VsyncSchedulerTest, ScheduleRedundantUpdate) { |
| 199 // Start immediately schedules work. |
| 200 ExpectSnapshotCallback(-4000, kVsyncInterval, 4000, 7000); |
| 201 ExpectUpdateCallback(6000, kVsyncInterval, 14000, 17000); |
| 202 ExpectSnapshotCallback(6000, kVsyncInterval, 14000, 17000); |
| 203 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 204 kSnapshotPhase, kPresentationPhase)); |
| 205 |
| 206 // Before the first update, schedule another update. |
| 207 // Nothing happens because an update is still due at 6000. |
| 208 FastForwardTo(5000); |
| 209 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 210 } |
| 211 |
| 212 TEST_F(VsyncSchedulerTest, ScheduleRequiredSnapshot) { |
| 213 // Start immediately schedules work. |
| 214 ExpectSnapshotCallback(-4000, kVsyncInterval, 4000, 7000); |
| 215 ExpectUpdateCallback(6000, kVsyncInterval, 14000, 17000); |
| 216 ExpectSnapshotCallback(6000, kVsyncInterval, 14000, 17000); |
| 217 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 218 kSnapshotPhase, kPresentationPhase)); |
| 219 |
| 220 // Shortly after the last snapshot, schedule another snapshot. |
| 221 FastForwardTo(15000); |
| 222 ExpectUpdateCallback(16000, kVsyncInterval, 24000, 27000); |
| 223 ExpectSnapshotCallback(16000, kVsyncInterval, 24000, 27000); |
| 224 scheduler_->ScheduleFrame(SchedulingMode::kSnapshot); |
| 225 |
| 226 // Exactly at the moment of the next snapshot, schedule another snapshot. |
| 227 FastForwardTo(24000); |
| 228 ExpectUpdateCallback(26000, kVsyncInterval, 34000, 37000); |
| 229 ExpectSnapshotCallback(26000, kVsyncInterval, 34000, 37000); |
| 230 scheduler_->ScheduleFrame(SchedulingMode::kSnapshot); |
| 231 |
| 232 // A long time thereafter, with no time to update, schedule another snapshot. |
| 233 FastForwardTo(53000); |
| 234 ExpectSnapshotCallback(46000, kVsyncInterval, 54000, 57000); |
| 235 scheduler_->ScheduleFrame(SchedulingMode::kSnapshot); |
| 236 |
| 237 // A long time thereafter, with time to update, schedule another snapshot. |
| 238 FastForwardTo(75000); |
| 239 ExpectUpdateCallback(76000, kVsyncInterval, 84000, 87000); |
| 240 ExpectSnapshotCallback(76000, kVsyncInterval, 84000, 87000); |
| 241 scheduler_->ScheduleFrame(SchedulingMode::kSnapshot); |
| 242 } |
| 243 |
| 244 TEST_F(VsyncSchedulerTest, ScheduleRequiredUpdate) { |
| 245 // Start immediately schedules work. |
| 246 ExpectSnapshotCallback(-4000, kVsyncInterval, 4000, 7000); |
| 247 ExpectUpdateCallback(6000, kVsyncInterval, 14000, 17000); |
| 248 ExpectSnapshotCallback(6000, kVsyncInterval, 14000, 17000); |
| 249 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 250 kSnapshotPhase, kPresentationPhase)); |
| 251 |
| 252 // Shortly after the first update, schedule another update. |
| 253 FastForwardTo(8000); |
| 254 ExpectUpdateCallback(16000, kVsyncInterval, 24000, 27000); |
| 255 ExpectSnapshotCallback(16000, kVsyncInterval, 24000, 27000); |
| 256 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 257 |
| 258 // Exactly at the moment of the next update, schedule another update. |
| 259 FastForwardTo(16000); |
| 260 ExpectUpdateCallback(26000, kVsyncInterval, 34000, 37000); |
| 261 ExpectSnapshotCallback(26000, kVsyncInterval, 34000, 37000); |
| 262 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 263 |
| 264 // A long time thereafter, with no time to snapshot, schedule another update. |
| 265 FastForwardTo(55000); |
| 266 ExpectUpdateCallback(56000, kVsyncInterval, 64000, 67000); |
| 267 ExpectSnapshotCallback(56000, kVsyncInterval, 64000, 67000); |
| 268 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 269 |
| 270 // A long time thereafter, with time to snapshot, schedule another update. |
| 271 FastForwardTo(83000); |
| 272 ExpectSnapshotCallback(76000, kVsyncInterval, 84000, 87000); |
| 273 ExpectUpdateCallback(86000, kVsyncInterval, 94000, 97000); |
| 274 ExpectSnapshotCallback(86000, kVsyncInterval, 94000, 97000); |
| 275 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 276 } |
| 277 |
| 278 TEST_F(VsyncSchedulerTest, StartAndStop) { |
| 279 // Scheduling frames before start does nothing. |
| 280 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 281 |
| 282 // Starting the scheduler automatically schedules an update. |
| 283 FastForwardTo(15000); |
| 284 ExpectUpdateCallback(16000, kVsyncInterval, 24000, 27000); |
| 285 ExpectSnapshotCallback(16000, kVsyncInterval, 24000, 27000); |
| 286 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 287 kSnapshotPhase, kPresentationPhase)); |
| 288 |
| 289 // Stopping the scheduler suspends further updates. |
| 290 FastForwardTo(24000); |
| 291 scheduler_->Stop(); |
| 292 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 293 |
| 294 // Restarting scheduling resumes updates. |
| 295 FastForwardTo(53000); |
| 296 ExpectSnapshotCallback(46000, kVsyncInterval, 54000, 57000); |
| 297 ExpectUpdateCallback(56000, kVsyncInterval, 64000, 67000); |
| 298 ExpectSnapshotCallback(56000, kVsyncInterval, 64000, 67000); |
| 299 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 300 kSnapshotPhase, kPresentationPhase)); |
| 301 |
| 302 // Stopping the scheduler cancels undelivered updates. |
| 303 FastForwardTo(63000); |
| 304 // canceled: ExpectUpdateCallback(66000, kVsyncInterval, 74000, 77000); |
| 305 // canceled: ExpectSnapshotCallback(66000, kVsyncInterval, 74000, 77000); |
| 306 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 307 FastForwardTo(65000); |
| 308 scheduler_->Stop(); |
| 309 } |
| 310 |
| 311 TEST_F(VsyncSchedulerTest, RedundantStart) { |
| 312 // Start immediately schedules work. |
| 313 ExpectSnapshotCallback(-4000, kVsyncInterval, 4000, 7000); |
| 314 ExpectUpdateCallback(6000, kVsyncInterval, 14000, 17000); |
| 315 ExpectSnapshotCallback(6000, kVsyncInterval, 14000, 17000); |
| 316 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 317 kSnapshotPhase, kPresentationPhase)); |
| 318 |
| 319 // Doing it again has no added effect. |
| 320 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 321 kSnapshotPhase, kPresentationPhase)); |
| 322 |
| 323 // A long time thereafter, schedule another update. |
| 324 FastForwardTo(55000); |
| 325 ExpectUpdateCallback(56000, kVsyncInterval, 64000, 67000); |
| 326 ExpectSnapshotCallback(56000, kVsyncInterval, 64000, 67000); |
| 327 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 328 } |
| 329 |
| 330 TEST_F(VsyncSchedulerTest, StartWithNewParameters) { |
| 331 // Start immediately schedules work. |
| 332 ExpectSnapshotCallback(-4000, kVsyncInterval, 4000, 7000); |
| 333 ExpectUpdateCallback(6000, kVsyncInterval, 14000, 17000); |
| 334 ExpectSnapshotCallback(6000, kVsyncInterval, 14000, 17000); |
| 335 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 336 kSnapshotPhase, kPresentationPhase)); |
| 337 |
| 338 // After the snapshot is delivered, change parameters. |
| 339 FastForwardTo(14000); |
| 340 ExpectUpdateCallback(17000, kVsyncInterval * 2, 33000, 39000); |
| 341 ExpectSnapshotCallback(17000, kVsyncInterval * 2, 33000, 39000); |
| 342 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval * 2, |
| 343 kUpdatePhase * 2, kSnapshotPhase * 2, |
| 344 kPresentationPhase * 2)); |
| 345 |
| 346 // Schedule another update with these parameters. |
| 347 FastForwardTo(18000); |
| 348 ExpectUpdateCallback(37000, kVsyncInterval * 2, 53000, 59000); |
| 349 // canceled: ExpectSnapshotCallback(37000, kVsyncInterval * 2, 53000, 59000); |
| 350 scheduler_->ScheduleFrame(SchedulingMode::kUpdateAndSnapshot); |
| 351 |
| 352 // At the moment when the update is delivered, change parameters again. |
| 353 // We're too late to cancel the prior update but we do cancel the prior |
| 354 // snapshot and we'll follow it up with another update with the new |
| 355 // parameters. |
| 356 FastForwardTo(37000); |
| 357 ExpectUpdateCallback(46000, kVsyncInterval, 54000, 57000); |
| 358 ExpectSnapshotCallback(46000, kVsyncInterval, 54000, 57000); |
| 359 EXPECT_TRUE(scheduler_->Start(kVsyncTimebase, kVsyncInterval, kUpdatePhase, |
| 360 kSnapshotPhase, kPresentationPhase)); |
| 361 } |
| 362 |
| 363 // TODO(jeffbrown): Add tests for cases where the compositor has fallen behind. |
| 364 |
| 365 } // namespace compositor |
OLD | NEW |