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