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 cc::FrameRateControllerClient { 15 public: 16 FakeFrameRateControllerClient() { Reset(); } 17 18 void Reset() { began_frame_ = false; } 19 bool BeganFrame() const { return began_frame_; } 20 21 virtual void FrameRateControllerTick( 22 bool throttled, const BeginFrameArgs& args) OVERRIDE { 23 began_frame_ = !throttled; 24 } 25 26 protected: 27 bool began_frame_; 28 }; 29 30 TEST(FrameRateControllerTest, TestFrameThrottling_ImmediateAck) { 31 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 32 new base::TestSimpleTaskRunner; 33 FakeFrameRateControllerClient client; 34 base::TimeDelta interval = base::TimeDelta::FromMicroseconds( 35 base::Time::kMicrosecondsPerSecond / 60); 36 scoped_refptr<FakeDelayBasedTimeSource> time_source = 37 FakeDelayBasedTimeSource::Create(interval, task_runner.get()); 38 FrameRateController controller(time_source); 39 40 controller.SetClient(&client); 41 controller.SetActive(true); 42 43 base::TimeTicks elapsed; // Muck around with time a bit 44 45 // Trigger one frame, make sure the BeginFrame callback is called 46 elapsed += task_runner->NextPendingTaskDelay(); 47 time_source->SetNow(elapsed); 48 task_runner->RunPendingTasks(); 49 EXPECT_TRUE(client.BeganFrame()); 50 client.Reset(); 51 52 // Tell the controller we drew 53 controller.DidSwapBuffers(); 54 55 // Tell the controller the frame ended 5ms later 56 time_source->SetNow(time_source->Now() + 57 base::TimeDelta::FromMilliseconds(5)); 58 controller.DidSwapBuffersComplete(); 59 60 // Trigger another frame, make sure BeginFrame runs again 61 elapsed += task_runner->NextPendingTaskDelay(); 62 // Sanity check that previous code didn't move time backward. 63 EXPECT_GE(elapsed, time_source->Now()); 64 time_source->SetNow(elapsed); 65 task_runner->RunPendingTasks(); 66 EXPECT_TRUE(client.BeganFrame()); 67 } 68 69 TEST(FrameRateControllerTest, TestFrameThrottling_TwoFramesInFlight) { 70 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 71 new base::TestSimpleTaskRunner; 72 FakeFrameRateControllerClient client; 73 base::TimeDelta interval = base::TimeDelta::FromMicroseconds( 74 base::Time::kMicrosecondsPerSecond / 60); 75 scoped_refptr<FakeDelayBasedTimeSource> time_source = 76 FakeDelayBasedTimeSource::Create(interval, task_runner.get()); 77 FrameRateController controller(time_source); 78 79 controller.SetClient(&client); 80 controller.SetActive(true); 81 controller.SetMaxSwapsPending(2); 82 83 base::TimeTicks elapsed; // Muck around with time a bit 84 85 // Trigger one frame, make sure the BeginFrame callback is called 86 elapsed += task_runner->NextPendingTaskDelay(); 87 time_source->SetNow(elapsed); 88 task_runner->RunPendingTasks(); 89 EXPECT_TRUE(client.BeganFrame()); 90 client.Reset(); 91 92 // Tell the controller we drew 93 controller.DidSwapBuffers(); 94 95 // Trigger another frame, make sure BeginFrame callback runs again 96 elapsed += task_runner->NextPendingTaskDelay(); 97 // Sanity check that previous code didn't move time backward. 98 EXPECT_GE(elapsed, time_source->Now()); 99 time_source->SetNow(elapsed); 100 task_runner->RunPendingTasks(); 101 EXPECT_TRUE(client.BeganFrame()); 102 client.Reset(); 103 104 // Tell the controller we drew, again. 105 controller.DidSwapBuffers(); 106 107 // Trigger another frame. Since two frames are pending, we should not draw. 108 elapsed += task_runner->NextPendingTaskDelay(); 109 // Sanity check that previous code didn't move time backward. 110 EXPECT_GE(elapsed, time_source->Now()); 111 time_source->SetNow(elapsed); 112 task_runner->RunPendingTasks(); 113 EXPECT_FALSE(client.BeganFrame()); 114 115 // Tell the controller the first frame ended 5ms later 116 time_source->SetNow(time_source->Now() + 117 base::TimeDelta::FromMilliseconds(5)); 118 controller.DidSwapBuffersComplete(); 119 120 // Tick should not have been called 121 EXPECT_FALSE(client.BeganFrame()); 122 123 // Trigger yet another frame. Since one frames is pending, another 124 // BeginFrame callback should run. 125 elapsed += task_runner->NextPendingTaskDelay(); 126 // Sanity check that previous code didn't move time backward. 127 EXPECT_GE(elapsed, time_source->Now()); 128 time_source->SetNow(elapsed); 129 task_runner->RunPendingTasks(); 130 EXPECT_TRUE(client.BeganFrame()); 131 } 132 133 TEST(FrameRateControllerTest, TestFrameThrottling_Unthrottled) { 134 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 135 new base::TestSimpleTaskRunner; 136 FakeFrameRateControllerClient client; 137 FrameRateController controller(task_runner.get()); 138 139 controller.SetClient(&client); 140 controller.SetMaxSwapsPending(2); 141 142 // SetActive triggers 1st frame, make sure the BeginFrame callback 143 // is called 144 controller.SetActive(true); 145 task_runner->RunPendingTasks(); 146 EXPECT_TRUE(client.BeganFrame()); 147 client.Reset(); 148 149 // Even if we don't call DidSwapBuffers, FrameRateController should 150 // still attempt to tick multiple times until it does result in 151 // a DidSwapBuffers. 152 task_runner->RunPendingTasks(); 153 EXPECT_TRUE(client.BeganFrame()); 154 client.Reset(); 155 156 task_runner->RunPendingTasks(); 157 EXPECT_TRUE(client.BeganFrame()); 158 client.Reset(); 159 160 // DidSwapBuffers triggers 2nd frame, make sure the BeginFrame callback is 161 // called 162 controller.DidSwapBuffers(); 163 task_runner->RunPendingTasks(); 164 EXPECT_TRUE(client.BeganFrame()); 165 client.Reset(); 166 167 // DidSwapBuffers triggers 3rd frame (> max_frames_pending), 168 // make sure the BeginFrame callback is NOT called 169 controller.DidSwapBuffers(); 170 task_runner->RunPendingTasks(); 171 EXPECT_FALSE(client.BeganFrame()); 172 client.Reset(); 173 174 // Make sure there is no pending task since we can't do anything until we 175 // receive a DidSwapBuffersComplete anyway. 176 EXPECT_FALSE(task_runner->HasPendingTask()); 177 178 // DidSwapBuffersComplete triggers a frame, make sure the BeginFrame 179 // callback is called 180 controller.DidSwapBuffersComplete(); 181 task_runner->RunPendingTasks(); 182 EXPECT_TRUE(client.BeganFrame()); 183 } 184 185 } // namespace 186 } // namespace cc 187