• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 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/scheduler/frame_rate_controller.h"
6 
7 #include "base/test/test_simple_task_runner.h"
8 #include "cc/test/scheduler_test_common.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace cc {
12 namespace {
13 
14 class FakeFrameRateControllerClient : public FrameRateControllerClient {
15  public:
FakeFrameRateControllerClient()16   FakeFrameRateControllerClient() { Reset(); }
17 
Reset()18   void Reset() { frame_count_ = 0; }
BeganFrame() const19   bool BeganFrame() const { return frame_count_ > 0; }
frame_count() const20   int frame_count() const { return frame_count_; }
21 
FrameRateControllerTick(bool throttled,const BeginFrameArgs & args)22   virtual void FrameRateControllerTick(
23       bool throttled, const BeginFrameArgs& args) OVERRIDE {
24     frame_count_ += throttled ? 0 : 1;
25   }
26 
27  protected:
28   int frame_count_;
29 };
30 
TEST(FrameRateControllerTest,TestFrameThrottling_ImmediateAck)31 TEST(FrameRateControllerTest, TestFrameThrottling_ImmediateAck) {
32   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
33       new base::TestSimpleTaskRunner;
34   FakeFrameRateControllerClient client;
35   base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
36       base::Time::kMicrosecondsPerSecond / 60);
37   scoped_refptr<FakeDelayBasedTimeSource> time_source =
38       FakeDelayBasedTimeSource::Create(interval, task_runner.get());
39   FrameRateController controller(time_source);
40 
41   controller.SetClient(&client);
42   controller.SetActive(true);
43 
44   base::TimeTicks elapsed;  // Muck around with time a bit
45 
46   // Trigger one frame, make sure the BeginFrame callback is called
47   elapsed += task_runner->NextPendingTaskDelay();
48   time_source->SetNow(elapsed);
49   task_runner->RunPendingTasks();
50   EXPECT_TRUE(client.BeganFrame());
51   client.Reset();
52 
53   // Tell the controller we drew
54   controller.DidSwapBuffers();
55 
56   // Tell the controller the frame ended 5ms later
57   time_source->SetNow(time_source->Now() +
58                       base::TimeDelta::FromMilliseconds(5));
59   controller.DidSwapBuffersComplete();
60 
61   // Trigger another frame, make sure BeginFrame runs again
62   elapsed += task_runner->NextPendingTaskDelay();
63   // Sanity check that previous code didn't move time backward.
64   EXPECT_GE(elapsed, time_source->Now());
65   time_source->SetNow(elapsed);
66   task_runner->RunPendingTasks();
67   EXPECT_TRUE(client.BeganFrame());
68 }
69 
TEST(FrameRateControllerTest,TestFrameThrottling_TwoFramesInFlight)70 TEST(FrameRateControllerTest, TestFrameThrottling_TwoFramesInFlight) {
71   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
72       new base::TestSimpleTaskRunner;
73   FakeFrameRateControllerClient client;
74   base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
75       base::Time::kMicrosecondsPerSecond / 60);
76   scoped_refptr<FakeDelayBasedTimeSource> time_source =
77       FakeDelayBasedTimeSource::Create(interval, task_runner.get());
78   FrameRateController controller(time_source);
79 
80   controller.SetClient(&client);
81   controller.SetActive(true);
82   controller.SetMaxSwapsPending(2);
83 
84   base::TimeTicks elapsed;  // Muck around with time a bit
85 
86   // Trigger one frame, make sure the BeginFrame callback is called
87   elapsed += task_runner->NextPendingTaskDelay();
88   time_source->SetNow(elapsed);
89   task_runner->RunPendingTasks();
90   EXPECT_TRUE(client.BeganFrame());
91   client.Reset();
92 
93   // Tell the controller we drew
94   controller.DidSwapBuffers();
95 
96   // Trigger another frame, make sure BeginFrame callback runs again
97   elapsed += task_runner->NextPendingTaskDelay();
98   // Sanity check that previous code didn't move time backward.
99   EXPECT_GE(elapsed, time_source->Now());
100   time_source->SetNow(elapsed);
101   task_runner->RunPendingTasks();
102   EXPECT_TRUE(client.BeganFrame());
103   client.Reset();
104 
105   // Tell the controller we drew, again.
106   controller.DidSwapBuffers();
107 
108   // Trigger another frame. Since two frames are pending, we should not draw.
109   elapsed += task_runner->NextPendingTaskDelay();
110   // Sanity check that previous code didn't move time backward.
111   EXPECT_GE(elapsed, time_source->Now());
112   time_source->SetNow(elapsed);
113   task_runner->RunPendingTasks();
114   EXPECT_FALSE(client.BeganFrame());
115 
116   // Tell the controller the first frame ended 5ms later
117   time_source->SetNow(time_source->Now() +
118                       base::TimeDelta::FromMilliseconds(5));
119   controller.DidSwapBuffersComplete();
120 
121   // Tick should not have been called
122   EXPECT_FALSE(client.BeganFrame());
123 
124   // Trigger yet another frame. Since one frames is pending, another
125   // BeginFrame callback should run.
126   elapsed += task_runner->NextPendingTaskDelay();
127   // Sanity check that previous code didn't move time backward.
128   EXPECT_GE(elapsed, time_source->Now());
129   time_source->SetNow(elapsed);
130   task_runner->RunPendingTasks();
131   EXPECT_TRUE(client.BeganFrame());
132 }
133 
TEST(FrameRateControllerTest,TestFrameThrottling_Unthrottled)134 TEST(FrameRateControllerTest, TestFrameThrottling_Unthrottled) {
135   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
136       new base::TestSimpleTaskRunner;
137   FakeFrameRateControllerClient client;
138   FrameRateController controller(task_runner.get());
139 
140   controller.SetClient(&client);
141   controller.SetMaxSwapsPending(2);
142 
143   // SetActive triggers 1st frame, make sure the BeginFrame callback
144   // is called
145   controller.SetActive(true);
146   task_runner->RunPendingTasks();
147   EXPECT_TRUE(client.BeganFrame());
148   client.Reset();
149 
150   // Even if we don't call DidSwapBuffers, FrameRateController should
151   // still attempt to tick multiple times until it does result in
152   // a DidSwapBuffers.
153   task_runner->RunPendingTasks();
154   EXPECT_TRUE(client.BeganFrame());
155   client.Reset();
156 
157   task_runner->RunPendingTasks();
158   EXPECT_TRUE(client.BeganFrame());
159   client.Reset();
160 
161   // DidSwapBuffers triggers 2nd frame, make sure the BeginFrame callback is
162   // called
163   controller.DidSwapBuffers();
164   task_runner->RunPendingTasks();
165   EXPECT_TRUE(client.BeganFrame());
166   client.Reset();
167 
168   // DidSwapBuffers triggers 3rd frame (> max_frames_pending),
169   // make sure the BeginFrame callback is NOT called
170   controller.DidSwapBuffers();
171   task_runner->RunPendingTasks();
172   EXPECT_FALSE(client.BeganFrame());
173   client.Reset();
174 
175   // Make sure there is no pending task since we can't do anything until we
176   // receive a DidSwapBuffersComplete anyway.
177   EXPECT_FALSE(task_runner->HasPendingTask());
178 
179   // DidSwapBuffersComplete triggers a frame, make sure the BeginFrame
180   // callback is called
181   controller.DidSwapBuffersComplete();
182   task_runner->RunPendingTasks();
183   EXPECT_TRUE(client.BeganFrame());
184 }
185 
TEST(FrameRateControllerTest,TestFrameThrottling_NoDoubleTicking)186 TEST(FrameRateControllerTest, TestFrameThrottling_NoDoubleTicking) {
187   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
188       new base::TestSimpleTaskRunner;
189   FakeFrameRateControllerClient client;
190   FrameRateController controller(task_runner.get());
191   controller.SetClient(&client);
192 
193   // SetActive triggers 1st frame and queues another tick task since the time
194   // source isn't throttling.
195   controller.SetActive(true);
196   task_runner->RunPendingTasks();
197   EXPECT_TRUE(client.BeganFrame());
198   client.Reset();
199   EXPECT_TRUE(task_runner->HasPendingTask());
200 
201   // Simulate a frame swap. This shouldn't queue a second tick task.
202   controller.DidSwapBuffers();
203   controller.DidSwapBuffersComplete();
204 
205   // The client should only be ticked once.
206   task_runner->RunPendingTasks();
207   EXPECT_EQ(1, client.frame_count());
208 }
209 
210 }  // namespace
211 }  // namespace cc
212