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/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"
19 class FakeDisplaySchedulerClient
: public DisplaySchedulerClient
{
21 FakeDisplaySchedulerClient() : draw_and_swap_count_(0) {}
23 ~FakeDisplaySchedulerClient() override
{}
25 bool DrawAndSwap() override
{
26 draw_and_swap_count_
++;
30 void Reset() { draw_and_swap_count_
= 0; }
32 int draw_and_swap_count() const { return draw_and_swap_count_
; }
35 int draw_and_swap_count_
;
38 class TestDisplayScheduler
: public DisplayScheduler
{
40 TestDisplayScheduler(DisplaySchedulerClient
* client
,
41 BeginFrameSource
* begin_frame_source
,
42 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
,
43 int max_pending_swaps
)
44 : DisplayScheduler(client
,
48 scheduler_begin_frame_deadline_count_(0) {}
50 base::TimeTicks
DesiredBeginFrameDeadlineTimeForTest() {
51 return DesiredBeginFrameDeadlineTime();
54 void BeginFrameDeadlineForTest() { OnBeginFrameDeadline(); }
56 void ScheduleBeginFrameDeadline() override
{
57 scheduler_begin_frame_deadline_count_
++;
58 DisplayScheduler::ScheduleBeginFrameDeadline();
61 int scheduler_begin_frame_deadline_count() {
62 return scheduler_begin_frame_deadline_count_
;
66 int scheduler_begin_frame_deadline_count_
;
69 class DisplaySchedulerTest
: public testing::Test
{
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
));
81 ~DisplaySchedulerTest() override
{}
83 void SetUp() override
{ scheduler_
->SetRootSurfaceResourcesLocked(false); }
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
));
96 TestNowSource
& now_src() { return *now_src_
; }
97 FakeDisplaySchedulerClient
& client() { return *client_
; }
98 DisplayScheduler
& scheduler() { return *scheduler_
; }
100 scoped_refptr
<TestNowSource
> now_src_
;
101 scoped_refptr
<base::NullTaskRunner
> null_task_runner_
;
103 FakeBeginFrameSource fake_begin_frame_source_
;
104 scoped_ptr
<FakeDisplaySchedulerClient
> client_
;
105 scoped_ptr
<TestDisplayScheduler
> scheduler_
;
108 TEST_F(DisplaySchedulerTest
, EntireDisplayDamagedDrawsImmediately
) {
109 SurfaceId
root_surface_id(1);
111 EXPECT_LT(now_src().Now(),
112 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
113 scheduler_
->EntireDisplayDamaged(root_surface_id
);
114 EXPECT_GE(now_src().Now(),
115 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
118 TEST_F(DisplaySchedulerTest
, SurfaceDamaged
) {
119 SurfaceId
root_surface_id(0);
123 // Set the root surface
124 scheduler_
->EntireDisplayDamaged(root_surface_id
);
126 // Get scheduler to detect surface 1 as active by drawing
127 // two frames in a row with damage from surface 1.
129 scheduler_
->SurfaceDamaged(sid1
);
130 scheduler_
->BeginFrameDeadlineForTest();
132 scheduler_
->SurfaceDamaged(sid1
);
133 scheduler_
->BeginFrameDeadlineForTest();
135 // Damage only from surface 2 (inactive) does not trigger deadline early.
137 scheduler_
->SurfaceDamaged(sid2
);
138 EXPECT_LT(now_src().Now(),
139 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
141 // Damage from surface 1 triggers deadline early.
142 scheduler_
->SurfaceDamaged(sid1
);
143 EXPECT_GE(now_src().Now(),
144 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
145 scheduler_
->BeginFrameDeadlineForTest();
147 // Make both surface 1 and 2 active.
149 scheduler_
->SurfaceDamaged(sid2
);
150 scheduler_
->SurfaceDamaged(sid1
);
151 scheduler_
->BeginFrameDeadlineForTest();
153 // Deadline doesn't trigger early until surface 1 and 2 are both damaged.
155 EXPECT_LT(now_src().Now(),
156 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
157 scheduler_
->SurfaceDamaged(sid1
);
158 EXPECT_LT(now_src().Now(),
159 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
160 scheduler_
->SurfaceDamaged(sid2
);
161 EXPECT_GE(now_src().Now(),
162 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
163 scheduler_
->BeginFrameDeadlineForTest();
165 // Make the system idle
167 scheduler_
->BeginFrameDeadlineForTest();
169 scheduler_
->BeginFrameDeadlineForTest();
171 // Deadline should trigger early if child surfaces are idle and
172 // we get damage on the root surface.
174 EXPECT_LT(now_src().Now(),
175 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
176 scheduler_
->SurfaceDamaged(root_surface_id
);
177 EXPECT_GE(now_src().Now(),
178 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
179 scheduler_
->BeginFrameDeadlineForTest();
182 TEST_F(DisplaySchedulerTest
, OutputSurfaceLost
) {
185 // DrawAndSwap normally.
187 EXPECT_LT(now_src().Now(),
188 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
189 EXPECT_EQ(0, client_
->draw_and_swap_count());
190 scheduler_
->SurfaceDamaged(sid1
);
191 scheduler_
->BeginFrameDeadlineForTest();
192 EXPECT_EQ(1, client_
->draw_and_swap_count());
194 // Deadline triggers immediately on OutputSurfaceLost.
196 EXPECT_LT(now_src().Now(),
197 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
198 scheduler_
->OutputSurfaceLost();
199 EXPECT_GE(now_src().Now(),
200 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
202 // Deadline does not DrawAndSwap after OutputSurfaceLost.
203 EXPECT_EQ(1, client_
->draw_and_swap_count());
204 scheduler_
->SurfaceDamaged(sid1
);
205 scheduler_
->BeginFrameDeadlineForTest();
206 EXPECT_EQ(1, client_
->draw_and_swap_count());
209 TEST_F(DisplaySchedulerTest
, RootSurfaceResourcesLocked
) {
211 base::TimeTicks late_deadline
;
213 // DrawAndSwap normally.
215 EXPECT_LT(now_src().Now(),
216 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
217 EXPECT_EQ(0, client_
->draw_and_swap_count());
218 scheduler_
->SurfaceDamaged(sid1
);
219 scheduler_
->BeginFrameDeadlineForTest();
220 EXPECT_EQ(1, client_
->draw_and_swap_count());
222 // Deadline triggers late while root resources are locked.
223 late_deadline
= now_src().Now() + BeginFrameArgs::DefaultInterval();
225 scheduler_
->SurfaceDamaged(sid1
);
226 EXPECT_GT(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
227 scheduler_
->SetRootSurfaceResourcesLocked(true);
228 EXPECT_EQ(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
230 // Deadline does not DrawAndSwap while root resources are locked.
231 EXPECT_EQ(1, client_
->draw_and_swap_count());
232 scheduler_
->SurfaceDamaged(sid1
);
233 scheduler_
->BeginFrameDeadlineForTest();
234 EXPECT_EQ(1, client_
->draw_and_swap_count());
236 // Deadline triggers normally when root resources are unlocked.
237 late_deadline
= now_src().Now() + BeginFrameArgs::DefaultInterval();
239 scheduler_
->SurfaceDamaged(sid1
);
240 EXPECT_EQ(late_deadline
, scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
241 scheduler_
->SetRootSurfaceResourcesLocked(false);
242 EXPECT_EQ(base::TimeTicks(),
243 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
245 EXPECT_EQ(1, client_
->draw_and_swap_count());
246 scheduler_
->BeginFrameDeadlineForTest();
247 EXPECT_EQ(2, client_
->draw_and_swap_count());
250 TEST_F(DisplaySchedulerTest
, DidSwapBuffers
) {
253 base::TimeTicks late_deadline
;
255 // Get scheduler to detect surface 1 and 2 as active.
257 scheduler_
->SurfaceDamaged(sid1
);
258 scheduler_
->SurfaceDamaged(sid2
);
259 scheduler_
->BeginFrameDeadlineForTest();
261 scheduler_
->SurfaceDamaged(sid1
);
262 scheduler_
->SurfaceDamaged(sid2
);
263 scheduler_
->BeginFrameDeadlineForTest();
265 // DrawAndSwap normally.
267 EXPECT_LT(now_src().Now(),
268 scheduler_
->DesiredBeginFrameDeadlineTimeForTest());
269 EXPECT_EQ(2, client_
->draw_and_swap_count());
270 scheduler_
->SurfaceDamaged(sid1
);
271 scheduler_
->SurfaceDamaged(sid2
);
272 scheduler_
->BeginFrameDeadlineForTest();
273 EXPECT_EQ(3, client_
->draw_and_swap_count());
274 scheduler_
->DidSwapBuffers();
276 // Deadline triggers early when swap throttled.
278 // Damage surface 1, but not surface 2 so we avoid triggering deadline
279 // early because all surfaces are ready.
280 scheduler_
->SurfaceDamaged(sid1
);
281 EXPECT_EQ(scheduler_
->DesiredBeginFrameDeadlineTimeForTest(),
284 // Don't draw and swap in deadline while swap throttled.
285 EXPECT_EQ(3, client_
->draw_and_swap_count());
286 scheduler_
->BeginFrameDeadlineForTest();
287 EXPECT_EQ(3, client_
->draw_and_swap_count());
289 // Deadline triggers normally once not swap throttled.
290 // Damage from previous BeginFrame should cary over, so don't damage again.
291 late_deadline
= now_src().Now() + BeginFrameArgs::DefaultInterval();
292 scheduler_
->DidSwapBuffersComplete();
294 EXPECT_GT(scheduler_
->DesiredBeginFrameDeadlineTimeForTest(),
296 EXPECT_LT(scheduler_
->DesiredBeginFrameDeadlineTimeForTest(), late_deadline
);
297 // Still waiting for surface 2. Once it updates, deadline should trigger
298 // immediately again.
299 scheduler_
->SurfaceDamaged(sid2
);
300 EXPECT_EQ(scheduler_
->DesiredBeginFrameDeadlineTimeForTest(),
302 // Draw and swap now that we aren't throttled.
303 EXPECT_EQ(3, client_
->draw_and_swap_count());
304 scheduler_
->BeginFrameDeadlineForTest();
305 EXPECT_EQ(4, client_
->draw_and_swap_count());
308 // This test verfies that we try to reschedule the deadline
309 // after any event that may change what deadline we want.
310 TEST_F(DisplaySchedulerTest
, ScheduleBeginFrameDeadline
) {
311 SurfaceId
root_surface_id(1);
314 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
317 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
319 scheduler_
->BeginFrameDeadlineForTest();
320 scheduler_
->DidSwapBuffers();
322 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
324 scheduler_
->DidSwapBuffersComplete();
325 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
327 scheduler_
->EntireDisplayDamaged(root_surface_id
);
328 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
330 scheduler_
->SurfaceDamaged(sid1
);
331 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
333 scheduler_
->SetRootSurfaceResourcesLocked(true);
334 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());
336 scheduler_
->OutputSurfaceLost();
337 EXPECT_EQ(count
++, scheduler_
->scheduler_begin_frame_deadline_count());