diff options
Diffstat (limited to 'chromium/cc/scheduler/scheduler_unittest.cc')
-rw-r--r-- | chromium/cc/scheduler/scheduler_unittest.cc | 691 |
1 files changed, 572 insertions, 119 deletions
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc index 930111c1b2a..a1da822cff1 100644 --- a/chromium/cc/scheduler/scheduler_unittest.cc +++ b/chromium/cc/scheduler/scheduler_unittest.cc @@ -1,13 +1,13 @@ // 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/scheduler.h" #include <string> #include <vector> #include "base/logging.h" +#include "base/memory/scoped_vector.h" #include "cc/test/scheduler_test_common.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -28,6 +28,18 @@ namespace cc { namespace { +void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) { + scheduler->DidCreateAndInitializeOutputSurface(); + scheduler->SetNeedsCommit(); + scheduler->FinishCommit(); + // Go through the motions to draw the commit. + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); + // We need another BeginFrame so Scheduler calls SetNeedsBeginFrame(false). + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); +} + class FakeSchedulerClient : public SchedulerClient { public: FakeSchedulerClient() @@ -52,13 +64,17 @@ class FakeSchedulerClient : public SchedulerClient { int num_draws() const { return num_draws_; } int num_actions_() const { return static_cast<int>(actions_.size()); } const char* Action(int i) const { return actions_[i]; } - std::string StateForAction(int i) const { return states_[i]; } + base::Value& StateForAction(int i) const { return *states_[i]; } - bool HasAction(const char* action) const { + int ActionIndex(const char* action) const { for (size_t i = 0; i < actions_.size(); i++) if (!strcmp(actions_[i], action)) - return true; - return false; + return i; + return -1; + } + + bool HasAction(const char* action) const { + return ActionIndex(action) >= 0; } void SetDrawWillHappen(bool draw_will_happen) { @@ -71,48 +87,63 @@ class FakeSchedulerClient : public SchedulerClient { // Scheduler Implementation. virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE { actions_.push_back("SetNeedsBeginFrameOnImplThread"); - states_.push_back(scheduler_->StateAsStringForTesting()); + states_.push_back(scheduler_->StateAsValue().release()); needs_begin_frame_ = enable; } virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE { actions_.push_back("ScheduledActionSendBeginFrameToMainThread"); - states_.push_back(scheduler_->StateAsStringForTesting()); + states_.push_back(scheduler_->StateAsValue().release()); } - virtual ScheduledActionDrawAndSwapResult - ScheduledActionDrawAndSwapIfPossible() OVERRIDE { + virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() + OVERRIDE { actions_.push_back("ScheduledActionDrawAndSwapIfPossible"); - states_.push_back(scheduler_->StateAsStringForTesting()); + states_.push_back(scheduler_->StateAsValue().release()); num_draws_++; - return ScheduledActionDrawAndSwapResult(draw_will_happen_, - draw_will_happen_ && - swap_will_happen_if_draw_happens_); + bool did_readback = false; + return DrawSwapReadbackResult( + draw_will_happen_, + draw_will_happen_ && swap_will_happen_if_draw_happens_, + did_readback); } - virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced() - OVERRIDE { + virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE { actions_.push_back("ScheduledActionDrawAndSwapForced"); - states_.push_back(scheduler_->StateAsStringForTesting()); - return ScheduledActionDrawAndSwapResult(true, - swap_will_happen_if_draw_happens_); + states_.push_back(scheduler_->StateAsValue().release()); + bool did_draw = true; + bool did_swap = swap_will_happen_if_draw_happens_; + bool did_readback = false; + return DrawSwapReadbackResult(did_draw, did_swap, did_readback); + } + virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE { + actions_.push_back("ScheduledActionDrawAndReadback"); + states_.push_back(scheduler_->StateAsValue().release()); + bool did_draw = true; + bool did_swap = false; + bool did_readback = true; + return DrawSwapReadbackResult(did_draw, did_swap, did_readback); } virtual void ScheduledActionCommit() OVERRIDE { actions_.push_back("ScheduledActionCommit"); - states_.push_back(scheduler_->StateAsStringForTesting()); + states_.push_back(scheduler_->StateAsValue().release()); } virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE { actions_.push_back("ScheduledActionUpdateVisibleTiles"); - states_.push_back(scheduler_->StateAsStringForTesting()); + states_.push_back(scheduler_->StateAsValue().release()); } - virtual void ScheduledActionActivatePendingTreeIfNeeded() OVERRIDE { - actions_.push_back("ScheduledActionActivatePendingTreeIfNeeded"); - states_.push_back(scheduler_->StateAsStringForTesting()); + virtual void ScheduledActionActivatePendingTree() OVERRIDE { + actions_.push_back("ScheduledActionActivatePendingTree"); + states_.push_back(scheduler_->StateAsValue().release()); } virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE { actions_.push_back("ScheduledActionBeginOutputSurfaceCreation"); - states_.push_back(scheduler_->StateAsStringForTesting()); + states_.push_back(scheduler_->StateAsValue().release()); } virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE { actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread"); - states_.push_back(scheduler_->StateAsStringForTesting()); + states_.push_back(scheduler_->StateAsValue().release()); + } + virtual void ScheduledActionManageTiles() OVERRIDE { + actions_.push_back("ScheduledActionManageTiles"); + states_.push_back(scheduler_->StateAsValue().release()); } virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {} virtual base::TimeDelta DrawDurationEstimate() OVERRIDE { @@ -125,13 +156,21 @@ class FakeSchedulerClient : public SchedulerClient { return base::TimeDelta(); } + virtual void PostBeginFrameDeadline(const base::Closure& closure, + base::TimeTicks deadline) OVERRIDE { + actions_.push_back("PostBeginFrameDeadlineTask"); + states_.push_back(scheduler_->StateAsValue().release()); + } + + virtual void DidBeginFrameDeadlineOnImplThread() OVERRIDE {} + protected: bool needs_begin_frame_; bool draw_will_happen_; bool swap_will_happen_if_draw_happens_; int num_draws_; std::vector<const char*> actions_; - std::vector<std::string> states_; + ScopedVector<base::Value> states_; scoped_ptr<Scheduler> scheduler_; }; @@ -149,94 +188,205 @@ TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginFrame) { EXPECT_EQ(0, client.num_actions_()); } -TEST(SchedulerTest, RequestCommit) { +void RequestCommit(bool deadline_scheduling_enabled) { FakeSchedulerClient client; - SchedulerSettings default_scheduler_settings; - Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + SchedulerSettings scheduler_settings; + scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); - client.Reset(); - scheduler->DidCreateAndInitializeOutputSurface(); + InitializeOutputSurfaceAndFirstCommit(scheduler); - // SetNeedsCommit should begin the frame. + // SetNeedsCommit should begin the frame on the next BeginFrame. + client.Reset(); scheduler->SetNeedsCommit(); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_TRUE(client.needs_begin_frame()); + if (deadline_scheduling_enabled) { + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + } else { + EXPECT_EQ(client.num_actions_(), 2); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); + EXPECT_TRUE(client.HasAction("SetNeedsBeginFrameOnImplThread")); + } + client.Reset(); + + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (deadline_scheduling_enabled) { + EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + } else { + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + } + EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); + + // If we don't swap on the deadline, we need to request another BeginFrame. + scheduler->OnBeginFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); // FinishCommit should commit scheduler->FinishCommit(); - EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); - // BeginFrame should draw. + // BeginFrame should prepare the draw. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); + + // BeginFrame deadline should draw. + scheduler->OnBeginFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); + + // The following BeginFrame deadline should SetNeedsBeginFrame(false) to avoid + // excessive toggles. + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + client.Reset(); + + scheduler->OnBeginFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); EXPECT_FALSE(client.needs_begin_frame()); client.Reset(); } -TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread) { +TEST(SchedulerTest, RequestCommit) { + bool deadline_scheduling_enabled = false; + RequestCommit(deadline_scheduling_enabled); +} + +TEST(SchedulerTest, RequestCommit_Deadline) { + bool deadline_scheduling_enabled = true; + RequestCommit(deadline_scheduling_enabled); +} + +void RequestCommitAfterBeginFrameSentToMainThread( + bool deadline_scheduling_enabled) { FakeSchedulerClient client; - SchedulerSettings default_scheduler_settings; - Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + SchedulerSettings scheduler_settings; + scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); + InitializeOutputSurfaceAndFirstCommit(scheduler); client.Reset(); - scheduler->DidCreateAndInitializeOutputSurface(); - // SetNedsCommit should begin the frame. + // SetNeedsCommit should begin the frame. scheduler->SetNeedsCommit(); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + if (deadline_scheduling_enabled) { + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + } else { + EXPECT_EQ(client.num_actions_(), 2); + EXPECT_TRUE(client.HasAction("SetNeedsBeginFrameOnImplThread")); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); + } + + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (deadline_scheduling_enabled) { + EXPECT_EQ(client.num_actions_(), 2); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); + EXPECT_TRUE(client.HasAction("PostBeginFrameDeadlineTask")); + } else { + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + } + + EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); - // Now SetNeedsCommit again. Calling here means we need a second frame. + // Now SetNeedsCommit again. Calling here means we need a second commit. scheduler->SetNeedsCommit(); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 0, 1); + EXPECT_EQ(client.num_actions_(), 0); client.Reset(); - // Since another commit is needed, FinishCommit should commit, - // then begin another frame. + // Finish the first commit. scheduler->FinishCommit(); EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); client.Reset(); + scheduler->OnBeginFrameDeadline(); + if (deadline_scheduling_enabled) { + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); + EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + } else { + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3); + EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 3); + EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 2, 3); + } - // Tick should draw but then begin another frame. - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + // Because we just swapped, the Scheduler should also request the next + // BeginFrame from the OutputSurface. EXPECT_TRUE(client.needs_begin_frame()); - EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 2); client.Reset(); - // Go back to quiescent state and verify we no longer request BeginFrames. + // Since another commit is needed, the next BeginFrame should initiate + // the second commit. + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (deadline_scheduling_enabled) { + EXPECT_EQ(client.num_actions_(), 2); + EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginFrameToMainThread")); + EXPECT_TRUE(client.HasAction("PostBeginFrameDeadlineTask")); + } else { + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + } + client.Reset(); + + // Finishing the commit before the deadline should post a new deadline task + // to trigger the deadline early. scheduler->FinishCommit(); + EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); + EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); + + // On the next BeginFrame, verify we go back to a quiescent state and + // no longer request BeginFrames. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_FALSE(client.needs_begin_frame()); + client.Reset(); } -TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) { +TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread) { + bool deadline_scheduling_enabled = false; + RequestCommitAfterBeginFrameSentToMainThread(deadline_scheduling_enabled); +} + +TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread_Deadline) { + bool deadline_scheduling_enabled = true; + RequestCommitAfterBeginFrameSentToMainThread(deadline_scheduling_enabled); +} + +void TextureAcquisitionCausesCommitInsteadOfDraw( + bool deadline_scheduling_enabled) { FakeSchedulerClient client; - SchedulerSettings default_scheduler_settings; - Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + SchedulerSettings scheduler_settings; + scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); + InitializeOutputSurfaceAndFirstCommit(scheduler); client.Reset(); - scheduler->DidCreateAndInitializeOutputSurface(); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); @@ -244,9 +394,21 @@ TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) { client.Reset(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + client.Reset(); + scheduler->OnBeginFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); EXPECT_FALSE(scheduler->RedrawPending()); + EXPECT_TRUE(client.needs_begin_frame()); + + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(client.needs_begin_frame()); client.Reset(); @@ -264,54 +426,103 @@ TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) { // No draw happens since the textures are acquired by the main thread. client.Reset(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + client.Reset(); + scheduler->OnBeginFrameDeadline(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); scheduler->SetNeedsCommit(); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 0, 2); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 2); - EXPECT_TRUE(client.needs_begin_frame()); + if (deadline_scheduling_enabled) { + EXPECT_EQ(0, client.num_actions_()); + } else { + EXPECT_SINGLE_ACTION("ScheduledActionSendBeginFrameToMainThread", client); + } + + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (deadline_scheduling_enabled) { + EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + } else { + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + } // Commit will release the texture. client.Reset(); scheduler->FinishCommit(); - EXPECT_SINGLE_ACTION("ScheduledActionCommit", client); + EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); EXPECT_TRUE(scheduler->RedrawPending()); - EXPECT_TRUE(client.needs_begin_frame()); // Now we can draw again after the commit happens. client.Reset(); - scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); EXPECT_FALSE(scheduler->RedrawPending()); - EXPECT_FALSE(client.needs_begin_frame()); + EXPECT_TRUE(client.needs_begin_frame()); + + // Make sure we stop requesting BeginFrames if we don't swap. + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + EXPECT_FALSE(client.needs_begin_frame()); } -TEST(SchedulerTest, TextureAcquisitionCollision) { +TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) { + bool deadline_scheduling_enabled = false; + TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled); +} + +TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) { + bool deadline_scheduling_enabled = true; + TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled); +} + +void TextureAcquisitionCollision(bool deadline_scheduling_enabled) { FakeSchedulerClient client; - SchedulerSettings default_scheduler_settings; - Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + SchedulerSettings scheduler_settings; + scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client); - client.Reset(); - scheduler->DidCreateAndInitializeOutputSurface(); + InitializeOutputSurfaceAndFirstCommit(scheduler); + client.Reset(); scheduler->SetNeedsCommit(); +if (deadline_scheduling_enabled) { + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + } else { + EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); + EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + } + + client.Reset(); scheduler->SetMainThreadNeedsLayerTextures(); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 4); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 4); - EXPECT_ACTION("ScheduledActionAcquireLayerTexturesForMainThread", - client, - 2, - 4); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 3, 4); + EXPECT_SINGLE_ACTION( + "ScheduledActionAcquireLayerTexturesForMainThread", client); + + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (deadline_scheduling_enabled) { + EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + } else { + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + } + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); // Although the compositor cannot draw because textures are locked by main // thread, we continue requesting SetNeedsBeginFrame in anticipation of the @@ -321,43 +532,88 @@ TEST(SchedulerTest, TextureAcquisitionCollision) { // Trigger the commit scheduler->FinishCommit(); EXPECT_TRUE(client.needs_begin_frame()); - client.Reset(); // Between commit and draw, texture acquisition for main thread delayed, // and main thread blocks. + client.Reset(); scheduler->SetMainThreadNeedsLayerTextures(); EXPECT_EQ(0, client.num_actions_()); - client.Reset(); // No implicit commit is expected. + client.Reset(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + + client.Reset(); + scheduler->OnBeginFrameDeadline(); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3); - EXPECT_ACTION("ScheduledActionAcquireLayerTexturesForMainThread", - client, - 1, - 3); + EXPECT_ACTION( + "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3); EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 2, 3); - client.Reset(); + EXPECT_TRUE(client.needs_begin_frame()); - // Compositor not scheduled to draw because textures are locked by main + // The compositor should not draw because textures are locked by main // thread. + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); EXPECT_FALSE(client.needs_begin_frame()); - // Needs an explicit commit from the main thread. + // The impl thread need an explicit commit from the main thread to lock + // the textures. + client.Reset(); scheduler->SetNeedsCommit(); - EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + if (deadline_scheduling_enabled) { + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client); + } else { + EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); + EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + } + EXPECT_TRUE(client.needs_begin_frame()); + + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + if (deadline_scheduling_enabled) { + EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); + } else { + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + } client.Reset(); - // Trigger the commit + // Trigger the commit, which will trigger the deadline task early. scheduler->FinishCommit(); + EXPECT_ACTION("ScheduledActionCommit", client, 0, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); + + // Verify we draw on the next BeginFrame deadline + scheduler->OnBeginFrameDeadline(); + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2); + EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_TRUE(client.needs_begin_frame()); + client.Reset(); } -TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) { +TEST(SchedulerTest, TextureAcquisitionCollision) { + bool deadline_scheduling_enabled = false; + TextureAcquisitionCollision(deadline_scheduling_enabled); +} + +TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) { + bool deadline_scheduling_enabled = true; + TextureAcquisitionCollision(deadline_scheduling_enabled); +} + +void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) { FakeSchedulerClient client; - SchedulerSettings default_scheduler_settings; - Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + SchedulerSettings scheduler_settings; + scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled; + Scheduler* scheduler = client.CreateScheduler(scheduler_settings); scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); @@ -367,6 +623,10 @@ TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) { scheduler->DidCreateAndInitializeOutputSurface(); scheduler->SetNeedsCommit(); + if (deadline_scheduling_enabled) { + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); + } scheduler->FinishCommit(); scheduler->SetMainThreadNeedsLayerTextures(); scheduler->SetNeedsCommit(); @@ -376,36 +636,48 @@ TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) { scheduler->SetVisible(false); EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread", client); - client.Reset(); - // Already sent a begin frame on this current frame, so wait. + client.Reset(); scheduler->SetVisible(true); EXPECT_EQ(0, client.num_actions_()); - client.Reset(); + EXPECT_TRUE(client.needs_begin_frame()); // Regaining visibility with textures acquired by main thread while // compositor is waiting for first draw should result in a request // for a new frame in order to escape a deadlock. + client.Reset(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2); - EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2); + EXPECT_ACTION("PostBeginFrameDeadlineTask", client, 1, 2); +} + +TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) { + bool deadline_scheduling_enabled = false; + VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled); +} + +TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) { + bool deadline_scheduling_enabled = true; + VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled); } class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient { public: virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {} - virtual ScheduledActionDrawAndSwapResult - ScheduledActionDrawAndSwapIfPossible() OVERRIDE { + virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() + OVERRIDE { // Only SetNeedsRedraw the first time this is called if (!num_draws_) scheduler_->SetNeedsRedraw(); return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); } - virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced() - OVERRIDE { + virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE { NOTREACHED(); - return ScheduledActionDrawAndSwapResult(true, true); + bool did_draw = true; + bool did_swap = true; + bool did_readback = false; + return DrawSwapReadbackResult(did_draw, did_swap, did_readback); } virtual void ScheduledActionCommit() OVERRIDE {} @@ -424,7 +696,8 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) { scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); - scheduler->DidCreateAndInitializeOutputSurface(); + InitializeOutputSurfaceAndFirstCommit(scheduler); + client.Reset(); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); @@ -432,11 +705,20 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) { EXPECT_EQ(0, client.num_draws()); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_TRUE(client.needs_begin_frame()); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); + EXPECT_EQ(2, client.num_draws()); + EXPECT_FALSE(scheduler->RedrawPending()); + EXPECT_TRUE(client.needs_begin_frame()); + + // We stop requesting BeginFrames after a BeginFrame where we don't swap. + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(client.needs_begin_frame()); @@ -450,7 +732,8 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); - scheduler->DidCreateAndInitializeOutputSurface(); + InitializeOutputSurfaceAndFirstCommit(scheduler); + client.Reset(); client.SetDrawWillHappen(false); @@ -461,6 +744,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { // Fail the draw. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(1, client.num_draws()); // We have a commit pending and the draw failed, and we didn't lose the redraw @@ -471,6 +755,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { // Fail the draw again. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); @@ -479,58 +764,86 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { // Draw successfully. client.SetDrawWillHappen(true); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_TRUE(client.needs_begin_frame()); } -class SchedulerClientThatsetNeedsCommitInsideDraw : public FakeSchedulerClient { +class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { public: + SchedulerClientThatSetNeedsCommitInsideDraw() + : set_needs_commit_on_next_draw_(false) {} + virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {} - virtual ScheduledActionDrawAndSwapResult - ScheduledActionDrawAndSwapIfPossible() OVERRIDE { + virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() + OVERRIDE { // Only SetNeedsCommit the first time this is called - if (!num_draws_) + if (set_needs_commit_on_next_draw_) { scheduler_->SetNeedsCommit(); + set_needs_commit_on_next_draw_ = false; + } return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); } - virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced() - OVERRIDE { + virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE { NOTREACHED(); - return ScheduledActionDrawAndSwapResult(true, true); + bool did_draw = true; + bool did_swap = false; + bool did_readback = false; + return DrawSwapReadbackResult(did_draw, did_swap, did_readback); } virtual void ScheduledActionCommit() OVERRIDE {} virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {} virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {} + + void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; } + + private: + bool set_needs_commit_on_next_draw_; }; // Tests for the scheduler infinite-looping on SetNeedsCommit requests that // happen inside a ScheduledActionDrawAndSwap TEST(SchedulerTest, RequestCommitInsideDraw) { - SchedulerClientThatsetNeedsCommitInsideDraw client; + SchedulerClientThatSetNeedsCommitInsideDraw client; SchedulerSettings default_scheduler_settings; Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); - scheduler->DidCreateAndInitializeOutputSurface(); + InitializeOutputSurfaceAndFirstCommit(scheduler); + client.Reset(); + EXPECT_FALSE(client.needs_begin_frame()); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_EQ(0, client.num_draws()); EXPECT_TRUE(client.needs_begin_frame()); + client.SetNeedsCommitOnNextDraw(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + client.SetNeedsCommitOnNextDraw(); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(client.needs_begin_frame()); scheduler->FinishCommit(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); - EXPECT_EQ(2, client.num_draws());; + scheduler->OnBeginFrameDeadline(); + EXPECT_EQ(2, client.num_draws()); + + EXPECT_FALSE(scheduler->RedrawPending()); + EXPECT_FALSE(scheduler->CommitPending()); + EXPECT_TRUE(client.needs_begin_frame()); + + // We stop requesting BeginFrames after a BeginFrame where we don't swap. + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); + EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); EXPECT_FALSE(scheduler->CommitPending()); EXPECT_FALSE(client.needs_begin_frame()); @@ -544,7 +857,8 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); - scheduler->DidCreateAndInitializeOutputSurface(); + InitializeOutputSurfaceAndFirstCommit(scheduler); + client.Reset(); client.SetDrawWillHappen(false); @@ -555,6 +869,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { // Fail the draw. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(1, client.num_draws()); // We have a commit pending and the draw failed, and we didn't lose the commit @@ -565,6 +880,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { // Fail the draw again. scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(2, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_TRUE(scheduler->RedrawPending()); @@ -573,6 +889,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { // Draw successfully. client.SetDrawWillHappen(true); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); EXPECT_FALSE(scheduler->RedrawPending()); @@ -580,13 +897,14 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { } TEST(SchedulerTest, NoSwapWhenDrawFails) { - SchedulerClientThatsetNeedsCommitInsideDraw client; + SchedulerClientThatSetNeedsCommitInsideDraw client; SchedulerSettings default_scheduler_settings; Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); scheduler->SetCanStart(); scheduler->SetVisible(true); scheduler->SetCanDraw(true); - scheduler->DidCreateAndInitializeOutputSurface(); + InitializeOutputSurfaceAndFirstCommit(scheduler); + client.Reset(); scheduler->SetNeedsRedraw(); EXPECT_TRUE(scheduler->RedrawPending()); @@ -594,7 +912,9 @@ TEST(SchedulerTest, NoSwapWhenDrawFails) { EXPECT_EQ(0, client.num_draws()); // Draw successfully, this starts a new frame. + client.SetNeedsCommitOnNextDraw(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(1, client.num_draws()); scheduler->SetNeedsRedraw(); @@ -603,7 +923,9 @@ TEST(SchedulerTest, NoSwapWhenDrawFails) { // Fail to draw, this should not start a frame. client.SetDrawWillHappen(false); + client.SetNeedsCommitOnNextDraw(); scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + scheduler->OnBeginFrameDeadline(); EXPECT_EQ(2, client.num_draws()); } @@ -616,11 +938,142 @@ TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) { client.SetDrawWillHappen(true); client.SetSwapWillHappenIfDrawHappens(false); - // Get the compositor to do a ScheduledActionDrawAndSwapForced. + // Get the compositor to do a ScheduledActionDrawAndReadback. scheduler->SetCanDraw(true); scheduler->SetNeedsRedraw(); - scheduler->SetNeedsForcedRedraw(); - EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapForced")); + scheduler->SetNeedsForcedCommitForReadback(); + scheduler->FinishCommit(); + EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback")); +} + +TEST(SchedulerTest, BackToBackReadbackAllowed) { + // Some clients call readbacks twice in a row before the replacement + // commit comes in. Make sure it is allowed. + FakeSchedulerClient client; + SchedulerSettings default_scheduler_settings; + Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + + // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before + // the replacement commit comes in. + scheduler->SetCanDraw(true); + scheduler->SetNeedsRedraw(); + scheduler->SetNeedsForcedCommitForReadback(); + scheduler->FinishCommit(); + EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback")); + + client.Reset(); + scheduler->SetNeedsForcedCommitForReadback(); + scheduler->FinishCommit(); + EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback")); + + // The replacement commit comes in after 2 readbacks. + client.Reset(); + scheduler->FinishCommit(); +} + + +class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient { + public: + virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() + OVERRIDE { + scheduler_->SetNeedsManageTiles(); + return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); + } +}; + +// Test manage tiles is independant of draws. +TEST(SchedulerTest, ManageTiles) { + SchedulerClientNeedsManageTilesInDraw client; + SchedulerSettings default_scheduler_settings; + Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings); + scheduler->SetCanStart(); + scheduler->SetVisible(true); + scheduler->SetCanDraw(true); + InitializeOutputSurfaceAndFirstCommit(scheduler); + + // Request both draw and manage tiles. ManageTiles shouldn't + // be trigged until BeginFrame. + client.Reset(); + scheduler->SetNeedsManageTiles(); + scheduler->SetNeedsRedraw(); + EXPECT_TRUE(scheduler->RedrawPending()); + EXPECT_TRUE(scheduler->ManageTilesPending()); + EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_EQ(0, client.num_draws()); + EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles")); + EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); + + // We have no immediate actions to perform, so the BeginFrame should post + // the deadline task. + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + + // On the deadline, he actions should have occured in the right order. + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_EQ(1, client.num_draws()); + EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); + EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); + EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), + client.ActionIndex("ScheduledActionManageTiles")); + EXPECT_FALSE(scheduler->RedrawPending()); + EXPECT_FALSE(scheduler->ManageTilesPending()); + + // Request a draw. We don't need a ManageTiles yet. + client.Reset(); + scheduler->SetNeedsRedraw(); + EXPECT_TRUE(scheduler->RedrawPending()); + EXPECT_FALSE(scheduler->ManageTilesPending()); + EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_EQ(0, client.num_draws()); + + // We have no immediate actions to perform, so the BeginFrame should post + // the deadline task. + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + + // Draw. The draw will trigger SetNeedsManageTiles, and + // then the ManageTiles action will be triggered after the Draw. + // Afterwards, neither a draw nor ManageTiles are pending. + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_EQ(1, client.num_draws()); + EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); + EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); + EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"), + client.ActionIndex("ScheduledActionManageTiles")); + EXPECT_FALSE(scheduler->RedrawPending()); + EXPECT_FALSE(scheduler->ManageTilesPending()); + + // We need a BeginFrame where we don't swap to go idle. + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client);; + EXPECT_EQ(0, client.num_draws()); + + // Now trigger a ManageTiles outside of a draw. We will then need + // a begin-frame for the ManageTiles, but we don't need a draw. + client.Reset(); + EXPECT_FALSE(client.needs_begin_frame()); + scheduler->SetNeedsManageTiles(); + EXPECT_TRUE(client.needs_begin_frame()); + EXPECT_TRUE(scheduler->ManageTilesPending()); + EXPECT_FALSE(scheduler->RedrawPending()); + + // BeginFrame. There will be no draw, only ManageTiles. + client.Reset(); + scheduler->BeginFrame(BeginFrameArgs::CreateForTesting()); + EXPECT_SINGLE_ACTION("PostBeginFrameDeadlineTask", client); + client.Reset(); + scheduler->OnBeginFrameDeadline(); + EXPECT_EQ(0, client.num_draws()); + EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible")); + EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles")); } } // namespace |