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: 16 FakeFrameRateControllerClient() { Reset(); } 17 18 void Reset() { frame_count_ = 0; } 19 bool BeganFrame() const { return frame_count_ > 0; } 20 int frame_count() const { return frame_count_; } 21 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 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 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 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 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