| // Copyright 2015 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/surfaces/display_scheduler.h" |
| |
| #include "base/logging.h" |
| #include "base/test/null_task_runner.h" |
| #include "base/test/simple_test_tick_clock.h" |
| #include "base/trace_event/trace_event.h" |
| #include "cc/output/begin_frame_args.h" |
| #include "cc/surfaces/display.h" |
| #include "cc/test/fake_external_begin_frame_source.h" |
| #include "cc/test/scheduler_test_common.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace cc { |
| namespace { |
| |
| const int kMaxPendingSwaps = 1; |
| |
| static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1); |
| |
| class FakeDisplaySchedulerClient : public DisplaySchedulerClient { |
| public: |
| FakeDisplaySchedulerClient() : draw_and_swap_count_(0) {} |
| |
| ~FakeDisplaySchedulerClient() override {} |
| |
| bool DrawAndSwap() override { |
| draw_and_swap_count_++; |
| return true; |
| } |
| |
| void Reset() { draw_and_swap_count_ = 0; } |
| |
| int draw_and_swap_count() const { return draw_and_swap_count_; } |
| |
| protected: |
| int draw_and_swap_count_; |
| }; |
| |
| class TestDisplayScheduler : public DisplayScheduler { |
| public: |
| TestDisplayScheduler(BeginFrameSource* begin_frame_source, |
| base::SingleThreadTaskRunner* task_runner, |
| int max_pending_swaps) |
| : DisplayScheduler(task_runner, max_pending_swaps), |
| scheduler_begin_frame_deadline_count_(0) { |
| SetBeginFrameSource(begin_frame_source); |
| } |
| |
| base::TimeTicks DesiredBeginFrameDeadlineTimeForTest() { |
| return DesiredBeginFrameDeadlineTime(); |
| } |
| |
| void BeginFrameDeadlineForTest() { |
| // Ensure that any missed BeginFrames were handled by the scheduler. We need |
| // to run the scheduled task ourselves since the NullTaskRunner won't. |
| if (!missed_begin_frame_task_.IsCancelled()) |
| missed_begin_frame_task_.callback().Run(); |
| OnBeginFrameDeadline(); |
| } |
| |
| void ScheduleBeginFrameDeadline() override { |
| scheduler_begin_frame_deadline_count_++; |
| DisplayScheduler::ScheduleBeginFrameDeadline(); |
| } |
| |
| int scheduler_begin_frame_deadline_count() { |
| return scheduler_begin_frame_deadline_count_; |
| } |
| |
| bool inside_begin_frame_deadline_interval() { |
| return inside_begin_frame_deadline_interval_; |
| } |
| |
| protected: |
| int scheduler_begin_frame_deadline_count_; |
| }; |
| |
| class DisplaySchedulerTest : public testing::Test { |
| public: |
| DisplaySchedulerTest() |
| : fake_begin_frame_source_(0.f, false), |
| task_runner_(new base::NullTaskRunner), |
| scheduler_(&fake_begin_frame_source_, |
| task_runner_.get(), |
| kMaxPendingSwaps) { |
| now_src_.Advance(base::TimeDelta::FromMicroseconds(10000)); |
| scheduler_.SetClient(&client_); |
| } |
| |
| ~DisplaySchedulerTest() override {} |
| |
| void SetUp() override { scheduler_.SetRootSurfaceResourcesLocked(false); } |
| |
| void AdvanceTimeAndBeginFrameForTest() { |
| now_src_.Advance(base::TimeDelta::FromMicroseconds(10000)); |
| // FakeBeginFrameSource deals with |source_id| and |sequence_number|. |
| BeginFrameArgs args = fake_begin_frame_source_.CreateBeginFrameArgs( |
| BEGINFRAME_FROM_HERE, &now_src_); |
| fake_begin_frame_source_.TestOnBeginFrame(args); |
| } |
| |
| protected: |
| base::SimpleTestTickClock& now_src() { return now_src_; } |
| FakeDisplaySchedulerClient& client() { return client_; } |
| DisplayScheduler& scheduler() { return scheduler_; } |
| |
| FakeExternalBeginFrameSource fake_begin_frame_source_; |
| |
| base::SimpleTestTickClock now_src_; |
| scoped_refptr<base::NullTaskRunner> task_runner_; |
| FakeDisplaySchedulerClient client_; |
| TestDisplayScheduler scheduler_; |
| }; |
| |
| TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilNewRootSurface) { |
| SurfaceId root_surface_id1( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| SurfaceId root_surface_id2( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(2, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(3, base::UnguessableToken::Create())); |
| base::TimeTicks late_deadline; |
| |
| scheduler_.SetVisible(true); |
| |
| // Go trough an initial BeginFrame cycle with the root surface. |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SetNewRootSurface(root_surface_id1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Resize on the next begin frame cycle should cause the deadline to wait |
| // for a new root surface. |
| AdvanceTimeAndBeginFrameForTest(); |
| late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.DisplayResized(); |
| EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SetNewRootSurface(root_surface_id2); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Verify deadline goes back to normal after resize. |
| late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SurfaceDamaged(root_surface_id2); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| } |
| |
| TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilDamagedSurface) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(2, base::UnguessableToken::Create())); |
| base::TimeTicks late_deadline; |
| |
| scheduler_.SetVisible(true); |
| |
| // Go trough an initial BeginFrame cycle with the root surface. |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SetNewRootSurface(root_surface_id); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Resize on the next begin frame cycle should cause the deadline to wait |
| // for a new root surface. |
| AdvanceTimeAndBeginFrameForTest(); |
| late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.DisplayResized(); |
| EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SurfaceDamaged(root_surface_id); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Verify deadline goes back to normal after resize. |
| AdvanceTimeAndBeginFrameForTest(); |
| late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SurfaceDamaged(root_surface_id); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| } |
| |
| TEST_F(DisplaySchedulerTest, SurfaceDamaged) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| SurfaceId sid2(kArbitraryFrameSinkId, |
| LocalSurfaceId(2, base::UnguessableToken::Create())); |
| |
| scheduler_.SetVisible(true); |
| |
| // Set the root surface |
| scheduler_.SetNewRootSurface(root_surface_id); |
| |
| // Get scheduler to detect surface 1 as active by drawing |
| // two frames in a row with damage from surface 1. |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Damage only from surface 2 (inactive) does not trigger deadline early. |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SurfaceDamaged(sid2); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| |
| // Damage from surface 1 triggers deadline early. |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Make both surface 1 and 2 active. |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SurfaceDamaged(sid2); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Deadline doesn't trigger early until surface 1 and 2 are both damaged. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SurfaceDamaged(sid2); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // Make the system idle |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.BeginFrameDeadlineForTest(); |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_FALSE(scheduler_.inside_begin_frame_deadline_interval()); |
| |
| // Deadline should trigger early if child surfaces are idle and |
| // we get damage on the root surface. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_FALSE(scheduler_.inside_begin_frame_deadline_interval()); |
| scheduler_.SurfaceDamaged(root_surface_id); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| } |
| |
| TEST_F(DisplaySchedulerTest, OutputSurfaceLost) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| |
| scheduler_.SetVisible(true); |
| |
| // Set the root surface |
| scheduler_.SetNewRootSurface(root_surface_id); |
| |
| // DrawAndSwap normally. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| EXPECT_EQ(0, client_.draw_and_swap_count()); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| |
| // Deadline triggers immediately on OutputSurfaceLost. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.OutputSurfaceLost(); |
| EXPECT_GE(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| |
| // Deadline does not DrawAndSwap after OutputSurfaceLost. |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| } |
| |
| TEST_F(DisplaySchedulerTest, VisibleWithoutDamageNoTicks) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| |
| EXPECT_EQ(0u, fake_begin_frame_source_.num_observers()); |
| scheduler_.SetVisible(true); |
| |
| // When becoming visible, don't start listening for begin frames until there |
| // is some damage. |
| EXPECT_EQ(0u, fake_begin_frame_source_.num_observers()); |
| scheduler_.SetNewRootSurface(root_surface_id); |
| |
| EXPECT_EQ(1u, fake_begin_frame_source_.num_observers()); |
| } |
| |
| TEST_F(DisplaySchedulerTest, VisibleWithDamageTicks) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| |
| scheduler_.SetNewRootSurface(root_surface_id); |
| |
| // When there is damage, start listening for begin frames once becoming |
| // visible. |
| EXPECT_EQ(0u, fake_begin_frame_source_.num_observers()); |
| scheduler_.SetVisible(true); |
| |
| EXPECT_EQ(1u, fake_begin_frame_source_.num_observers()); |
| } |
| |
| TEST_F(DisplaySchedulerTest, Visibility) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| |
| scheduler_.SetNewRootSurface(root_surface_id); |
| scheduler_.SetVisible(true); |
| EXPECT_EQ(1u, fake_begin_frame_source_.num_observers()); |
| |
| // DrawAndSwap normally. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| EXPECT_EQ(0, client_.draw_and_swap_count()); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| |
| // Become not visible. |
| scheduler_.SetVisible(false); |
| |
| // It will stop listening for begin frames after the current deadline. |
| EXPECT_EQ(1u, fake_begin_frame_source_.num_observers()); |
| |
| // Deadline does not DrawAndSwap when not visible. |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| // Now it stops listening for begin frames. |
| EXPECT_EQ(0u, fake_begin_frame_source_.num_observers()); |
| |
| // Does not start listening for begin frames when becoming visible without |
| // damage. |
| scheduler_.SetVisible(true); |
| EXPECT_EQ(0u, fake_begin_frame_source_.num_observers()); |
| scheduler_.SetVisible(false); |
| |
| // Does not start listening for begin frames when damage arrives. |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_EQ(0u, fake_begin_frame_source_.num_observers()); |
| |
| // But does when becoming visible with damage again. |
| scheduler_.SetVisible(true); |
| EXPECT_EQ(1u, fake_begin_frame_source_.num_observers()); |
| } |
| |
| TEST_F(DisplaySchedulerTest, ResizeCausesSwap) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| |
| scheduler_.SetVisible(true); |
| |
| // Set the root surface |
| scheduler_.SetNewRootSurface(root_surface_id); |
| |
| // DrawAndSwap normally. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| EXPECT_EQ(0, client_.draw_and_swap_count()); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| |
| scheduler_.DisplayResized(); |
| AdvanceTimeAndBeginFrameForTest(); |
| // DisplayResized should trigger a swap to happen. |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(2, client_.draw_and_swap_count()); |
| } |
| |
| TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| base::TimeTicks late_deadline; |
| |
| scheduler_.SetVisible(true); |
| |
| // Set the root surface |
| scheduler_.SetNewRootSurface(root_surface_id); |
| |
| // DrawAndSwap normally. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| EXPECT_EQ(0, client_.draw_and_swap_count()); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| |
| // Deadline triggers late while root resources are locked. |
| AdvanceTimeAndBeginFrameForTest(); |
| late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SetRootSurfaceResourcesLocked(true); |
| EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| |
| // Deadline does not DrawAndSwap while root resources are locked. |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| |
| // Deadline triggers normally when root resources are unlocked. |
| AdvanceTimeAndBeginFrameForTest(); |
| late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| scheduler_.SetRootSurfaceResourcesLocked(false); |
| scheduler_.SurfaceDamaged(root_surface_id); |
| EXPECT_EQ(base::TimeTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| |
| EXPECT_EQ(1, client_.draw_and_swap_count()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(2, client_.draw_and_swap_count()); |
| } |
| |
| TEST_F(DisplaySchedulerTest, DidSwapBuffers) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(0, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| SurfaceId sid2(kArbitraryFrameSinkId, |
| LocalSurfaceId(2, base::UnguessableToken::Create())); |
| |
| scheduler_.SetVisible(true); |
| |
| // Set the root surface |
| scheduler_.SetNewRootSurface(root_surface_id); |
| |
| // Get scheduler to detect surface 1 and 2 as active. |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.SurfaceDamaged(sid2); |
| scheduler_.BeginFrameDeadlineForTest(); |
| AdvanceTimeAndBeginFrameForTest(); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.SurfaceDamaged(sid2); |
| scheduler_.BeginFrameDeadlineForTest(); |
| |
| // DrawAndSwap normally. |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_LT(now_src().NowTicks(), |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| EXPECT_EQ(2, client_.draw_and_swap_count()); |
| scheduler_.SurfaceDamaged(sid1); |
| scheduler_.SurfaceDamaged(sid2); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(3, client_.draw_and_swap_count()); |
| scheduler_.DidSwapBuffers(); |
| |
| // Deadline triggers late when swap throttled. |
| AdvanceTimeAndBeginFrameForTest(); |
| base::TimeTicks late_deadline = |
| now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); |
| // Damage surface 1, but not surface 2 so we avoid triggering deadline |
| // early because all surfaces are ready. |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| |
| // Don't draw and swap in deadline while swap throttled. |
| EXPECT_EQ(3, client_.draw_and_swap_count()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(3, client_.draw_and_swap_count()); |
| |
| // Deadline triggers normally once not swap throttled. |
| // Damage from previous BeginFrame should cary over, so don't damage again. |
| scheduler_.DidReceiveSwapBuffersAck(); |
| AdvanceTimeAndBeginFrameForTest(); |
| base::TimeTicks expected_deadline = |
| scheduler_.LastUsedBeginFrameArgs().deadline - |
| BeginFrameArgs::DefaultEstimatedParentDrawTime(); |
| EXPECT_EQ(expected_deadline, |
| scheduler_.DesiredBeginFrameDeadlineTimeForTest()); |
| // Still waiting for surface 2. Once it updates, deadline should trigger |
| // immediately again. |
| scheduler_.SurfaceDamaged(sid2); |
| EXPECT_EQ(scheduler_.DesiredBeginFrameDeadlineTimeForTest(), |
| base::TimeTicks()); |
| // Draw and swap now that we aren't throttled. |
| EXPECT_EQ(3, client_.draw_and_swap_count()); |
| scheduler_.BeginFrameDeadlineForTest(); |
| EXPECT_EQ(4, client_.draw_and_swap_count()); |
| } |
| |
| // This test verfies that we try to reschedule the deadline |
| // after any event that may change what deadline we want. |
| TEST_F(DisplaySchedulerTest, ScheduleBeginFrameDeadline) { |
| SurfaceId root_surface_id( |
| kArbitraryFrameSinkId, |
| LocalSurfaceId(1, base::UnguessableToken::Create())); |
| SurfaceId sid1(kArbitraryFrameSinkId, |
| LocalSurfaceId(2, base::UnguessableToken::Create())); |
| int count = 1; |
| EXPECT_EQ(count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.SetVisible(true); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.SetVisible(true); |
| EXPECT_EQ(count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.SetVisible(false); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| // Set the root surface while not visible. |
| scheduler_.SetNewRootSurface(root_surface_id); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.SetVisible(true); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| // Set the root surface while visible. |
| scheduler_.SetNewRootSurface(root_surface_id); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.BeginFrameDeadlineForTest(); |
| scheduler_.DidSwapBuffers(); |
| AdvanceTimeAndBeginFrameForTest(); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.DidReceiveSwapBuffersAck(); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.DisplayResized(); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.SetNewRootSurface(root_surface_id); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.SurfaceDamaged(sid1); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.SetRootSurfaceResourcesLocked(true); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| |
| scheduler_.OutputSurfaceLost(); |
| EXPECT_EQ(++count, scheduler_.scheduler_begin_frame_deadline_count()); |
| } |
| |
| } // namespace |
| } // namespace cc |