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.
5 #include "cc/surfaces/display_scheduler.h"
7 #include "base/logging.h"
8 #include "base/test/null_task_runner.h"
9 #include "base/test/simple_test_tick_clock.h"
10 #include "base/trace_event/trace_event.h"
11 #include "cc/output/begin_frame_args.h"
12 #include "cc/surfaces/display.h"
13 #include "cc/test/scheduler_test_common.h"
14 #include "testing/gtest/include/gtest/gtest.h"
19 const int kMaxPendingSwaps
= 1;
21 class FakeDisplaySchedulerClient
: public DisplaySchedulerClient
{
23 FakeDisplaySchedulerClient() : draw_and_swap_count_(0) {}
25 ~FakeDisplaySchedulerClient() override
{}
27 bool DrawAndSwap() override
{
28 draw_and_swap_count_
++;
32 void Reset() { draw_and_swap_count_
= 0; }
34 int draw_and_swap_count() const { return draw_and_swap_count_
; }
37 int draw_and_swap_count_
;
40 class TestDisplayScheduler
: public DisplayScheduler
{
42 TestDisplayScheduler(DisplaySchedulerClient
* client
,
43 BeginFrameSource
* begin_frame_source
,
44 base::SingleThreadTaskRunner
* task_runner
,
45 int max_pending_swaps
)
46 : DisplayScheduler(client
,
50 scheduler_begin_frame_deadline_count_(0) {}
52 base::TimeTicks
DesiredBeginFrameDeadlineTimeForTest() {
53 return DesiredBeginFrameDeadlineTime();
56 void BeginFrameDeadlineForTest() { OnBeginFrameDeadline(); }
58 void ScheduleBeginFrameDeadline() override
{
59 scheduler_begin_frame_deadline_count_
++;
60 DisplayScheduler::ScheduleBeginFrameDeadline();
63 int scheduler_begin_frame_deadline_count() {
64 return scheduler_begin_frame_deadline_count_
;
68 int scheduler_begin_frame_deadline_count_
;
71 class DisplaySchedulerTest
: public testing::Test
{
73 DisplaySchedulerTest()
74 : now_src_(new base::SimpleTestTickClock()),
75 task_runner_(new base::NullTaskRunner
),
76 client_(new FakeDisplaySchedulerClient
),
77 scheduler_(new TestDisplayScheduler(client_
.get(),
78 &fake_begin_frame_source_
,
81 now_src_
->Advance(base::TimeDelta::FromMicroseconds(10000));
84 ~DisplaySchedulerTest() override
{}
86 void SetUp() override
{ scheduler_
->SetRootSurfaceResourcesLocked(false); }
88 void BeginFrameForTest() {
89 base::TimeTicks frame_time
= now_src_
->NowTicks();
90 base::TimeDelta interval
= BeginFrameArgs::DefaultInterval();
91 base::TimeTicks deadline
= frame_time
+ interval
;
92 fake_begin_frame_source_
.TestOnBeginFrame(
93 BeginFrameArgs::Create(BEGINFRAME_FROM_HERE
, frame_time
, deadline
,
94 interval
, BeginFrameArgs::NORMAL
));
98 base::SimpleTestTickClock
& now_src() { return *now_src_
; }
99 FakeDisplaySchedulerClient
& client() { return *client_
; }
100 DisplayScheduler
& scheduler() { return *scheduler_
; }
102 FakeBeginFrameSource fake_begin_frame_source_
;
104 scoped_ptr
<base::SimpleTestTickClock
> now_src_
;
105 scoped_refptr
<base::NullTaskRunner
> task_runner_
;
106 scoped_ptr
<FakeDisplaySchedulerClient
> client_
;
107 scoped_ptr
<TestDisplayScheduler
> scheduler_
;
110 TEST_F(DisplaySchedulerTest
, ResizeHasLateDeadlineUntilNewRootSurface
) {
111 SurfaceId
root_surface_id1(1);
112 SurfaceId
root_surface_id2(2);
114 base::TimeTicks late_deadline
;
116 // Go trough an initial BeginFrame cycle with the root surface.
118 scheduler_
->SetNewRootSurface(root_surface_id1
);
119 scheduler_
->BeginFrameDeadlineForTest();
121 // Resize on the next begin frame cycle should cause the deadline to wait
122 // for a new root surface.
123 late_deadline
= now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
125 scheduler_
->SurfaceDamaged(sid1
);
126 EXPECT_GT(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
127 scheduler_
->DisplayResized();
128 EXPECT_EQ(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
129 scheduler_
->SetNewRootSurface(root_surface_id2
);
130 EXPECT_GE(now_src().NowTicks(),
131 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
132 scheduler_
->BeginFrameDeadlineForTest();
134 // Verify deadline goes back to normal after resize.
135 late_deadline
= now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
137 scheduler_
->SurfaceDamaged(sid1
);
138 EXPECT_GT(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
139 scheduler_
->SurfaceDamaged(root_surface_id2
);
140 EXPECT_GE(now_src().NowTicks(),
141 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
142 scheduler_
->BeginFrameDeadlineForTest();
145 TEST_F(DisplaySchedulerTest
, ResizeHasLateDeadlineUntilDamagedSurface
) {
146 SurfaceId
root_surface_id(1);
148 base::TimeTicks late_deadline
;
150 // Go trough an initial BeginFrame cycle with the root surface.
152 scheduler_
->SetNewRootSurface(root_surface_id
);
153 scheduler_
->BeginFrameDeadlineForTest();
155 // Resize on the next begin frame cycle should cause the deadline to wait
156 // for a new root surface.
157 late_deadline
= now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
159 scheduler_
->SurfaceDamaged(sid1
);
160 EXPECT_GT(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
161 scheduler_
->DisplayResized();
162 EXPECT_EQ(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
163 scheduler_
->SurfaceDamaged(root_surface_id
);
164 EXPECT_GE(now_src().NowTicks(),
165 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
166 scheduler_
->BeginFrameDeadlineForTest();
168 // Verify deadline goes back to normal after resize.
169 late_deadline
= now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
171 scheduler_
->SurfaceDamaged(sid1
);
172 EXPECT_GT(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
173 scheduler_
->SurfaceDamaged(root_surface_id
);
174 EXPECT_GE(now_src().NowTicks(),
175 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
176 scheduler_
->BeginFrameDeadlineForTest();
179 TEST_F(DisplaySchedulerTest
, SurfaceDamaged
) {
180 SurfaceId
root_surface_id(0);
184 // Set the root surface
185 scheduler_
->SetNewRootSurface(root_surface_id
);
187 // Get scheduler to detect surface 1 as active by drawing
188 // two frames in a row with damage from surface 1.
190 scheduler_
->SurfaceDamaged(sid1
);
191 scheduler_
->BeginFrameDeadlineForTest();
193 scheduler_
->SurfaceDamaged(sid1
);
194 scheduler_
->BeginFrameDeadlineForTest();
196 // Damage only from surface 2 (inactive) does not trigger deadline early.
198 scheduler_
->SurfaceDamaged(sid2
);
199 EXPECT_LT(now_src().NowTicks(),
200 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
202 // Damage from surface 1 triggers deadline early.
203 scheduler_
->SurfaceDamaged(sid1
);
204 EXPECT_GE(now_src().NowTicks(),
205 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
206 scheduler_
->BeginFrameDeadlineForTest();
208 // Make both surface 1 and 2 active.
210 scheduler_
->SurfaceDamaged(sid2
);
211 scheduler_
->SurfaceDamaged(sid1
);
212 scheduler_
->BeginFrameDeadlineForTest();
214 // Deadline doesn't trigger early until surface 1 and 2 are both damaged.
216 EXPECT_LT(now_src().NowTicks(),
217 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
218 scheduler_
->SurfaceDamaged(sid1
);
219 EXPECT_LT(now_src().NowTicks(),
220 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
221 scheduler_
->SurfaceDamaged(sid2
);
222 EXPECT_GE(now_src().NowTicks(),
223 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
224 scheduler_
->BeginFrameDeadlineForTest();
226 // Make the system idle
228 scheduler_
->BeginFrameDeadlineForTest();
230 scheduler_
->BeginFrameDeadlineForTest();
232 // Deadline should trigger early if child surfaces are idle and
233 // we get damage on the root surface.
235 EXPECT_LT(now_src().NowTicks(),
236 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
237 scheduler_
->SurfaceDamaged(root_surface_id
);
238 EXPECT_GE(now_src().NowTicks(),
239 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
240 scheduler_
->BeginFrameDeadlineForTest();
243 TEST_F(DisplaySchedulerTest
, OutputSurfaceLost
) {
246 // DrawAndSwap normally.
248 EXPECT_LT(now_src().NowTicks(),
249 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
250 EXPECT_EQ(0, client_
->draw_and_swap_count());
251 scheduler_
->SurfaceDamaged(sid1
);
252 scheduler_
->BeginFrameDeadlineForTest();
253 EXPECT_EQ(1, client_
->draw_and_swap_count());
255 // Deadline triggers immediately on OutputSurfaceLost.
257 EXPECT_LT(now_src().NowTicks(),
258 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
259 scheduler_
->OutputSurfaceLost();
260 EXPECT_GE(now_src().NowTicks(),
261 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
263 // Deadline does not DrawAndSwap after OutputSurfaceLost.
264 EXPECT_EQ(1, client_
->draw_and_swap_count());
265 scheduler_
->SurfaceDamaged(sid1
);
266 scheduler_
->BeginFrameDeadlineForTest();
267 EXPECT_EQ(1, client_
->draw_and_swap_count());
270 TEST_F(DisplaySchedulerTest
, RootSurfaceResourcesLocked
) {
272 base::TimeTicks late_deadline
;
274 // DrawAndSwap normally.
276 EXPECT_LT(now_src().NowTicks(),
277 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
278 EXPECT_EQ(0, client_
->draw_and_swap_count());
279 scheduler_
->SurfaceDamaged(sid1
);
280 scheduler_
->BeginFrameDeadlineForTest();
281 EXPECT_EQ(1, client_
->draw_and_swap_count());
283 // Deadline triggers late while root resources are locked.
284 late_deadline
= now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
286 scheduler_
->SurfaceDamaged(sid1
);
287 EXPECT_GT(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
288 scheduler_
->SetRootSurfaceResourcesLocked(true);
289 EXPECT_EQ(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
291 // Deadline does not DrawAndSwap while root resources are locked.
292 EXPECT_EQ(1, client_
->draw_and_swap_count());
293 scheduler_
->SurfaceDamaged(sid1
);
294 scheduler_
->BeginFrameDeadlineForTest();
295 EXPECT_EQ(1, client_
->draw_and_swap_count());
297 // Deadline triggers normally when root resources are unlocked.
298 late_deadline
= now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
300 scheduler_
->SurfaceDamaged(sid1
);
301 EXPECT_EQ(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
302 scheduler_
->SetRootSurfaceResourcesLocked(false);
303 EXPECT_EQ(base::TimeTicks(),
304 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
306 EXPECT_EQ(1, client_
->draw_and_swap_count());
307 scheduler_
->BeginFrameDeadlineForTest();
308 EXPECT_EQ(2, client_
->draw_and_swap_count());
311 TEST_F(DisplaySchedulerTest
, DidSwapBuffers
) {
315 // Get scheduler to detect surface 1 and 2 as active.
317 scheduler_
->SurfaceDamaged(sid1
);
318 scheduler_
->SurfaceDamaged(sid2
);
319 scheduler_
->BeginFrameDeadlineForTest();
321 scheduler_
->SurfaceDamaged(sid1
);
322 scheduler_
->SurfaceDamaged(sid2
);
323 scheduler_
->BeginFrameDeadlineForTest();
325 // DrawAndSwap normally.
327 EXPECT_LT(now_src().NowTicks(),
328 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
329 EXPECT_EQ(2, client_
->draw_and_swap_count());
330 scheduler_
->SurfaceDamaged(sid1
);
331 scheduler_
->SurfaceDamaged(sid2
);
332 scheduler_
->BeginFrameDeadlineForTest();
333 EXPECT_EQ(3, client_
->draw_and_swap_count());
334 scheduler_
->DidSwapBuffers();
336 // Deadline triggers late when swap throttled.
337 base::TimeTicks late_deadline
=
338 now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
340 // Damage surface 1, but not surface 2 so we avoid triggering deadline
341 // early because all surfaces are ready.
342 scheduler_
->SurfaceDamaged(sid1
);
343 EXPECT_EQ(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
345 // Don't draw and swap in deadline while swap throttled.
346 EXPECT_EQ(3, client_
->draw_and_swap_count());
347 scheduler_
->BeginFrameDeadlineForTest();
348 EXPECT_EQ(3, client_
->draw_and_swap_count());
350 // Deadline triggers normally once not swap throttled.
351 // Damage from previous BeginFrame should cary over, so don't damage again.
352 base::TimeTicks expected_deadline
=
353 fake_begin_frame_source_
.TestLastUsedBeginFrameArgs().deadline
-
354 BeginFrameArgs::DefaultEstimatedParentDrawTime();
355 scheduler_
->DidSwapBuffersComplete();
357 EXPECT_EQ(expected_deadline
,
358 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
359 // Still waiting for surface 2. Once it updates, deadline should trigger
360 // immediately again.
361 scheduler_
->SurfaceDamaged(sid2
);
362 EXPECT_EQ(scheduler_
->DesiredBeginFrameDeadlineTimeForTest(),
364 // Draw and swap now that we aren't throttled.
365 EXPECT_EQ(3, client_
->draw_and_swap_count());
366 scheduler_
->BeginFrameDeadlineForTest();
367 EXPECT_EQ(4, client_
->draw_and_swap_count());
370 // This test verfies that we try to reschedule the deadline
371 // after any event that may change what deadline we want.
372 TEST_F(DisplaySchedulerTest
, ScheduleBeginFrameDeadline
) {
373 SurfaceId
root_surface_id(1);
376 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
379 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
381 scheduler_
->BeginFrameDeadlineForTest();
382 scheduler_
->DidSwapBuffers();
384 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
386 scheduler_
->DidSwapBuffersComplete();
387 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
389 scheduler_
->DisplayResized();
390 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
392 scheduler_
->SetNewRootSurface(root_surface_id
);
393 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
395 scheduler_
->SurfaceDamaged(sid1
);
396 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
398 scheduler_
->SetRootSurfaceResourcesLocked(true);
399 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
401 scheduler_
->OutputSurfaceLost();
402 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());