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 "cc/surfaces/display_scheduler.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/test/null_task_runner.h" |
| 9 #include "base/trace_event/trace_event.h" |
| 10 #include "cc/output/begin_frame_args.h" |
| 11 #include "cc/surfaces/display.h" |
| 12 #include "cc/test/scheduler_test_common.h" |
| 13 #include "cc/test/test_now_source.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" |
| 15 |
| 16 namespace cc { |
| 17 namespace { |
| 18 |
| 19 class FakeDisplaySchedulerClient : public DisplaySchedulerClient { |
| 20 public: |
| 21 FakeDisplaySchedulerClient() : draw_and_swap_count_(0) {} |
| 22 |
| 23 ~FakeDisplaySchedulerClient() override {} |
| 24 |
| 25 bool DrawAndSwap() override { |
| 26 draw_and_swap_count_++; |
| 27 return true; |
| 28 } |
| 29 |
| 30 void Reset() { draw_and_swap_count_ = 0; } |
| 31 |
| 32 int draw_and_swap_count() const { return draw_and_swap_count_; } |
| 33 |
| 34 protected: |
| 35 int draw_and_swap_count_; |
| 36 }; |
| 37 |
| 38 class TestDisplayScheduler : public DisplayScheduler { |
| 39 public: |
| 40 TestDisplayScheduler(DisplaySchedulerClient* client, |
| 41 BeginFrameSource* begin_frame_source, |
| 42 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 43 int max_pending_swaps) |
| 44 : DisplayScheduler(client, |
| 45 begin_frame_source, |
| 46 task_runner, |
| 47 max_pending_swaps), |
| 48 scheduler_begin_frame_deadline_count_(0) {} |
| 49 |
| 50 base::TimeTicks DesiredBeginFrameDeadlineTimeForTest() { |
| 51 return DesiredBeginFrameDeadlineTime(); |
| 52 } |
| 53 |
| 54 void BeginFrameDeadlineForTest() { OnBeginFrameDeadline(); } |
| 55 |
| 56 void ScheduleBeginFrameDeadline() override { |
| 57 scheduler_begin_frame_deadline_count_++; |
| 58 DisplayScheduler::ScheduleBeginFrameDeadline(); |
| 59 } |
| 60 |
| 61 int scheduler_begin_frame_deadline_count() { |
| 62 return scheduler_begin_frame_deadline_count_; |
| 63 } |
| 64 |
| 65 protected: |
| 66 int scheduler_begin_frame_deadline_count_; |
| 67 }; |
| 68 |
| 69 class DisplaySchedulerTest : public testing::Test { |
| 70 public: |
| 71 DisplaySchedulerTest() { |
| 72 const int max_pending_swaps = 1; |
| 73 now_src_ = TestNowSource::Create(); |
| 74 null_task_runner_ = make_scoped_refptr(new base::NullTaskRunner); |
| 75 client_ = make_scoped_ptr(new FakeDisplaySchedulerClient); |
| 76 scheduler_ = make_scoped_ptr( |
| 77 new TestDisplayScheduler(client_.get(), &fake_begin_frame_source_, |
| 78 null_task_runner_, max_pending_swaps)); |
| 79 } |
| 80 |
| 81 ~DisplaySchedulerTest() override {} |
| 82 |
| 83 void SetUp() override { scheduler_->SetRootSurfaceResourcesLocked(false); } |
| 84 |
| 85 void BeginFrameForTest() { |
| 86 base::TimeTicks frame_time = now_src_->Now(); |
| 87 base::TimeDelta interval = BeginFrameArgs::DefaultInterval(); |
| 88 base::TimeTicks deadline = frame_time + interval - |
| 89 BeginFrameArgs::DefaultEstimatedParentDrawTime(); |
| 90 fake_begin_frame_source_.TestOnBeginFrame( |
| 91 BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, |
| 92 interval, BeginFrameArgs::NORMAL)); |
| 93 } |
| 94 |
| 95 protected: |
| 96 TestNowSource& now_src() { return *now_src_; } |
| 97 FakeDisplaySchedulerClient& client() { return *client_; } |
| 98 DisplayScheduler& scheduler() { return *scheduler_; } |
| 99 |
| 100 scoped_refptr<TestNowSource> now_src_; |
| 101 scoped_refptr<base::NullTaskRunner> null_task_runner_; |
| 102 |
| 103 FakeBeginFrameSource fake_begin_frame_source_; |
| 104 scoped_ptr<FakeDisplaySchedulerClient> client_; |
| 105 scoped_ptr<TestDisplayScheduler> scheduler_; |
| 106 }; |
| 107 |
| 108 TEST_F(DisplaySchedulerTest, EntireDisplayDamagedDrawsImmediately) { |
| 109 SurfaceId root_surface_id(1); |
| 110 BeginFrameForTest(); |
| 111 EXPECT_LT(now_src().Now(), |
| 112 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 113 scheduler_->EntireDisplayDamaged(root_surface_id); |
| 114 EXPECT_GE(now_src().Now(), |
| 115 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 116 } |
| 117 |
| 118 TEST_F(DisplaySchedulerTest, SurfaceDamaged) { |
| 119 SurfaceId sid1(1); |
| 120 SurfaceId sid2(2); |
| 121 |
| 122 // Get scheduler to detect surface 1 as active by drawing |
| 123 // two frames in a row with damage from surface 1. |
| 124 BeginFrameForTest(); |
| 125 scheduler_->SurfaceDamaged(sid1); |
| 126 scheduler_->BeginFrameDeadlineForTest(); |
| 127 BeginFrameForTest(); |
| 128 scheduler_->SurfaceDamaged(sid1); |
| 129 scheduler_->BeginFrameDeadlineForTest(); |
| 130 |
| 131 // Damage only from surface 2 (inactive) does not trigger deadline early. |
| 132 BeginFrameForTest(); |
| 133 scheduler_->SurfaceDamaged(sid2); |
| 134 EXPECT_LT(now_src().Now(), |
| 135 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 136 |
| 137 // Damage from surface 1 triggers deadline early. |
| 138 scheduler_->SurfaceDamaged(sid1); |
| 139 EXPECT_GE(now_src().Now(), |
| 140 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 141 scheduler_->BeginFrameDeadlineForTest(); |
| 142 |
| 143 // Make both surface 1 and 2 active. |
| 144 BeginFrameForTest(); |
| 145 scheduler_->SurfaceDamaged(sid2); |
| 146 scheduler_->SurfaceDamaged(sid1); |
| 147 scheduler_->BeginFrameDeadlineForTest(); |
| 148 |
| 149 // Deadline doesn't trigger early until surface 1 and 2 are both damaged. |
| 150 BeginFrameForTest(); |
| 151 EXPECT_LT(now_src().Now(), |
| 152 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 153 scheduler_->SurfaceDamaged(sid1); |
| 154 EXPECT_LT(now_src().Now(), |
| 155 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 156 scheduler_->SurfaceDamaged(sid2); |
| 157 EXPECT_GE(now_src().Now(), |
| 158 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 159 scheduler_->BeginFrameDeadlineForTest(); |
| 160 } |
| 161 |
| 162 TEST_F(DisplaySchedulerTest, OutputSurfaceLost) { |
| 163 SurfaceId sid1(1); |
| 164 |
| 165 // DrawAndSwap normally. |
| 166 BeginFrameForTest(); |
| 167 EXPECT_LT(now_src().Now(), |
| 168 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 169 EXPECT_EQ(0, client_->draw_and_swap_count()); |
| 170 scheduler_->SurfaceDamaged(sid1); |
| 171 scheduler_->BeginFrameDeadlineForTest(); |
| 172 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 173 |
| 174 // Deadline triggers immediately on OutputSurfaceLost. |
| 175 BeginFrameForTest(); |
| 176 EXPECT_LT(now_src().Now(), |
| 177 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 178 scheduler_->OutputSurfaceLost(); |
| 179 EXPECT_GE(now_src().Now(), |
| 180 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 181 |
| 182 // Deadline does not DrawAndSwap after OutputSurfaceLost. |
| 183 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 184 scheduler_->SurfaceDamaged(sid1); |
| 185 scheduler_->BeginFrameDeadlineForTest(); |
| 186 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 187 } |
| 188 |
| 189 TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) { |
| 190 SurfaceId sid1(1); |
| 191 base::TimeTicks late_deadline; |
| 192 |
| 193 // DrawAndSwap normally. |
| 194 BeginFrameForTest(); |
| 195 EXPECT_LT(now_src().Now(), |
| 196 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 197 EXPECT_EQ(0, client_->draw_and_swap_count()); |
| 198 scheduler_->SurfaceDamaged(sid1); |
| 199 scheduler_->BeginFrameDeadlineForTest(); |
| 200 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 201 |
| 202 // Deadline triggers late while root resources are locked. |
| 203 late_deadline = now_src().Now() + BeginFrameArgs::DefaultInterval(); |
| 204 BeginFrameForTest(); |
| 205 scheduler_->SurfaceDamaged(sid1); |
| 206 EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 207 scheduler_->SetRootSurfaceResourcesLocked(true); |
| 208 EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 209 |
| 210 // Deadline does not DrawAndSwap while root resources are locked. |
| 211 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 212 scheduler_->SurfaceDamaged(sid1); |
| 213 scheduler_->BeginFrameDeadlineForTest(); |
| 214 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 215 |
| 216 // Deadline triggers normally when root resources are locked. |
| 217 late_deadline = now_src().Now() + BeginFrameArgs::DefaultInterval(); |
| 218 BeginFrameForTest(); |
| 219 scheduler_->SurfaceDamaged(sid1); |
| 220 EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 221 scheduler_->SetRootSurfaceResourcesLocked(false); |
| 222 EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 223 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 224 scheduler_->BeginFrameDeadlineForTest(); |
| 225 EXPECT_EQ(2, client_->draw_and_swap_count()); |
| 226 } |
| 227 |
| 228 TEST_F(DisplaySchedulerTest, DidSwapBuffers) { |
| 229 SurfaceId sid1(1); |
| 230 base::TimeTicks late_deadline; |
| 231 |
| 232 // DrawAndSwap normally. |
| 233 BeginFrameForTest(); |
| 234 EXPECT_LT(now_src().Now(), |
| 235 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 236 EXPECT_EQ(0, client_->draw_and_swap_count()); |
| 237 scheduler_->SurfaceDamaged(sid1); |
| 238 scheduler_->BeginFrameDeadlineForTest(); |
| 239 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 240 scheduler_->DidSwapBuffers(); |
| 241 |
| 242 // Deadline triggers immediately while swap throttled. |
| 243 BeginFrameForTest(); |
| 244 scheduler_->SurfaceDamaged(sid1); |
| 245 EXPECT_EQ(base::TimeTicks(), |
| 246 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 247 |
| 248 // Don't draw and swap in deadline while swap throttled. |
| 249 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 250 scheduler_->BeginFrameDeadlineForTest(); |
| 251 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 252 |
| 253 // Then triggers normally once not swap throttled. |
| 254 // Damage from previous BeginFrame should cary over, so don't damage again. |
| 255 late_deadline = now_src().Now() + BeginFrameArgs::DefaultInterval(); |
| 256 BeginFrameForTest(); |
| 257 EXPECT_EQ(base::TimeTicks(), |
| 258 scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 259 scheduler_->DidSwapBuffersComplete(); |
| 260 EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); |
| 261 |
| 262 // Draw and swap in deadline now that we aren't swap throttled. |
| 263 EXPECT_EQ(1, client_->draw_and_swap_count()); |
| 264 scheduler_->BeginFrameDeadlineForTest(); |
| 265 EXPECT_EQ(2, client_->draw_and_swap_count()); |
| 266 } |
| 267 |
| 268 // This test verfies that we try to reschedule the deadline |
| 269 // after any event that may change what deadline we want. |
| 270 TEST_F(DisplaySchedulerTest, ScheduleBeginFrameDeadline) { |
| 271 SurfaceId root_surface_id(1); |
| 272 SurfaceId sid1(2); |
| 273 int count = 1; |
| 274 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 275 |
| 276 BeginFrameForTest(); |
| 277 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 278 |
| 279 scheduler_->BeginFrameDeadlineForTest(); |
| 280 scheduler_->DidSwapBuffers(); |
| 281 BeginFrameForTest(); |
| 282 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 283 |
| 284 scheduler_->DidSwapBuffersComplete(); |
| 285 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 286 |
| 287 scheduler_->EntireDisplayDamaged(root_surface_id); |
| 288 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 289 |
| 290 scheduler_->SurfaceDamaged(sid1); |
| 291 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 292 |
| 293 scheduler_->SetRootSurfaceResourcesLocked(true); |
| 294 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 295 |
| 296 scheduler_->OutputSurfaceLost(); |
| 297 EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); |
| 298 } |
| 299 |
| 300 } // namespace |
| 301 } // namespace cc |
OLD | NEW |