| // Copyright 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/scheduler/frame_rate_controller.h" |
| |
| #include "base/test/test_simple_task_runner.h" |
| #include "cc/test/scheduler_test_common.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace cc { |
| namespace { |
| |
| class FakeFrameRateControllerClient : public cc::FrameRateControllerClient { |
| public: |
| FakeFrameRateControllerClient() { Reset(); } |
| |
| void Reset() { began_frame_ = false; } |
| bool BeganFrame() const { return began_frame_; } |
| |
| virtual void FrameRateControllerTick( |
| bool throttled, const BeginFrameArgs& args) OVERRIDE { |
| began_frame_ = !throttled; |
| } |
| |
| protected: |
| bool began_frame_; |
| }; |
| |
| TEST(FrameRateControllerTest, TestFrameThrottling_ImmediateAck) { |
| scoped_refptr<base::TestSimpleTaskRunner> task_runner = |
| new base::TestSimpleTaskRunner; |
| FakeFrameRateControllerClient client; |
| base::TimeDelta interval = base::TimeDelta::FromMicroseconds( |
| base::Time::kMicrosecondsPerSecond / 60); |
| scoped_refptr<FakeDelayBasedTimeSource> time_source = |
| FakeDelayBasedTimeSource::Create(interval, task_runner.get()); |
| FrameRateController controller(time_source); |
| |
| controller.SetClient(&client); |
| controller.SetActive(true); |
| |
| base::TimeTicks elapsed; // Muck around with time a bit |
| |
| // Trigger one frame, make sure the BeginFrame callback is called |
| elapsed += task_runner->NextPendingTaskDelay(); |
| time_source->SetNow(elapsed); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| client.Reset(); |
| |
| // Tell the controller we drew |
| controller.DidSwapBuffers(); |
| |
| // Tell the controller the frame ended 5ms later |
| time_source->SetNow(time_source->Now() + |
| base::TimeDelta::FromMilliseconds(5)); |
| controller.DidSwapBuffersComplete(); |
| |
| // Trigger another frame, make sure BeginFrame runs again |
| elapsed += task_runner->NextPendingTaskDelay(); |
| // Sanity check that previous code didn't move time backward. |
| EXPECT_GE(elapsed, time_source->Now()); |
| time_source->SetNow(elapsed); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| } |
| |
| TEST(FrameRateControllerTest, TestFrameThrottling_TwoFramesInFlight) { |
| scoped_refptr<base::TestSimpleTaskRunner> task_runner = |
| new base::TestSimpleTaskRunner; |
| FakeFrameRateControllerClient client; |
| base::TimeDelta interval = base::TimeDelta::FromMicroseconds( |
| base::Time::kMicrosecondsPerSecond / 60); |
| scoped_refptr<FakeDelayBasedTimeSource> time_source = |
| FakeDelayBasedTimeSource::Create(interval, task_runner.get()); |
| FrameRateController controller(time_source); |
| |
| controller.SetClient(&client); |
| controller.SetActive(true); |
| controller.SetMaxSwapsPending(2); |
| |
| base::TimeTicks elapsed; // Muck around with time a bit |
| |
| // Trigger one frame, make sure the BeginFrame callback is called |
| elapsed += task_runner->NextPendingTaskDelay(); |
| time_source->SetNow(elapsed); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| client.Reset(); |
| |
| // Tell the controller we drew |
| controller.DidSwapBuffers(); |
| |
| // Trigger another frame, make sure BeginFrame callback runs again |
| elapsed += task_runner->NextPendingTaskDelay(); |
| // Sanity check that previous code didn't move time backward. |
| EXPECT_GE(elapsed, time_source->Now()); |
| time_source->SetNow(elapsed); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| client.Reset(); |
| |
| // Tell the controller we drew, again. |
| controller.DidSwapBuffers(); |
| |
| // Trigger another frame. Since two frames are pending, we should not draw. |
| elapsed += task_runner->NextPendingTaskDelay(); |
| // Sanity check that previous code didn't move time backward. |
| EXPECT_GE(elapsed, time_source->Now()); |
| time_source->SetNow(elapsed); |
| task_runner->RunPendingTasks(); |
| EXPECT_FALSE(client.BeganFrame()); |
| |
| // Tell the controller the first frame ended 5ms later |
| time_source->SetNow(time_source->Now() + |
| base::TimeDelta::FromMilliseconds(5)); |
| controller.DidSwapBuffersComplete(); |
| |
| // Tick should not have been called |
| EXPECT_FALSE(client.BeganFrame()); |
| |
| // Trigger yet another frame. Since one frames is pending, another |
| // BeginFrame callback should run. |
| elapsed += task_runner->NextPendingTaskDelay(); |
| // Sanity check that previous code didn't move time backward. |
| EXPECT_GE(elapsed, time_source->Now()); |
| time_source->SetNow(elapsed); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| } |
| |
| TEST(FrameRateControllerTest, TestFrameThrottling_Unthrottled) { |
| scoped_refptr<base::TestSimpleTaskRunner> task_runner = |
| new base::TestSimpleTaskRunner; |
| FakeFrameRateControllerClient client; |
| FrameRateController controller(task_runner.get()); |
| |
| controller.SetClient(&client); |
| controller.SetMaxSwapsPending(2); |
| |
| // SetActive triggers 1st frame, make sure the BeginFrame callback |
| // is called |
| controller.SetActive(true); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| client.Reset(); |
| |
| // Even if we don't call DidSwapBuffers, FrameRateController should |
| // still attempt to tick multiple times until it does result in |
| // a DidSwapBuffers. |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| client.Reset(); |
| |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| client.Reset(); |
| |
| // DidSwapBuffers triggers 2nd frame, make sure the BeginFrame callback is |
| // called |
| controller.DidSwapBuffers(); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| client.Reset(); |
| |
| // DidSwapBuffers triggers 3rd frame (> max_frames_pending), |
| // make sure the BeginFrame callback is NOT called |
| controller.DidSwapBuffers(); |
| task_runner->RunPendingTasks(); |
| EXPECT_FALSE(client.BeganFrame()); |
| client.Reset(); |
| |
| // Make sure there is no pending task since we can't do anything until we |
| // receive a DidSwapBuffersComplete anyway. |
| EXPECT_FALSE(task_runner->HasPendingTask()); |
| |
| // DidSwapBuffersComplete triggers a frame, make sure the BeginFrame |
| // callback is called |
| controller.DidSwapBuffersComplete(); |
| task_runner->RunPendingTasks(); |
| EXPECT_TRUE(client.BeganFrame()); |
| } |
| |
| } // namespace |
| } // namespace cc |