summaryrefslogtreecommitdiff
path: root/chromium/cc/scheduler
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-18 14:10:49 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-06-18 13:53:24 +0000
commit813fbf95af77a531c57a8c497345ad2c61d475b3 (patch)
tree821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/cc/scheduler
parentaf6588f8d723931a298c995fa97259bb7f7deb55 (diff)
downloadqtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/cc/scheduler')
-rw-r--r--chromium/cc/scheduler/begin_frame_source.cc72
-rw-r--r--chromium/cc/scheduler/begin_frame_source.h40
-rw-r--r--chromium/cc/scheduler/begin_frame_source_unittest.cc144
-rw-r--r--chromium/cc/scheduler/commit_earlyout_reason.h40
-rw-r--r--chromium/cc/scheduler/delay_based_time_source.cc39
-rw-r--r--chromium/cc/scheduler/delay_based_time_source.h8
-rw-r--r--chromium/cc/scheduler/delay_based_time_source_unittest.cc17
-rw-r--r--chromium/cc/scheduler/scheduler.cc599
-rw-r--r--chromium/cc/scheduler/scheduler.h93
-rw-r--r--chromium/cc/scheduler/scheduler_settings.cc40
-rw-r--r--chromium/cc/scheduler/scheduler_settings.h18
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.cc655
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h152
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine_unittest.cc1100
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc3649
-rw-r--r--chromium/cc/scheduler/video_frame_controller.h40
16 files changed, 3794 insertions, 2912 deletions
diff --git a/chromium/cc/scheduler/begin_frame_source.cc b/chromium/cc/scheduler/begin_frame_source.cc
index 4a9f1844083..48d834359f4 100644
--- a/chromium/cc/scheduler/begin_frame_source.cc
+++ b/chromium/cc/scheduler/begin_frame_source.cc
@@ -5,10 +5,11 @@
#include "cc/scheduler/begin_frame_source.h"
#include "base/auto_reset.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/scheduler/delay_based_time_source.h"
#include "cc/scheduler/scheduler.h"
#include "ui/gfx/frame_time.h"
@@ -52,7 +53,7 @@ void BeginFrameObserverMixIn::OnBeginFrame(const BeginFrameArgs& args) {
}
void BeginFrameObserverMixIn::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->BeginDictionary("last_begin_frame_args_");
last_begin_frame_args_.AsValueInto(dict);
dict->EndDictionary();
@@ -79,9 +80,9 @@ void BeginFrameSourceMixIn::SetNeedsBeginFrames(bool needs_begin_frames) {
"new state",
needs_begin_frames);
if (needs_begin_frames_ != needs_begin_frames) {
+ needs_begin_frames_ = needs_begin_frames;
OnNeedsBeginFramesChange(needs_begin_frames);
}
- needs_begin_frames_ = needs_begin_frames;
}
void BeginFrameSourceMixIn::AddObserver(BeginFrameObserver* obs) {
@@ -116,7 +117,8 @@ void BeginFrameSourceMixIn::CallOnBeginFrame(const BeginFrameArgs& args) {
}
// Tracing support
-void BeginFrameSourceMixIn::AsValueInto(base::debug::TracedValue* dict) const {
+void BeginFrameSourceMixIn::AsValueInto(
+ base::trace_event::TracedValue* dict) const {
// As the observer might try to trace the source, prevent an infinte loop
// from occuring.
if (inside_as_value_into_) {
@@ -145,9 +147,9 @@ scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
BackToBackBeginFrameSource::BackToBackBeginFrameSource(
base::SingleThreadTaskRunner* task_runner)
: BeginFrameSourceMixIn(),
- weak_factory_(this),
task_runner_(task_runner),
- send_begin_frame_posted_(false) {
+ send_begin_frame_posted_(false),
+ weak_factory_(this) {
DCHECK(task_runner);
DCHECK_EQ(needs_begin_frames_, false);
DCHECK_EQ(send_begin_frame_posted_, false);
@@ -181,10 +183,9 @@ void BackToBackBeginFrameSource::BeginFrame() {
return;
base::TimeTicks now = Now();
- BeginFrameArgs args =
- BeginFrameArgs::Create(now,
- now + BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::DefaultInterval());
+ BeginFrameArgs args = BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
CallOnBeginFrame(args);
}
@@ -198,7 +199,7 @@ void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
// Tracing support
void BackToBackBeginFrameSource::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->SetString("type", "BackToBackBeginFrameSource");
BeginFrameSourceMixIn::AsValueInto(dict);
dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
@@ -243,8 +244,8 @@ BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
base::TimeTicks frame_time,
BeginFrameArgs::BeginFrameArgsType type) {
base::TimeTicks deadline = time_source_->NextTickTime();
- return BeginFrameArgs::CreateTyped(
- frame_time, deadline, time_source_->Interval(), type);
+ return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
+ time_source_->Interval(), type);
}
// TimeSourceClient support
@@ -264,13 +265,9 @@ void SyntheticBeginFrameSource::OnNeedsBeginFramesChange(
}
}
-bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
- return time_source_->Active();
-}
-
// Tracing support
void SyntheticBeginFrameSource::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->SetString("type", "SyntheticBeginFrameSource");
BeginFrameSourceMixIn::AsValueInto(dict);
@@ -300,6 +297,10 @@ BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
}
BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
+ if (active_source_) {
+ active_source_->SetNeedsBeginFrames(false);
+ active_source_->RemoveObserver(this);
+ }
}
void BeginFrameSourceMultiplexer::SetMinimumInterval(
@@ -314,11 +315,8 @@ void BeginFrameSourceMultiplexer::SetMinimumInterval(
}
void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
- DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource",
- "current active",
- active_source_,
- "source to remove",
- new_source);
+ DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource", "current active",
+ active_source_, "source to be added", new_source);
DCHECK(new_source);
DCHECK(!HasSource(new_source));
@@ -331,11 +329,8 @@ void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
void BeginFrameSourceMultiplexer::RemoveSource(
BeginFrameSource* existing_source) {
- DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource",
- "current active",
- active_source_,
- "source to remove",
- existing_source);
+ DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource", "current active",
+ active_source_, "source to be removed", existing_source);
DCHECK(existing_source);
DCHECK(HasSource(existing_source));
DCHECK_NE(existing_source, active_source_);
@@ -406,19 +401,10 @@ const BeginFrameArgs BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
}
// BeginFrameSource support
-bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
- if (active_source_) {
- return active_source_->NeedsBeginFrames();
- } else {
- return false;
- }
-}
-
-void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) {
- DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetNeedsBeginFrames",
- "active_source",
- active_source_,
- "needs_begin_frames",
+void BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange(
+ bool needs_begin_frames) {
+ DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange",
+ "active_source", active_source_, "needs_begin_frames",
needs_begin_frames);
if (active_source_) {
active_source_->SetNeedsBeginFrames(needs_begin_frames);
@@ -440,7 +426,7 @@ void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
// Tracing support
void BeginFrameSourceMultiplexer::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->SetString("type", "BeginFrameSourceMultiplexer");
dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
diff --git a/chromium/cc/scheduler/begin_frame_source.h b/chromium/cc/scheduler/begin_frame_source.h
index 3d849a40d63..d845dacd8e4 100644
--- a/chromium/cc/scheduler/begin_frame_source.h
+++ b/chromium/cc/scheduler/begin_frame_source.h
@@ -8,8 +8,8 @@
#include <set>
#include <string>
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/vsync_parameter_observer.h"
#include "cc/scheduler/delay_based_time_source.h"
@@ -50,7 +50,7 @@ class CC_EXPORT BeginFrameObserver {
virtual const BeginFrameArgs LastUsedBeginFrameArgs() const = 0;
// Tracing support
- virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const = 0;
};
// Simple mix in which implements a BeginFrameObserver which checks the
@@ -75,7 +75,7 @@ class CC_EXPORT BeginFrameObserverMixIn : public BeginFrameObserver {
const BeginFrameArgs LastUsedBeginFrameArgs() const override;
// Outputs last_begin_frame_args_
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
// Subclasses should override this method!
@@ -117,9 +117,12 @@ class CC_EXPORT BeginFrameSource {
virtual void AddObserver(BeginFrameObserver* obs) = 0;
virtual void RemoveObserver(BeginFrameObserver* obs) = 0;
+ // Tells the Source that client is ready to handle BeginFrames messages.
+ virtual void SetClientReady() = 0;
+
// Tracing support - Recommend (but not required) to call this implementation
// in any override.
- virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const = 0;
};
// Simple mix in which implements a BeginFrameSource.
@@ -134,15 +137,16 @@ class CC_EXPORT BeginFrameSourceMixIn : public BeginFrameSource {
~BeginFrameSourceMixIn() override {}
// BeginFrameSource
- bool NeedsBeginFrames() const override;
- void SetNeedsBeginFrames(bool needs_begin_frames) override;
+ bool NeedsBeginFrames() const final;
+ void SetNeedsBeginFrames(bool needs_begin_frames) final;
void DidFinishFrame(size_t remaining_frames) override {}
- void AddObserver(BeginFrameObserver* obs) override;
- void RemoveObserver(BeginFrameObserver* obs) override;
+ void AddObserver(BeginFrameObserver* obs) final;
+ void RemoveObserver(BeginFrameObserver* obs) final;
+ void SetClientReady() override {}
// Tracing support - Recommend (but not required) to call this implementation
// in any override.
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
BeginFrameSourceMixIn();
@@ -174,14 +178,13 @@ class CC_EXPORT BackToBackBeginFrameSource : public BeginFrameSourceMixIn {
void DidFinishFrame(size_t remaining_frames) override;
// Tracing
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
explicit BackToBackBeginFrameSource(
base::SingleThreadTaskRunner* task_runner);
virtual base::TimeTicks Now(); // Now overridable for testing
- base::WeakPtrFactory<BackToBackBeginFrameSource> weak_factory_;
base::SingleThreadTaskRunner* task_runner_;
bool send_begin_frame_posted_;
@@ -190,6 +193,9 @@ class CC_EXPORT BackToBackBeginFrameSource : public BeginFrameSourceMixIn {
void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
void BeginFrame();
+
+ private:
+ base::WeakPtrFactory<BackToBackBeginFrameSource> weak_factory_;
};
// A frame source which is locked to an external parameters provides from a
@@ -204,11 +210,8 @@ class CC_EXPORT SyntheticBeginFrameSource : public BeginFrameSourceMixIn,
base::TimeDelta initial_vsync_interval);
~SyntheticBeginFrameSource() override;
- // BeginFrameSource
- bool NeedsBeginFrames() const override;
-
// Tracing
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
// VSyncParameterObserver
void OnUpdateVSyncParameters(base::TimeTicks new_vsync_timebase,
@@ -254,12 +257,13 @@ class CC_EXPORT BeginFrameSourceMultiplexer : public BeginFrameSourceMixIn,
const BeginFrameArgs LastUsedBeginFrameArgs() const override;
// BeginFrameSource
- bool NeedsBeginFrames() const override;
- void SetNeedsBeginFrames(bool needs_begin_frames) override;
void DidFinishFrame(size_t remaining_frames) override;
+ // BeginFrameSourceMixIn
+ void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
+
// Tracing
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
BeginFrameSourceMultiplexer();
diff --git a/chromium/cc/scheduler/begin_frame_source_unittest.cc b/chromium/cc/scheduler/begin_frame_source_unittest.cc
index b741e3581a9..22126bead45 100644
--- a/chromium/cc/scheduler/begin_frame_source_unittest.cc
+++ b/chromium/cc/scheduler/begin_frame_source_unittest.cc
@@ -15,19 +15,18 @@
#include "testing/gtest/include/gtest/gtest.h"
// Macros to help set up expected calls on the MockBeginFrameObserver.
-#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \
- { \
- ::testing::Expectation exp = \
- EXPECT_CALL((obs), \
- OnBeginFrame(CreateBeginFrameArgsForTesting( \
- frame_time, deadline, interval))) \
- .InSequence((obs).sequence); \
+#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \
+ { \
+ ::testing::Expectation exp = \
+ EXPECT_CALL((obs), OnBeginFrame(CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, \
+ interval))).InSequence((obs).sequence); \
}
#define EXPECT_BEGIN_FRAME_USED(obs, frame_time, deadline, interval) \
{ \
- BeginFrameArgs args = \
- CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \
::testing::Expectation exp = \
EXPECT_CALL((obs), OnBeginFrame(args)).InSequence((obs).sequence); \
EXPECT_CALL((obs), LastUsedBeginFrameArgs()) \
@@ -38,15 +37,15 @@
// Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting
// observer behaviour).
-#define SEND_BEGIN_FRAME( \
- args_equal_to, source, frame_time, deadline, interval) \
- { \
- BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \
- BeginFrameArgs new_args = \
- CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \
- ASSERT_TRUE(!(old_args == new_args)); \
- (source).TestOnBeginFrame(new_args); \
- EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \
+#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \
+ interval) \
+ { \
+ BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \
+ BeginFrameArgs new_args = CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \
+ ASSERT_FALSE(old_args == new_args); \
+ (source).TestOnBeginFrame(new_args); \
+ EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \
}
// When dropping LastUsedBeginFrameArgs **shouldn't** change.
@@ -65,7 +64,7 @@ class MockBeginFrameObserver : public BeginFrameObserver {
MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&));
MOCK_CONST_METHOD0(LastUsedBeginFrameArgs, const BeginFrameArgs());
- virtual void AsValueInto(base::debug::TracedValue* dict) const {
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const {
dict->SetString("type", "MockBeginFrameObserver");
dict->BeginDictionary("last_begin_frame_args");
LastUsedBeginFrameArgs().AsValueInto(dict);
@@ -99,19 +98,25 @@ TEST(MockBeginFrameObserverTest, ExpectOnBeginFrame) {
MockBeginFrameObserver::kDefaultBeginFrameArgs);
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 100, 200, 300)); // One call to LastUsedBeginFrameArgs
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ BEGINFRAME_FROM_HERE, 100, 200,
+ 300)); // One call to LastUsedBeginFrameArgs
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 400, 600, 300)); // Multiple calls to LastUsedBeginFrameArgs
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(400, 600, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(400, 600, 300));
+ BEGINFRAME_FROM_HERE, 400, 600,
+ 300)); // Multiple calls to LastUsedBeginFrameArgs
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 700, 900, 300)); // No calls to LastUsedBeginFrameArgs
+ BEGINFRAME_FROM_HERE, 700, 900,
+ 300)); // No calls to LastUsedBeginFrameArgs
}
TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
@@ -125,28 +130,45 @@ TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
MockBeginFrameObserver::kDefaultBeginFrameArgs);
// Used
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(100, 200, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Dropped
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(400, 600, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Dropped
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(450, 650, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 450, 650, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Used
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(700, 900, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(700, 900, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
}
const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs =
- CreateBeginFrameArgsForTesting(-1, -1, -1);
+ CreateBeginFrameArgsForTesting(
+#ifdef NDEBUG
+ nullptr,
+#else
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "MockBeginFrameObserver::kDefaultBeginFrameArgs"),
+#endif
+ -1,
+ -1,
+ -1);
// BeginFrameObserverMixIn testing ---------------------------------------
class MockMinimalBeginFrameObserverMixIn : public BeginFrameObserverMixIn {
@@ -168,25 +190,31 @@ TEST(BeginFrameObserverMixInTest, OnBeginFrameImplementation) {
EXPECT_DEATH({ obs.OnBeginFrame(BeginFrameArgs()); }, "");
#endif
- BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(100, 200, 300);
+ BeginFrameArgs args1 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args1)).WillOnce(Return(true));
obs.OnBeginFrame(args1);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(0, obs.dropped_begin_frame_args());
#ifndef NDEBUG
- EXPECT_DEATH(
- { obs.OnBeginFrame(CreateBeginFrameArgsForTesting(50, 200, 300)); }, "");
+ EXPECT_DEATH({
+ obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 50, 200, 300));
+ },
+ "");
#endif
// Returning false shouldn't update the LastUsedBeginFrameArgs value.
- BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(200, 300, 400);
+ BeginFrameArgs args2 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 200, 300, 400);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args2)).WillOnce(Return(false));
obs.OnBeginFrame(args2);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(1, obs.dropped_begin_frame_args());
- BeginFrameArgs args3 = CreateBeginFrameArgsForTesting(150, 300, 400);
+ BeginFrameArgs args3 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 150, 300, 400);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args3)).WillOnce(Return(true));
obs.OnBeginFrame(args3);
EXPECT_EQ(args3, obs.LastUsedBeginFrameArgs());
@@ -256,7 +284,7 @@ class LoopingBeginFrameObserver : public BeginFrameObserverMixIn {
public:
BeginFrameSource* source_;
- void AsValueInto(base::debug::TracedValue* dict) const override {
+ void AsValueInto(base::trace_event::TracedValue* dict) const override {
dict->SetString("type", "LoopingBeginFrameObserver");
dict->BeginDictionary("source");
source_->AsValueInto(dict);
@@ -277,8 +305,8 @@ TEST(BeginFrameSourceMixInTest, DetectAsValueIntoLoop) {
obs.source_ = &source;
source.AddObserver(&obs);
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
source.AsValueInto(state.get());
}
@@ -312,7 +340,7 @@ class BackToBackBeginFrameSourceTest : public ::testing::Test {
scoped_ptr<TestBackToBackBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
- virtual void SetUp() override {
+ void SetUp() override {
now_src_ = TestNowSource::Create(1000);
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -323,7 +351,7 @@ class BackToBackBeginFrameSourceTest : public ::testing::Test {
source_->AddObserver(obs_.get());
}
- virtual void TearDown() override { obs_.reset(); }
+ void TearDown() override { obs_.reset(); }
};
const int64_t BackToBackBeginFrameSourceTest::kDeadline =
@@ -478,7 +506,7 @@ class SyntheticBeginFrameSourceTest : public ::testing::Test {
scoped_ptr<TestSyntheticBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
- virtual void SetUp() override {
+ void SetUp() override {
now_src_ = TestNowSource::Create(1000);
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -488,15 +516,15 @@ class SyntheticBeginFrameSourceTest : public ::testing::Test {
source_->AddObserver(obs_.get());
}
- virtual void TearDown() override { obs_.reset(); }
+ void TearDown() override { obs_.reset(); }
};
TEST_F(SyntheticBeginFrameSourceTest,
SetNeedsBeginFramesCallsOnBeginFrameWithMissedTick) {
now_src_->SetNowMicroseconds(10010);
- EXPECT_CALL((*obs_),
- OnBeginFrame(CreateTypedBeginFrameArgsForTesting(
- 10000, 20000, 10000, BeginFrameArgs::MISSED)));
+ EXPECT_CALL((*obs_), OnBeginFrame(CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 10000, 20000, 10000,
+ BeginFrameArgs::MISSED)));
source_->SetNeedsBeginFrames(true); // Should cause the last tick to be sent
// No tasks should need to be run for this to occur.
}
@@ -547,7 +575,7 @@ TEST_F(SyntheticBeginFrameSourceTest, VSyncChanges) {
// BeginFrameSourceMultiplexer testing -----------------------------------
class BeginFrameSourceMultiplexerTest : public ::testing::Test {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
mux_ = BeginFrameSourceMultiplexer::Create();
source1_store_ = make_scoped_ptr(new FakeBeginFrameSource());
@@ -559,7 +587,7 @@ class BeginFrameSourceMultiplexerTest : public ::testing::Test {
source3_ = source3_store_.get();
}
- virtual void TearDown() override {
+ void TearDown() override {
// Make sure the mux is torn down before the sources.
mux_.reset();
}
diff --git a/chromium/cc/scheduler/commit_earlyout_reason.h b/chromium/cc/scheduler/commit_earlyout_reason.h
new file mode 100644
index 00000000000..14aaeb3b7d9
--- /dev/null
+++ b/chromium/cc/scheduler/commit_earlyout_reason.h
@@ -0,0 +1,40 @@
+// Copyright 2014 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.
+
+#ifndef CC_SCHEDULER_COMMIT_EARLYOUT_REASON_H_
+#define CC_SCHEDULER_COMMIT_EARLYOUT_REASON_H_
+
+#include "base/logging.h"
+
+namespace cc {
+
+enum class CommitEarlyOutReason {
+ ABORTED_OUTPUT_SURFACE_LOST,
+ ABORTED_NOT_VISIBLE,
+ ABORTED_DEFERRED_COMMIT,
+ FINISHED_NO_UPDATES,
+};
+
+inline const char* CommitEarlyOutReasonToString(CommitEarlyOutReason reason) {
+ switch (reason) {
+ case CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST:
+ return "CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST";
+ case CommitEarlyOutReason::ABORTED_NOT_VISIBLE:
+ return "CommitEarlyOutReason::ABORTED_NOT_VISIBLE";
+ case CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT:
+ return "CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT";
+ case CommitEarlyOutReason::FINISHED_NO_UPDATES:
+ return "CommitEarlyOutReason::FINISHED_NO_UPDATES";
+ }
+ NOTREACHED();
+ return "???";
+}
+
+inline bool CommitEarlyOutHandledCommit(CommitEarlyOutReason reason) {
+ return reason == CommitEarlyOutReason::FINISHED_NO_UPDATES;
+}
+
+} // namespace cc
+
+#endif // CC_SCHEDULER_COMMIT_EARLYOUT_REASON_H_
diff --git a/chromium/cc/scheduler/delay_based_time_source.cc b/chromium/cc/scheduler/delay_based_time_source.cc
index cd214fd98d7..ef43524a878 100644
--- a/chromium/cc/scheduler/delay_based_time_source.cc
+++ b/chromium/cc/scheduler/delay_based_time_source.cc
@@ -9,11 +9,11 @@
#include <string>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
namespace cc {
@@ -36,7 +36,7 @@ static const double kPhaseChangeThreshold = 0.25;
} // namespace
// The following methods correspond to the DelayBasedTimeSource that uses
-// the base::TimeTicks::HighResNow as the timebase.
+// the base::TimeTicks::Now as the timebase.
scoped_refptr<DelayBasedTimeSourceHighRes> DelayBasedTimeSourceHighRes::Create(
base::TimeDelta interval,
base::SingleThreadTaskRunner* task_runner) {
@@ -53,7 +53,7 @@ DelayBasedTimeSourceHighRes::DelayBasedTimeSourceHighRes(
DelayBasedTimeSourceHighRes::~DelayBasedTimeSourceHighRes() {}
base::TimeTicks DelayBasedTimeSourceHighRes::Now() const {
- return base::TimeTicks::HighResNow();
+ return base::TimeTicks::Now();
}
// The following methods correspond to the DelayBasedTimeSource that uses
@@ -234,34 +234,20 @@ base::TimeTicks DelayBasedTimeSource::Now() const {
// now=37 tick_target=16.667 new_target=50.000 -->
// tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13)
base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) {
- base::TimeDelta new_interval = next_parameters_.interval;
-
- // |interval_offset| is the offset from |now| to the next multiple of
- // |interval| after |tick_target|, possibly negative if in the past.
- base::TimeDelta interval_offset = base::TimeDelta::FromInternalValue(
- (next_parameters_.tick_target - now).ToInternalValue() %
- new_interval.ToInternalValue());
- // If |now| is exactly on the interval (i.e. offset==0), don't adjust.
- // Otherwise, if |tick_target| was in the past, adjust forward to the next
- // tick after |now|.
- if (interval_offset.ToInternalValue() != 0 &&
- next_parameters_.tick_target < now) {
- interval_offset += new_interval;
- }
-
- base::TimeTicks new_tick_target = now + interval_offset;
+ base::TimeTicks new_tick_target = now.SnappedToNextTick(
+ next_parameters_.tick_target, next_parameters_.interval);
DCHECK(now <= new_tick_target)
<< "now = " << now.ToInternalValue()
<< "; new_tick_target = " << new_tick_target.ToInternalValue()
- << "; new_interval = " << new_interval.InMicroseconds()
- << "; tick_target = " << next_parameters_.tick_target.ToInternalValue()
- << "; interval_offset = " << interval_offset.ToInternalValue();
+ << "; new_interval = " << next_parameters_.interval.InMicroseconds()
+ << "; tick_target = " << next_parameters_.tick_target.ToInternalValue();
// Avoid double ticks when:
// 1) Turning off the timer and turning it right back on.
// 2) Jittery data is passed to SetTimebaseAndInterval().
- if (new_tick_target - last_tick_time_ <= new_interval / kDoubleTickDivisor)
- new_tick_target += new_interval;
+ if (new_tick_target - last_tick_time_ <=
+ next_parameters_.interval / kDoubleTickDivisor)
+ new_tick_target += next_parameters_.interval;
return new_tick_target;
}
@@ -290,7 +276,8 @@ std::string DelayBasedTimeSourceHighRes::TypeString() const {
return "DelayBasedTimeSourceHighRes";
}
-void DelayBasedTimeSource::AsValueInto(base::debug::TracedValue* state) const {
+void DelayBasedTimeSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
state->SetString("type", TypeString());
state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue());
state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue());
diff --git a/chromium/cc/scheduler/delay_based_time_source.h b/chromium/cc/scheduler/delay_based_time_source.h
index 9f670d1f8ff..4d7276c97c8 100644
--- a/chromium/cc/scheduler/delay_based_time_source.h
+++ b/chromium/cc/scheduler/delay_based_time_source.h
@@ -12,7 +12,7 @@
#include "cc/base/cc_export.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class SingleThreadTaskRunner;
@@ -55,7 +55,7 @@ class CC_EXPORT DelayBasedTimeSource
// Virtual for testing.
virtual base::TimeTicks Now() const;
- virtual void AsValueInto(base::debug::TracedValue* dict) const;
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
protected:
DelayBasedTimeSource(base::TimeDelta interval,
@@ -95,7 +95,9 @@ class CC_EXPORT DelayBasedTimeSource
DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSource);
};
-// DelayBasedTimeSource uses base::TimeTicks::HighResNow as its timebase.
+// DelayBasedTimeSource that once used base::TimeTicks::HighResNow as its time
+// source, but is now a no-op.
+// TODO(brianderson): Remove along with gfx::/FrameTime.http://crbug.com/447329
class DelayBasedTimeSourceHighRes : public DelayBasedTimeSource {
public:
static scoped_refptr<DelayBasedTimeSourceHighRes> Create(
diff --git a/chromium/cc/scheduler/delay_based_time_source_unittest.cc b/chromium/cc/scheduler/delay_based_time_source_unittest.cc
index 0af8b02f4b9..f721b11ff7f 100644
--- a/chromium/cc/scheduler/delay_based_time_source_unittest.cc
+++ b/chromium/cc/scheduler/delay_based_time_source_unittest.cc
@@ -508,23 +508,6 @@ TEST(DelayBasedTimeSourceTest, TestDeactivateAndReactivateAfterNextTickTime) {
EXPECT_EQ(13, task_runner->NextPendingTaskDelay().InMilliseconds());
}
-TEST(DelayBasedTimeSourceTest, TestOverflow) {
- // int(big_now / interval) < 0, so this causes a crash if the number of
- // intervals elapsed is attempted to be stored in an int.
- base::TimeDelta interval = base::TimeDelta::FromInternalValue(4000);
- base::TimeTicks big_now = base::TimeTicks::FromInternalValue(8635916564000);
-
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- FakeTimeSourceClient client;
- scoped_refptr<FakeDelayBasedTimeSource> timer =
- FakeDelayBasedTimeSource::Create(interval, task_runner.get());
- timer->SetClient(&client);
- timer->SetNow(big_now);
- timer->SetActive(true);
- EXPECT_EQ(0, task_runner->NextPendingTaskDelay().InMilliseconds());
-}
-
TEST(DelayBasedTimeSourceTest, TestReturnValueWhenTimerIsDeActivated) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index 88c27c103e3..d2520335c0c 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -5,11 +5,13 @@
#include "cc/scheduler/scheduler.h"
#include <algorithm>
+
#include "base/auto_reset.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "cc/scheduler/delay_based_time_source.h"
@@ -19,21 +21,14 @@ namespace cc {
BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
Scheduler* scheduler) {
- if (!scheduler->settings_.throttle_frame_production) {
+ if (scheduler->settings_.use_external_begin_frame_source) {
TRACE_EVENT1("cc",
"Scheduler::Scheduler()",
"PrimaryFrameSource",
- "BackToBackBeginFrameSource");
- DCHECK(!scheduler->primary_frame_source_internal_);
- scheduler->primary_frame_source_internal_ =
- BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
+ "ExternalBeginFrameSource");
+ DCHECK(scheduler->primary_frame_source_internal_)
+ << "Need external BeginFrameSource";
return scheduler->primary_frame_source_internal_.get();
- } else if (scheduler->settings_.begin_frame_scheduling_enabled) {
- TRACE_EVENT1("cc",
- "Scheduler::Scheduler()",
- "PrimaryFrameSource",
- "SchedulerClient");
- return scheduler->client_->ExternalBeginFrameSource();
} else {
TRACE_EVENT1("cc",
"Scheduler::Scheduler()",
@@ -54,18 +49,14 @@ BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
}
BeginFrameSource*
-SchedulerFrameSourcesConstructor::ConstructBackgroundFrameSource(
+SchedulerFrameSourcesConstructor::ConstructUnthrottledFrameSource(
Scheduler* scheduler) {
- TRACE_EVENT1("cc",
- "Scheduler::Scheduler()",
- "BackgroundFrameSource",
- "SyntheticBeginFrameSource");
- DCHECK(!(scheduler->background_frame_source_internal_));
- scheduler->background_frame_source_internal_ =
- SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(),
- scheduler->Now(),
- base::TimeDelta::FromSeconds(1));
- return scheduler->background_frame_source_internal_.get();
+ TRACE_EVENT1("cc", "Scheduler::Scheduler()", "UnthrottledFrameSource",
+ "BackToBackBeginFrameSource");
+ DCHECK(!scheduler->unthrottled_frame_source_internal_);
+ scheduler->unthrottled_frame_source_internal_ =
+ BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
+ return scheduler->unthrottled_frame_source_internal_.get();
}
Scheduler::Scheduler(
@@ -73,20 +64,21 @@ Scheduler::Scheduler(
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source,
SchedulerFrameSourcesConstructor* frame_sources_constructor)
: frame_source_(),
primary_frame_source_(NULL),
- background_frame_source_(NULL),
- primary_frame_source_internal_(),
- background_frame_source_internal_(),
+ primary_frame_source_internal_(external_begin_frame_source.Pass()),
vsync_observer_(NULL),
+ authoritative_vsync_interval_(base::TimeDelta()),
+ last_vsync_timebase_(base::TimeTicks()),
+ throttle_frame_production_(false),
settings_(scheduler_settings),
client_(client),
layer_tree_host_id_(layer_tree_host_id),
task_runner_(task_runner),
- power_monitor_(power_monitor),
- begin_retro_frame_posted_(false),
+ begin_impl_frame_deadline_mode_(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE),
state_machine_(scheduler_settings),
inside_process_scheduled_actions_(false),
inside_action_(SchedulerStateMachine::ACTION_NONE),
@@ -102,8 +94,6 @@ Scheduler::Scheduler(
base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
begin_impl_frame_deadline_closure_ = base::Bind(
&Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
- poll_for_draw_triggers_closure_ = base::Bind(
- &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
advance_commit_state_closure_ = base::Bind(
&Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
@@ -114,17 +104,20 @@ Scheduler::Scheduler(
primary_frame_source_ =
frame_sources_constructor->ConstructPrimaryFrameSource(this);
frame_source_->AddSource(primary_frame_source_);
+ primary_frame_source_->SetClientReady();
- // Background ticking frame source
- background_frame_source_ =
- frame_sources_constructor->ConstructBackgroundFrameSource(this);
- frame_source_->AddSource(background_frame_source_);
+ // Unthrottled frame source
+ unthrottled_frame_source_ =
+ frame_sources_constructor->ConstructUnthrottledFrameSource(this);
+ frame_source_->AddSource(unthrottled_frame_source_);
- SetupPowerMonitoring();
+ SetThrottleFrameProduction(scheduler_settings.throttle_frame_production);
}
Scheduler::~Scheduler() {
- TeardownPowerMonitoring();
+ if (frame_source_->NeedsBeginFrames())
+ frame_source_->SetNeedsBeginFrames(false);
+ frame_source_->SetActiveSource(nullptr);
}
base::TimeTicks Scheduler::Now() const {
@@ -136,32 +129,16 @@ base::TimeTicks Scheduler::Now() const {
return now;
}
-void Scheduler::SetupPowerMonitoring() {
- if (settings_.disable_hi_res_timer_tasks_on_battery) {
- DCHECK(power_monitor_);
- power_monitor_->AddObserver(this);
- state_machine_.SetImplLatencyTakesPriorityOnBattery(
- power_monitor_->IsOnBatteryPower());
- }
-}
-
-void Scheduler::TeardownPowerMonitoring() {
- if (settings_.disable_hi_res_timer_tasks_on_battery) {
- DCHECK(power_monitor_);
- power_monitor_->RemoveObserver(this);
- }
-}
-
-void Scheduler::OnPowerStateChange(bool on_battery_power) {
- DCHECK(settings_.disable_hi_res_timer_tasks_on_battery);
- state_machine_.SetImplLatencyTakesPriorityOnBattery(on_battery_power);
-}
-
void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) {
- // TODO(brianderson): We should not be receiving 0 intervals.
- if (interval == base::TimeDelta())
+ if (authoritative_vsync_interval_ != base::TimeDelta()) {
+ interval = authoritative_vsync_interval_;
+ } else if (interval == base::TimeDelta()) {
+ // TODO(brianderson): We should not be receiving 0 intervals.
interval = BeginFrameArgs::DefaultInterval();
+ }
+
+ last_vsync_timebase_ = timebase;
if (vsync_observer_)
vsync_observer_->OnUpdateVSyncParameters(timebase, interval);
@@ -179,11 +156,6 @@ void Scheduler::SetCanStart() {
void Scheduler::SetVisible(bool visible) {
state_machine_.SetVisible(visible);
- if (visible) {
- frame_source_->SetActiveSource(primary_frame_source_);
- } else {
- frame_source_->SetActiveSource(background_frame_source_);
- }
ProcessScheduledActions();
}
@@ -197,6 +169,22 @@ void Scheduler::NotifyReadyToActivate() {
ProcessScheduledActions();
}
+void Scheduler::NotifyReadyToDraw() {
+ // Future work might still needed for crbug.com/352894.
+ state_machine_.NotifyReadyToDraw();
+ ProcessScheduledActions();
+}
+
+void Scheduler::SetThrottleFrameProduction(bool throttle) {
+ throttle_frame_production_ = throttle;
+ if (throttle) {
+ frame_source_->SetActiveSource(primary_frame_source_);
+ } else {
+ frame_source_->SetActiveSource(unthrottled_frame_source_);
+ }
+ ProcessScheduledActions();
+}
+
void Scheduler::SetNeedsCommit() {
state_machine_.SetNeedsCommit();
ProcessScheduledActions();
@@ -212,9 +200,14 @@ void Scheduler::SetNeedsAnimate() {
ProcessScheduledActions();
}
-void Scheduler::SetNeedsManageTiles() {
- DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
- state_machine_.SetNeedsManageTiles();
+void Scheduler::SetNeedsPrepareTiles() {
+ DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_PREPARE_TILES));
+ state_machine_.SetNeedsPrepareTiles();
+ ProcessScheduledActions();
+}
+
+void Scheduler::SetWaitForReadyToDraw() {
+ state_machine_.SetWaitForReadyToDraw();
ProcessScheduledActions();
}
@@ -232,11 +225,6 @@ void Scheduler::DidSwapBuffers() {
}
}
-void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
- state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
- ProcessScheduledActions();
-}
-
void Scheduler::DidSwapBuffersComplete() {
state_machine_.DidSwapBuffersComplete();
ProcessScheduledActions();
@@ -253,22 +241,22 @@ void Scheduler::NotifyReadyToCommit() {
ProcessScheduledActions();
}
-void Scheduler::BeginMainFrameAborted(bool did_handle) {
- TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
- state_machine_.BeginMainFrameAborted(did_handle);
+void Scheduler::BeginMainFrameAborted(CommitEarlyOutReason reason) {
+ TRACE_EVENT1("cc", "Scheduler::BeginMainFrameAborted", "reason",
+ CommitEarlyOutReasonToString(reason));
+ state_machine_.BeginMainFrameAborted(reason);
ProcessScheduledActions();
}
-void Scheduler::DidManageTiles() {
- state_machine_.DidManageTiles();
+void Scheduler::DidPrepareTiles() {
+ state_machine_.DidPrepareTiles();
}
void Scheduler::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
- state_machine_.DidLoseOutputSurface();
- if (frame_source_->NeedsBeginFrames())
- frame_source_->SetNeedsBeginFrames(false);
begin_retro_frame_args_.clear();
+ begin_retro_frame_task_.Cancel();
+ state_machine_.DidLoseOutputSurface();
ProcessScheduledActions();
}
@@ -302,69 +290,35 @@ base::TimeTicks Scheduler::LastBeginImplFrameTime() {
}
void Scheduler::SetupNextBeginFrameIfNeeded() {
- if (!task_runner_.get())
- return;
-
- bool needs_begin_frame = state_machine_.BeginFrameNeeded();
-
- bool at_end_of_deadline =
- (state_machine_.begin_impl_frame_state() ==
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
-
- bool should_call_set_needs_begin_frame =
- // Always request the BeginFrame immediately if it wasn't needed before.
- (needs_begin_frame && !frame_source_->NeedsBeginFrames()) ||
- // Only stop requesting BeginFrames after a deadline.
- (!needs_begin_frame && frame_source_->NeedsBeginFrames() &&
- at_end_of_deadline);
-
- if (should_call_set_needs_begin_frame) {
- frame_source_->SetNeedsBeginFrames(needs_begin_frame);
- }
-
- if (at_end_of_deadline) {
- frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
+ // Never call SetNeedsBeginFrames if the frame source already has the right
+ // value.
+ if (frame_source_->NeedsBeginFrames() != state_machine_.BeginFrameNeeded()) {
+ if (state_machine_.BeginFrameNeeded()) {
+ // Call SetNeedsBeginFrames(true) as soon as possible.
+ frame_source_->SetNeedsBeginFrames(true);
+ } else if (state_machine_.begin_impl_frame_state() ==
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) {
+ // Call SetNeedsBeginFrames(false) in between frames only.
+ frame_source_->SetNeedsBeginFrames(false);
+ client_->SendBeginMainFrameNotExpectedSoon();
+ }
}
PostBeginRetroFrameIfNeeded();
- SetupPollingMechanisms(needs_begin_frame);
}
// We may need to poll when we can't rely on BeginFrame to advance certain
// state or to avoid deadlock.
-void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
- bool needs_advance_commit_state_timer = false;
- // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
- // aren't expecting any more BeginFrames. This should only be needed by
- // the synchronous compositor when BeginFrameNeeded is false.
- if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
- DCHECK(!state_machine_.SupportsProactiveBeginFrame());
- DCHECK(!needs_begin_frame);
- if (poll_for_draw_triggers_task_.IsCancelled()) {
- poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
- base::TimeDelta delay = begin_impl_frame_args_.IsValid()
- ? begin_impl_frame_args_.interval
- : BeginFrameArgs::DefaultInterval();
- task_runner_->PostDelayedTask(
- FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
- }
- } else {
- poll_for_draw_triggers_task_.Cancel();
-
- // At this point we'd prefer to advance through the commit flow by
- // drawing a frame, however it's possible that the frame rate controller
- // will not give us a BeginFrame until the commit completes. See
- // crbug.com/317430 for an example of a swap ack being held on commit. Thus
- // we set a repeating timer to poll on ProcessScheduledActions until we
- // successfully reach BeginFrame. Synchronous compositor does not use
- // frame rate controller or have the circular wait in the bug.
- if (IsBeginMainFrameSentOrStarted() &&
- !settings_.using_synchronous_renderer_compositor) {
- needs_advance_commit_state_timer = true;
- }
- }
-
- if (needs_advance_commit_state_timer) {
+void Scheduler::SetupPollingMechanisms() {
+ // At this point we'd prefer to advance through the commit flow by
+ // drawing a frame, however it's possible that the frame rate controller
+ // will not give us a BeginFrame until the commit completes. See
+ // crbug.com/317430 for an example of a swap ack being held on commit. Thus
+ // we set a repeating timer to poll on ProcessScheduledActions until we
+ // successfully reach BeginFrame. Synchronous compositor does not use
+ // frame rate controller or have the circular wait in the bug.
+ if (IsBeginMainFrameSentOrStarted() &&
+ !settings_.using_synchronous_renderer_compositor) {
if (advance_commit_state_task_.IsCancelled() &&
begin_impl_frame_args_.IsValid()) {
// Since we'd rather get a BeginImplFrame by the normal mechanism, we
@@ -384,31 +338,38 @@ void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
// If the scheduler is busy, we queue the BeginFrame to be handled later as
// a BeginRetroFrame.
bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
- TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue());
+ TRACE_EVENT1("cc,benchmark", "Scheduler::BeginFrame", "args", args.AsValue());
+
+ // TODO(brianderson): Adjust deadline in the DisplayScheduler.
+ BeginFrameArgs adjusted_args(args);
+ adjusted_args.deadline -= EstimatedParentDrawTime();
+
+ // Deliver BeginFrames to children.
+ // TODO(brianderson): Move this responsibility to the DisplayScheduler.
+ if (state_machine_.children_need_begin_frames())
+ client_->SendBeginFramesToChildren(adjusted_args);
+
+ if (settings_.using_synchronous_renderer_compositor) {
+ BeginImplFrameSynchronous(adjusted_args);
+ return true;
+ }
// We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has
// sent us the last BeginFrame we have missed. As we might not be able to
// actually make rendering for this call, handle it like a "retro frame".
// TODO(brainderson): Add a test for this functionality ASAP!
- if (args.type == BeginFrameArgs::MISSED) {
- begin_retro_frame_args_.push_back(args);
+ if (adjusted_args.type == BeginFrameArgs::MISSED) {
+ begin_retro_frame_args_.push_back(adjusted_args);
PostBeginRetroFrameIfNeeded();
return true;
}
- BeginFrameArgs adjusted_args(args);
- adjusted_args.deadline -= EstimatedParentDrawTime();
-
- bool should_defer_begin_frame;
- if (settings_.using_synchronous_renderer_compositor) {
- should_defer_begin_frame = false;
- } else {
- should_defer_begin_frame =
- !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
- !frame_source_->NeedsBeginFrames() ||
- (state_machine_.begin_impl_frame_state() !=
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
- }
+ bool should_defer_begin_frame =
+ !begin_retro_frame_args_.empty() ||
+ !begin_retro_frame_task_.IsCancelled() ||
+ !frame_source_->NeedsBeginFrames() ||
+ (state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
if (should_defer_begin_frame) {
begin_retro_frame_args_.push_back(adjusted_args);
@@ -416,23 +377,51 @@ bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
"cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
// Queuing the frame counts as "using it", so we need to return true.
} else {
- BeginImplFrame(adjusted_args);
+ BeginImplFrameWithDeadline(adjusted_args);
}
return true;
}
+void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
+ state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames);
+ ProcessScheduledActions();
+}
+
+void Scheduler::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) {
+ authoritative_vsync_interval_ = interval;
+ if (vsync_observer_)
+ vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval);
+}
+
+void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) {
+ state_machine_.SetVideoNeedsBeginFrames(video_needs_begin_frames);
+ ProcessScheduledActions();
+}
+
+void Scheduler::OnDrawForOutputSurface() {
+ DCHECK(settings_.using_synchronous_renderer_compositor);
+ DCHECK_EQ(state_machine_.begin_impl_frame_state(),
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ DCHECK(!BeginImplFrameDeadlinePending());
+
+ state_machine_.OnBeginImplFrameDeadline();
+ ProcessScheduledActions();
+
+ state_machine_.OnBeginImplFrameIdle();
+ ProcessScheduledActions();
+}
+
// BeginRetroFrame is called for BeginFrames that we've deferred because
// the scheduler was in the middle of processing a previous BeginFrame.
void Scheduler::BeginRetroFrame() {
- TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
+ TRACE_EVENT0("cc,benchmark", "Scheduler::BeginRetroFrame");
DCHECK(!settings_.using_synchronous_renderer_compositor);
- DCHECK(begin_retro_frame_posted_);
- begin_retro_frame_posted_ = false;
+ DCHECK(!begin_retro_frame_args_.empty());
+ DCHECK(!begin_retro_frame_task_.IsCancelled());
+ DCHECK_EQ(state_machine_.begin_impl_frame_state(),
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
- // If there aren't any retroactive BeginFrames, then we've lost the
- // OutputSurface and should abort.
- if (begin_retro_frame_args_.empty())
- return;
+ begin_retro_frame_task_.Cancel();
// Discard expired BeginRetroFrames
// Today, we should always end up with at most one un-expired BeginRetroFrame
@@ -442,20 +431,16 @@ void Scheduler::BeginRetroFrame() {
// draining the queue if we don't catch up. If we consistently can't catch
// up, our fallback should be to lower our frame rate.
base::TimeTicks now = Now();
- base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
+
while (!begin_retro_frame_args_.empty()) {
- base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline(
- begin_retro_frame_args_.front(), draw_duration_estimate);
- if (now <= adjusted_deadline)
+ const BeginFrameArgs& args = begin_retro_frame_args_.front();
+ base::TimeTicks expiration_time = args.frame_time + args.interval;
+ if (now <= expiration_time)
break;
-
- TRACE_EVENT_INSTANT2("cc",
- "Scheduler::BeginRetroFrame discarding",
- TRACE_EVENT_SCOPE_THREAD,
- "deadline - now",
- (adjusted_deadline - now).InMicroseconds(),
- "BeginFrameArgs",
- begin_retro_frame_args_.front().AsValue());
+ TRACE_EVENT_INSTANT2(
+ "cc", "Scheduler::BeginRetroFrame discarding", TRACE_EVENT_SCOPE_THREAD,
+ "expiration_time - now", (expiration_time - now).InMillisecondsF(),
+ "BeginFrameArgs", begin_retro_frame_args_.front().AsValue());
begin_retro_frame_args_.pop_front();
frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
}
@@ -465,8 +450,9 @@ void Scheduler::BeginRetroFrame() {
"Scheduler::BeginRetroFrames all expired",
TRACE_EVENT_SCOPE_THREAD);
} else {
- BeginImplFrame(begin_retro_frame_args_.front());
+ BeginFrameArgs front = begin_retro_frame_args_.front();
begin_retro_frame_args_.pop_front();
+ BeginImplFrameWithDeadline(front);
}
}
@@ -482,7 +468,7 @@ void Scheduler::PostBeginRetroFrameIfNeeded() {
if (!frame_source_->NeedsBeginFrames())
return;
- if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
+ if (begin_retro_frame_args_.empty() || !begin_retro_frame_task_.IsCancelled())
return;
// begin_retro_frame_args_ should always be empty for the
@@ -493,34 +479,24 @@ void Scheduler::PostBeginRetroFrameIfNeeded() {
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
return;
- begin_retro_frame_posted_ = true;
- task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
+ begin_retro_frame_task_.Reset(begin_retro_frame_closure_);
+
+ task_runner_->PostTask(FROM_HERE, begin_retro_frame_task_.callback());
}
-// BeginImplFrame starts a compositor frame that will wait up until a deadline
-// for a BeginMainFrame+activation to complete before it times out and draws
-// any asynchronous animation and scroll/pinch updates.
-void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
+void Scheduler::BeginImplFrameWithDeadline(const BeginFrameArgs& args) {
bool main_thread_is_in_high_latency_mode =
state_machine_.MainThreadIsInHighLatencyMode();
- TRACE_EVENT2("cc",
- "Scheduler::BeginImplFrame",
- "args",
- args.AsValue(),
- "main_thread_is_high_latency",
+ TRACE_EVENT2("cc,benchmark", "Scheduler::BeginImplFrame", "args",
+ args.AsValue(), "main_thread_is_high_latency",
main_thread_is_in_high_latency_mode);
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
- "MainThreadLatency",
- main_thread_is_in_high_latency_mode);
- DCHECK_EQ(state_machine_.begin_impl_frame_state(),
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
- DCHECK(state_machine_.HasInitializedOutputSurface());
+ "MainThreadLatency", main_thread_is_in_high_latency_mode);
advance_commit_state_task_.Cancel();
- base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
begin_impl_frame_args_ = args;
- begin_impl_frame_args_.deadline -= draw_duration_estimate;
+ begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
if (!state_machine_.impl_latency_takes_priority() &&
main_thread_is_in_high_latency_mode &&
@@ -528,68 +504,115 @@ void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
}
- client_->WillBeginImplFrame(begin_impl_frame_args_);
- state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
- devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
+ BeginImplFrame();
+ // The deadline will be scheduled in ProcessScheduledActions.
+ state_machine_.OnBeginImplFrameDeadlinePending();
ProcessScheduledActions();
+}
- state_machine_.OnBeginImplFrameDeadlinePending();
- ScheduleBeginImplFrameDeadline(
- AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+void Scheduler::BeginImplFrameSynchronous(const BeginFrameArgs& args) {
+ TRACE_EVENT1("cc,benchmark", "Scheduler::BeginImplFrame", "args",
+ args.AsValue());
+ begin_impl_frame_args_ = args;
+ BeginImplFrame();
+ FinishImplFrame();
}
-base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
- const BeginFrameArgs& args,
- base::TimeDelta draw_duration_estimate) const {
- if (settings_.using_synchronous_renderer_compositor) {
- // The synchronous compositor needs to draw right away.
- return base::TimeTicks();
- } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
- // We are ready to draw a new active tree immediately.
- return base::TimeTicks();
- } else if (state_machine_.needs_redraw()) {
- // We have an animation or fast input path on the impl thread that wants
- // to draw, so don't wait too long for a new active tree.
- return args.deadline - draw_duration_estimate;
- } else {
- // The impl thread doesn't have anything it wants to draw and we are just
- // waiting for a new active tree, so post the deadline for the next
- // expected BeginImplFrame start. This allows us to draw immediately when
- // there is a new active tree, instead of waiting for the next
- // BeginImplFrame.
- // TODO(brianderson): Handle long deadlines (that are past the next frame's
- // frame time) properly instead of using this hack.
- return args.frame_time + args.interval;
- }
+void Scheduler::FinishImplFrame() {
+ state_machine_.OnBeginImplFrameIdle();
+ ProcessScheduledActions();
+
+ client_->DidFinishImplFrame();
+ frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
}
-void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
- TRACE_EVENT1(
- "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
- if (settings_.using_synchronous_renderer_compositor) {
- // The synchronous renderer compositor has to make its GL calls
- // within this call.
- // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
- // so the sychronous renderer compositor can take advantage of splitting
- // up the BeginImplFrame and deadline as well.
- OnBeginImplFrameDeadline();
- return;
- }
+// BeginImplFrame starts a compositor frame that will wait up until a deadline
+// for a BeginMainFrame+activation to complete before it times out and draws
+// any asynchronous animation and scroll/pinch updates.
+void Scheduler::BeginImplFrame() {
+ DCHECK_EQ(state_machine_.begin_impl_frame_state(),
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ DCHECK(!BeginImplFrameDeadlinePending());
+ DCHECK(state_machine_.HasInitializedOutputSurface());
+ DCHECK(advance_commit_state_task_.IsCancelled());
+
+ state_machine_.OnBeginImplFrame();
+ devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
+ client_->WillBeginImplFrame(begin_impl_frame_args_);
+
+ ProcessScheduledActions();
+}
+
+void Scheduler::ScheduleBeginImplFrameDeadline() {
+ // The synchronous compositor does not post a deadline task.
+ DCHECK(!settings_.using_synchronous_renderer_compositor);
+
begin_impl_frame_deadline_task_.Cancel();
begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
- base::TimeDelta delta = deadline - Now();
- if (delta <= base::TimeDelta())
- delta = base::TimeDelta();
+ begin_impl_frame_deadline_mode_ =
+ state_machine_.CurrentBeginImplFrameDeadlineMode();
+
+ base::TimeTicks deadline;
+ switch (begin_impl_frame_deadline_mode_) {
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE:
+ // No deadline.
+ return;
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
+ // We are ready to draw a new active tree immediately.
+ // We don't use Now() here because it's somewhat expensive to call.
+ deadline = base::TimeTicks();
+ break;
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
+ // We are animating on the impl thread but we can wait for some time.
+ deadline = begin_impl_frame_args_.deadline;
+ break;
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
+ // We are blocked for one reason or another and we should wait.
+ // TODO(brianderson): Handle long deadlines (that are past the next
+ // frame's frame time) properly instead of using this hack.
+ deadline =
+ begin_impl_frame_args_.frame_time + begin_impl_frame_args_.interval;
+ break;
+ case SchedulerStateMachine::
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW:
+ // We are blocked because we are waiting for ReadyToDraw signal. We would
+ // post deadline after we received ReadyToDraw singal.
+ TRACE_EVENT1("cc", "Scheduler::ScheduleBeginImplFrameDeadline",
+ "deadline_mode", "blocked_on_ready_to_draw");
+ return;
+ }
+
+ TRACE_EVENT2("cc", "Scheduler::ScheduleBeginImplFrameDeadline", "mode",
+ SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
+ begin_impl_frame_deadline_mode_),
+ "deadline", deadline);
+
+ base::TimeDelta delta = std::max(deadline - Now(), base::TimeDelta());
task_runner_->PostDelayedTask(
FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
}
+void Scheduler::ScheduleBeginImplFrameDeadlineIfNeeded() {
+ if (settings_.using_synchronous_renderer_compositor)
+ return;
+
+ if (state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
+ return;
+
+ if (begin_impl_frame_deadline_mode_ ==
+ state_machine_.CurrentBeginImplFrameDeadlineMode() &&
+ BeginImplFrameDeadlinePending())
+ return;
+
+ ScheduleBeginImplFrameDeadline();
+}
+
void Scheduler::OnBeginImplFrameDeadline() {
- TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
+ TRACE_EVENT0("cc,benchmark", "Scheduler::OnBeginImplFrameDeadline");
begin_impl_frame_deadline_task_.Cancel();
-
// We split the deadline actions up into two phases so the state machine
// has a chance to trigger actions that should occur durring and after
// the deadline separately. For example:
@@ -597,21 +620,16 @@ void Scheduler::OnBeginImplFrameDeadline() {
// order to wait for more user-input before starting the next commit.
// * Creating a new OuputSurface will not occur during the deadline in
// order to allow the state machine to "settle" first.
+
+ // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 Scheduler::OnBeginImplFrameDeadline1"));
state_machine_.OnBeginImplFrameDeadline();
ProcessScheduledActions();
- state_machine_.OnBeginImplFrameIdle();
- ProcessScheduledActions();
-
- client_->DidBeginImplFrameDeadline();
+ FinishImplFrame();
}
-void Scheduler::PollForAnticipatedDrawTriggers() {
- TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
- poll_for_draw_triggers_task_.Cancel();
- state_machine_.DidEnterPollForAnticipatedDrawTriggers();
- ProcessScheduledActions();
- state_machine_.DidLeavePollForAnticipatedDrawTriggers();
-}
void Scheduler::PollToAdvanceCommitState() {
TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
@@ -624,6 +642,14 @@ void Scheduler::DrawAndSwapIfPossible() {
state_machine_.DidDrawIfPossibleCompleted(result);
}
+void Scheduler::SetDeferCommits(bool defer_commits) {
+ TRACE_EVENT1("cc", "Scheduler::SetDeferCommits",
+ "defer_commits",
+ defer_commits);
+ state_machine_.SetDeferCommits(defer_commits);
+ ProcessScheduledActions();
+}
+
void Scheduler::ProcessScheduledActions() {
// We do not allow ProcessScheduledActions to be recursive.
// The top-level call will iteratively execute the next action for us anyway.
@@ -654,18 +680,27 @@ void Scheduler::ProcessScheduledActions() {
case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
client_->ScheduledActionSendBeginMainFrame();
break;
- case SchedulerStateMachine::ACTION_COMMIT:
+ case SchedulerStateMachine::ACTION_COMMIT: {
+ // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 Scheduler::ProcessScheduledActions4"));
client_->ScheduledActionCommit();
break;
- case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
- client_->ScheduledActionUpdateVisibleTiles();
- break;
+ }
case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
client_->ScheduledActionActivateSyncTree();
break;
- case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
+ case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
+ // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile6(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 Scheduler::ProcessScheduledActions6"));
DrawAndSwapIfPossible();
break;
+ }
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
client_->ScheduledActionDrawAndSwapForced();
break;
@@ -676,36 +711,36 @@ void Scheduler::ProcessScheduledActions() {
case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
client_->ScheduledActionBeginOutputSurfaceCreation();
break;
- case SchedulerStateMachine::ACTION_MANAGE_TILES:
- client_->ScheduledActionManageTiles();
+ case SchedulerStateMachine::ACTION_PREPARE_TILES:
+ client_->ScheduledActionPrepareTiles();
+ break;
+ case SchedulerStateMachine::ACTION_INVALIDATE_OUTPUT_SURFACE: {
+ client_->ScheduledActionInvalidateOutputSurface();
break;
+ }
}
} while (action != SchedulerStateMachine::ACTION_NONE);
- SetupNextBeginFrameIfNeeded();
+ SetupPollingMechanisms();
+
client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
- if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
- DCHECK(!settings_.using_synchronous_renderer_compositor);
- ScheduleBeginImplFrameDeadline(base::TimeTicks());
- }
-}
+ ScheduleBeginImplFrameDeadlineIfNeeded();
-bool Scheduler::WillDrawIfNeeded() const {
- return !state_machine_.PendingDrawsShouldBeAborted();
+ SetupNextBeginFrameIfNeeded();
}
-scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue()
+scoped_refptr<base::trace_event::ConvertableToTraceFormat> Scheduler::AsValue()
const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
AsValueInto(state.get());
return state;
}
-void Scheduler::AsValueInto(base::debug::TracedValue* state) const {
+void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const {
state->BeginDictionary("state_machine");
- state_machine_.AsValueInto(state, Now());
+ state_machine_.AsValueInto(state);
state->EndDictionary();
// Only trace frame sources when explicitly enabled - http://crbug.com/420607
@@ -726,18 +761,34 @@ void Scheduler::AsValueInto(base::debug::TracedValue* state) const {
estimated_parent_draw_time_.InMillisecondsF());
state->SetBoolean("last_set_needs_begin_frame_",
frame_source_->NeedsBeginFrames());
- state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_);
state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
+ state->SetBoolean("begin_retro_frame_task_",
+ !begin_retro_frame_task_.IsCancelled());
state->SetBoolean("begin_impl_frame_deadline_task_",
!begin_impl_frame_deadline_task_.IsCancelled());
- state->SetBoolean("poll_for_draw_triggers_task_",
- !poll_for_draw_triggers_task_.IsCancelled());
state->SetBoolean("advance_commit_state_task_",
!advance_commit_state_task_.IsCancelled());
state->BeginDictionary("begin_impl_frame_args");
begin_impl_frame_args_.AsValueInto(state);
state->EndDictionary();
+ base::TimeTicks now = Now();
+ base::TimeTicks frame_time = begin_impl_frame_args_.frame_time;
+ base::TimeTicks deadline = begin_impl_frame_args_.deadline;
+ base::TimeDelta interval = begin_impl_frame_args_.interval;
+ state->BeginDictionary("major_timestamps_in_ms");
+ state->SetDouble("0_interval", interval.InMillisecondsF());
+ state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF());
+ state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF());
+ state->SetDouble("3_frame_time_to_deadline",
+ (deadline - frame_time).InMillisecondsF());
+ state->SetDouble("4_now", (now - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble("5_frame_time",
+ (frame_time - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble("6_deadline",
+ (deadline - base::TimeTicks()).InMillisecondsF());
+ state->EndDictionary();
+
state->EndDictionary();
state->BeginDictionary("client_state");
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index f470d17a9e7..13daf008cc3 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -11,8 +11,6 @@
#include "base/basictypes.h"
#include "base/cancelable_callback.h"
#include "base/memory/scoped_ptr.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/power_monitor/power_observer.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/begin_frame_args.h"
@@ -24,7 +22,7 @@
#include "cc/scheduler/scheduler_state_machine.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
}
class SingleThreadTaskRunner;
@@ -34,22 +32,23 @@ namespace cc {
class SchedulerClient {
public:
- virtual BeginFrameSource* ExternalBeginFrameSource() = 0;
virtual void WillBeginImplFrame(const BeginFrameArgs& args) = 0;
virtual void ScheduledActionSendBeginMainFrame() = 0;
virtual DrawResult ScheduledActionDrawAndSwapIfPossible() = 0;
virtual DrawResult ScheduledActionDrawAndSwapForced() = 0;
virtual void ScheduledActionAnimate() = 0;
virtual void ScheduledActionCommit() = 0;
- virtual void ScheduledActionUpdateVisibleTiles() = 0;
virtual void ScheduledActionActivateSyncTree() = 0;
virtual void ScheduledActionBeginOutputSurfaceCreation() = 0;
- virtual void ScheduledActionManageTiles() = 0;
+ virtual void ScheduledActionPrepareTiles() = 0;
+ virtual void ScheduledActionInvalidateOutputSurface() = 0;
virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) = 0;
virtual base::TimeDelta DrawDurationEstimate() = 0;
virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() = 0;
virtual base::TimeDelta CommitToActivateDurationEstimate() = 0;
- virtual void DidBeginImplFrameDeadline() = 0;
+ virtual void DidFinishImplFrame() = 0;
+ virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) = 0;
+ virtual void SendBeginMainFrameNotExpectedSoon() = 0;
protected:
virtual ~SchedulerClient() {}
@@ -64,7 +63,7 @@ class CC_EXPORT SchedulerFrameSourcesConstructor {
public:
virtual ~SchedulerFrameSourcesConstructor() {}
virtual BeginFrameSource* ConstructPrimaryFrameSource(Scheduler* scheduler);
- virtual BeginFrameSource* ConstructBackgroundFrameSource(
+ virtual BeginFrameSource* ConstructUnthrottledFrameSource(
Scheduler* scheduler);
protected:
@@ -73,28 +72,29 @@ class CC_EXPORT SchedulerFrameSourcesConstructor {
friend class Scheduler;
};
-class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
- public base::PowerObserver {
+class CC_EXPORT Scheduler : public BeginFrameObserverMixIn {
public:
static scoped_ptr<Scheduler> Create(
SchedulerClient* client,
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor) {
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
SchedulerFrameSourcesConstructor frame_sources_constructor;
return make_scoped_ptr(new Scheduler(client,
scheduler_settings,
layer_tree_host_id,
task_runner,
- power_monitor,
+ external_begin_frame_source.Pass(),
&frame_sources_constructor));
}
~Scheduler() override;
- // base::PowerObserver method.
- void OnPowerStateChange(bool on_battery_power) override;
+ // BeginFrameObserverMixin
+ bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override;
+
+ void OnDrawForOutputSurface();
const SchedulerSettings& settings() const { return settings_; }
@@ -107,6 +107,8 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
void SetVisible(bool visible);
void SetCanDraw(bool can_draw);
void NotifyReadyToActivate();
+ void NotifyReadyToDraw();
+ void SetThrottleFrameProduction(bool throttle);
void SetNeedsCommit();
@@ -114,19 +116,20 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
void SetNeedsAnimate();
- void SetNeedsManageTiles();
+ void SetNeedsPrepareTiles();
+
+ void SetWaitForReadyToDraw();
void SetMaxSwapsPending(int max);
void DidSwapBuffers();
- void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
void DidSwapBuffersComplete();
void SetImplLatencyTakesPriority(bool impl_latency_takes_priority);
void NotifyReadyToCommit();
- void BeginMainFrameAborted(bool did_handle);
+ void BeginMainFrameAborted(CommitEarlyOutReason reason);
- void DidManageTiles();
+ void DidPrepareTiles();
void DidLoseOutputSurface();
void DidCreateAndInitializeOutputSurface();
@@ -139,8 +142,8 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
bool CommitPending() const { return state_machine_.CommitPending(); }
bool RedrawPending() const { return state_machine_.RedrawPending(); }
- bool ManageTilesPending() const {
- return state_machine_.ManageTilesPending();
+ bool PrepareTilesPending() const {
+ return state_machine_.PrepareTilesPending();
}
bool MainThreadIsInHighLatencyMode() const {
return state_machine_.MainThreadIsInHighLatencyMode();
@@ -149,30 +152,32 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
return !begin_impl_frame_deadline_task_.IsCancelled();
}
- bool WillDrawIfNeeded() const;
-
base::TimeTicks AnticipatedDrawTime() const;
void NotifyBeginMainFrameStarted();
base::TimeTicks LastBeginImplFrameTime();
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
- void AsValueInto(base::debug::TracedValue* value) const override;
+ void SetDeferCommits(bool defer_commits);
+
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* value) const override;
void SetContinuousPainting(bool continuous_painting) {
state_machine_.SetContinuousPainting(continuous_painting);
}
- // BeginFrameObserverMixin
- bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override;
+ void SetChildrenNeedBeginFrames(bool children_need_begin_frames);
+ void SetVideoNeedsBeginFrames(bool video_needs_begin_frames);
+
+ void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval);
protected:
Scheduler(SchedulerClient* client,
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source,
SchedulerFrameSourcesConstructor* frame_sources_constructor);
// virtual for testing - Don't call these in the constructor or
@@ -181,35 +186,35 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
scoped_ptr<BeginFrameSourceMultiplexer> frame_source_;
BeginFrameSource* primary_frame_source_;
- BeginFrameSource* background_frame_source_;
+ BeginFrameSource* unthrottled_frame_source_;
// Storage when frame sources are internal
scoped_ptr<BeginFrameSource> primary_frame_source_internal_;
- scoped_ptr<SyntheticBeginFrameSource> background_frame_source_internal_;
+ scoped_ptr<BeginFrameSource> unthrottled_frame_source_internal_;
VSyncParameterObserver* vsync_observer_;
+ base::TimeDelta authoritative_vsync_interval_;
+ base::TimeTicks last_vsync_timebase_;
+
+ bool throttle_frame_production_;
const SchedulerSettings settings_;
SchedulerClient* client_;
int layer_tree_host_id_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- base::PowerMonitor* power_monitor_;
-
base::TimeDelta estimated_parent_draw_time_;
- bool begin_retro_frame_posted_;
std::deque<BeginFrameArgs> begin_retro_frame_args_;
BeginFrameArgs begin_impl_frame_args_;
+ SchedulerStateMachine::BeginImplFrameDeadlineMode
+ begin_impl_frame_deadline_mode_;
base::Closure begin_retro_frame_closure_;
- base::Closure begin_unthrottled_frame_closure_;
-
base::Closure begin_impl_frame_deadline_closure_;
- base::Closure poll_for_draw_triggers_closure_;
base::Closure advance_commit_state_closure_;
+ base::CancelableClosure begin_retro_frame_task_;
base::CancelableClosure begin_impl_frame_deadline_task_;
- base::CancelableClosure poll_for_draw_triggers_task_;
base::CancelableClosure advance_commit_state_task_;
SchedulerStateMachine state_machine_;
@@ -217,25 +222,23 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
SchedulerStateMachine::Action inside_action_;
private:
- base::TimeTicks AdjustedBeginImplFrameDeadline(
- const BeginFrameArgs& args,
- base::TimeDelta draw_duration_estimate) const;
- void ScheduleBeginImplFrameDeadline(base::TimeTicks deadline);
+ void ScheduleBeginImplFrameDeadline();
+ void ScheduleBeginImplFrameDeadlineIfNeeded();
void SetupNextBeginFrameIfNeeded();
void PostBeginRetroFrameIfNeeded();
- void SetupPollingMechanisms(bool needs_begin_frame);
+ void SetupPollingMechanisms();
void DrawAndSwapIfPossible();
void ProcessScheduledActions();
bool CanCommitAndActivateBeforeDeadline() const;
void AdvanceCommitStateIfPossible();
bool IsBeginMainFrameSentOrStarted() const;
void BeginRetroFrame();
- void BeginImplFrame(const BeginFrameArgs& args);
+ void BeginImplFrameWithDeadline(const BeginFrameArgs& args);
+ void BeginImplFrameSynchronous(const BeginFrameArgs& args);
+ void BeginImplFrame();
+ void FinishImplFrame();
void OnBeginImplFrameDeadline();
- void PollForAnticipatedDrawTriggers();
void PollToAdvanceCommitState();
- void SetupPowerMonitoring();
- void TeardownPowerMonitoring();
base::TimeDelta EstimatedParentDrawTime() {
return estimated_parent_draw_time_;
diff --git a/chromium/cc/scheduler/scheduler_settings.cc b/chromium/cc/scheduler/scheduler_settings.cc
index ab9add087bd..c6c8e8eb2db 100644
--- a/chromium/cc/scheduler/scheduler_settings.cc
+++ b/chromium/cc/scheduler/scheduler_settings.cc
@@ -4,46 +4,30 @@
#include "cc/scheduler/scheduler_settings.h"
-#include "base/debug/trace_event_argument.h"
-#include "cc/trees/layer_tree_settings.h"
+#include "base/trace_event/trace_event_argument.h"
namespace cc {
SchedulerSettings::SchedulerSettings()
- : begin_frame_scheduling_enabled(true),
+ : use_external_begin_frame_source(false),
main_frame_before_activation_enabled(false),
impl_side_painting(false),
timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
using_synchronous_renderer_compositor(false),
throttle_frame_production(true),
- disable_hi_res_timer_tasks_on_battery(false) {
-}
-
-SchedulerSettings::SchedulerSettings(const LayerTreeSettings& settings)
- : begin_frame_scheduling_enabled(settings.begin_frame_scheduling_enabled),
- main_frame_before_activation_enabled(
- settings.main_frame_before_activation_enabled),
- impl_side_painting(settings.impl_side_painting),
- timeout_and_draw_when_animation_checkerboards(
- settings.timeout_and_draw_when_animation_checkerboards),
- maximum_number_of_failed_draws_before_draw_is_forced_(
- settings.maximum_number_of_failed_draws_before_draw_is_forced_),
- using_synchronous_renderer_compositor(
- settings.using_synchronous_renderer_compositor),
- throttle_frame_production(settings.throttle_frame_production),
- disable_hi_res_timer_tasks_on_battery(
- settings.disable_hi_res_timer_tasks_on_battery) {
+ main_thread_should_always_be_low_latency(false),
+ background_frame_interval(base::TimeDelta::FromSeconds(1)) {
}
SchedulerSettings::~SchedulerSettings() {}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
SchedulerSettings::AsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
- state->SetBoolean("begin_frame_scheduling_enabled",
- begin_frame_scheduling_enabled);
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
+ state->SetBoolean("use_external_begin_frame_source",
+ use_external_begin_frame_source);
state->SetBoolean("main_frame_before_activation_enabled",
main_frame_before_activation_enabled);
state->SetBoolean("impl_side_painting", impl_side_painting);
@@ -54,8 +38,10 @@ SchedulerSettings::AsValue() const {
state->SetBoolean("using_synchronous_renderer_compositor",
using_synchronous_renderer_compositor);
state->SetBoolean("throttle_frame_production", throttle_frame_production);
- state->SetBoolean("disable_hi_res_timer_tasks_on_battery",
- disable_hi_res_timer_tasks_on_battery);
+ state->SetBoolean("main_thread_should_always_be_low_latency",
+ main_thread_should_always_be_low_latency);
+ state->SetInteger("background_frame_interval",
+ background_frame_interval.InMicroseconds());
return state;
}
diff --git a/chromium/cc/scheduler/scheduler_settings.h b/chromium/cc/scheduler/scheduler_settings.h
index 8607991914e..421409ab4dc 100644
--- a/chromium/cc/scheduler/scheduler_settings.h
+++ b/chromium/cc/scheduler/scheduler_settings.h
@@ -6,34 +6,40 @@
#define CC_SCHEDULER_SCHEDULER_SETTINGS_H_
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "cc/base/cc_export.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
}
}
namespace cc {
-class LayerTreeSettings;
class CC_EXPORT SchedulerSettings {
public:
SchedulerSettings();
- explicit SchedulerSettings(const LayerTreeSettings& settings);
~SchedulerSettings();
- bool begin_frame_scheduling_enabled;
+ bool use_external_begin_frame_source;
bool main_frame_before_activation_enabled;
bool impl_side_painting;
bool timeout_and_draw_when_animation_checkerboards;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool using_synchronous_renderer_compositor;
bool throttle_frame_production;
- bool disable_hi_res_timer_tasks_on_battery;
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
+ // In main thread low latency mode the entire
+ // BeginMainFrame->Commit->Activation->Draw cycle should complete before
+ // starting the next cycle. Additionally, BeginMainFrame and Commit are
+ // completed atomically with no other tasks or actions occuring between them.
+ bool main_thread_should_always_be_low_latency;
+
+ base::TimeDelta background_frame_interval;
+
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
};
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc
index 2b8210d2d2f..e303d3ab48a 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine.cc
@@ -4,11 +4,11 @@
#include "cc/scheduler/scheduler_state_machine.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "ui/gfx/frame_time.h"
@@ -26,30 +26,37 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
last_frame_number_swap_performed_(-1),
last_frame_number_swap_requested_(-1),
last_frame_number_begin_main_frame_sent_(-1),
- last_frame_number_update_visible_tiles_was_called_(-1),
- manage_tiles_funnel_(0),
+ last_frame_number_invalidate_output_surface_performed_(-1),
+ animate_funnel_(false),
+ request_swap_funnel_(false),
+ send_begin_main_frame_funnel_(false),
+ invalidate_output_surface_funnel_(false),
+ prepare_tiles_funnel_(0),
consecutive_checkerboard_animations_(0),
max_pending_swaps_(1),
pending_swaps_(0),
needs_redraw_(false),
needs_animate_(false),
- needs_manage_tiles_(false),
- swap_used_incomplete_tile_(false),
+ needs_prepare_tiles_(false),
needs_commit_(false),
- inside_poll_for_anticipated_draw_triggers_(false),
visible_(false),
can_start_(false),
can_draw_(false),
has_pending_tree_(false),
pending_tree_is_ready_for_activation_(false),
active_tree_needs_first_draw_(false),
- did_commit_after_animating_(false),
did_create_and_initialize_first_output_surface_(false),
impl_latency_takes_priority_(false),
skip_next_begin_main_frame_to_reduce_latency_(false),
skip_begin_main_frame_to_reduce_latency_(false),
continuous_painting_(false),
- impl_latency_takes_priority_on_battery_(false) {
+ children_need_begin_frames_(false),
+ defer_commits_(false),
+ video_needs_begin_frames_(false),
+ last_commit_had_no_updates_(false),
+ wait_for_active_tree_ready_to_draw_(false),
+ did_request_swap_in_last_frame_(false),
+ did_perform_swap_in_last_draw_(false) {
}
const char* SchedulerStateMachine::OutputSurfaceStateToString(
@@ -86,6 +93,24 @@ const char* SchedulerStateMachine::BeginImplFrameStateToString(
return "???";
}
+const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
+ BeginImplFrameDeadlineMode mode) {
+ switch (mode) {
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW";
+ }
+ NOTREACHED();
+ return "???";
+}
+
const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
switch (state) {
case COMMIT_STATE_IDLE:
@@ -98,6 +123,8 @@ const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
return "COMMIT_STATE_READY_TO_COMMIT";
case COMMIT_STATE_WAITING_FOR_ACTIVATION:
return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
+ case COMMIT_STATE_WAITING_FOR_DRAW:
+ return "COMMIT_STATE_WAITING_FOR_DRAW";
}
NOTREACHED();
return "???";
@@ -129,8 +156,6 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
return "ACTION_SEND_BEGIN_MAIN_FRAME";
case ACTION_COMMIT:
return "ACTION_COMMIT";
- case ACTION_UPDATE_VISIBLE_TILES:
- return "ACTION_UPDATE_VISIBLE_TILES";
case ACTION_ACTIVATE_SYNC_TREE:
return "ACTION_ACTIVATE_SYNC_TREE";
case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
@@ -141,23 +166,25 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
return "ACTION_DRAW_AND_SWAP_ABORT";
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
- case ACTION_MANAGE_TILES:
- return "ACTION_MANAGE_TILES";
+ case ACTION_PREPARE_TILES:
+ return "ACTION_PREPARE_TILES";
+ case ACTION_INVALIDATE_OUTPUT_SURFACE:
+ return "ACTION_INVALIDATE_OUTPUT_SURFACE";
}
NOTREACHED();
return "???";
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
SchedulerStateMachine::AsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
- AsValueInto(state.get(), gfx::FrameTime::Now());
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
+ AsValueInto(state.get());
return state;
}
-void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
- base::TimeTicks now) const {
+void SchedulerStateMachine::AsValueInto(
+ base::trace_event::TracedValue* state) const {
state->BeginDictionary("major_state");
state->SetString("next_action", ActionToString(NextAction()));
state->SetString("begin_impl_frame_state",
@@ -169,35 +196,9 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
state->EndDictionary();
- state->BeginDictionary("major_timestamps_in_ms");
- state->SetDouble("0_interval",
- begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
- state->SetDouble(
- "1_now_to_deadline",
- (begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
- state->SetDouble(
- "2_frame_time_to_now",
- (now - begin_impl_frame_args_.frame_time).InMicroseconds() / 1000.0L);
- state->SetDouble("3_frame_time_to_deadline",
- (begin_impl_frame_args_.deadline -
- begin_impl_frame_args_.frame_time).InMicroseconds() /
- 1000.0L);
- state->SetDouble("4_now",
- (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
- state->SetDouble(
- "5_frame_time",
- (begin_impl_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() /
- 1000.0L);
- state->SetDouble(
- "6_deadline",
- (begin_impl_frame_args_.deadline - base::TimeTicks()).InMicroseconds() /
- 1000.0L);
- state->EndDictionary();
-
state->BeginDictionary("minor_state");
state->SetInteger("commit_count", commit_count_);
state->SetInteger("current_frame_number", current_frame_number_);
-
state->SetInteger("last_frame_number_animate_performed",
last_frame_number_animate_performed_);
state->SetInteger("last_frame_number_swap_performed",
@@ -206,18 +207,20 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
last_frame_number_swap_requested_);
state->SetInteger("last_frame_number_begin_main_frame_sent",
last_frame_number_begin_main_frame_sent_);
- state->SetInteger("last_frame_number_update_visible_tiles_was_called",
- last_frame_number_update_visible_tiles_was_called_);
-
- state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
+ state->SetBoolean("funnel: animate_funnel", animate_funnel_);
+ state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_);
+ state->SetBoolean("funnel: send_begin_main_frame_funnel",
+ send_begin_main_frame_funnel_);
+ state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_);
+ state->SetBoolean("funnel: invalidate_output_surface_funnel",
+ invalidate_output_surface_funnel_);
state->SetInteger("consecutive_checkerboard_animations",
consecutive_checkerboard_animations_);
state->SetInteger("max_pending_swaps_", max_pending_swaps_);
state->SetInteger("pending_swaps_", pending_swaps_);
state->SetBoolean("needs_redraw", needs_redraw_);
state->SetBoolean("needs_animate_", needs_animate_);
- state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
- state->SetBoolean("swap_used_incomplete_tile", swap_used_incomplete_tile_);
+ state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_);
state->SetBoolean("needs_commit", needs_commit_);
state->SetBoolean("visible", visible_);
state->SetBoolean("can_start", can_start_);
@@ -227,7 +230,8 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
pending_tree_is_ready_for_activation_);
state->SetBoolean("active_tree_needs_first_draw",
active_tree_needs_first_draw_);
- state->SetBoolean("did_commit_after_animating", did_commit_after_animating_);
+ state->SetBoolean("wait_for_active_tree_ready_to_draw",
+ wait_for_active_tree_ready_to_draw_);
state->SetBoolean("did_create_and_initialize_first_output_surface",
did_create_and_initialize_first_output_surface_);
state->SetBoolean("impl_latency_takes_priority",
@@ -239,45 +243,17 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency",
skip_next_begin_main_frame_to_reduce_latency_);
state->SetBoolean("continuous_painting", continuous_painting_);
- state->SetBoolean("impl_latency_takes_priority_on_battery",
- impl_latency_takes_priority_on_battery_);
+ state->SetBoolean("children_need_begin_frames", children_need_begin_frames_);
+ state->SetBoolean("video_needs_begin_frames", video_needs_begin_frames_);
+ state->SetBoolean("defer_commits", defer_commits_);
+ state->SetBoolean("last_commit_had_no_updates", last_commit_had_no_updates_);
+ state->SetBoolean("did_request_swap_in_last_frame",
+ did_request_swap_in_last_frame_);
+ state->SetBoolean("did_perform_swap_in_last_draw",
+ did_perform_swap_in_last_draw_);
state->EndDictionary();
}
-void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
- current_frame_number_++;
-
- // "Drain" the ManageTiles funnel.
- if (manage_tiles_funnel_ > 0)
- manage_tiles_funnel_--;
-
- skip_begin_main_frame_to_reduce_latency_ =
- skip_next_begin_main_frame_to_reduce_latency_;
- skip_next_begin_main_frame_to_reduce_latency_ = false;
-}
-
-bool SchedulerStateMachine::HasAnimatedThisFrame() const {
- return last_frame_number_animate_performed_ == current_frame_number_;
-}
-
-bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_begin_main_frame_sent_;
-}
-
-bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_update_visible_tiles_was_called_;
-}
-
-bool SchedulerStateMachine::HasSwappedThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_performed_;
-}
-
-bool SchedulerStateMachine::HasRequestedSwapThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_requested_;
-}
-
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
// These are all the cases where we normally cannot or do not want to draw
// but, if needs_redraw_ is true and we do not draw to make forward progress,
@@ -329,7 +305,7 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE)
return false;
- // We want to clear the pipline of any pending draws and activations
+ // We want to clear the pipeline of any pending draws and activations
// before starting output surface initialization. This allows us to avoid
// weird corner cases where we abort draws or force activation while we
// are initializing the output surface.
@@ -344,19 +320,20 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
bool SchedulerStateMachine::ShouldDraw() const {
// If we need to abort draws, we should do so ASAP since the draw could
// be blocking other important actions (like output surface initialization),
- // from occuring. If we are waiting for the first draw, then perfom the
+ // from occurring. If we are waiting for the first draw, then perform the
// aborted draw to keep things moving. If we are not waiting for the first
// draw however, we don't want to abort for no reason.
if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_;
- // If a commit has occurred after the animate call, we need to call animate
- // again before we should draw.
- if (did_commit_after_animating_)
+ // Do not draw too many times in a single frame. It's okay that we don't check
+ // this before checking for aborted draws because aborted draws do not request
+ // a swap.
+ if (request_swap_funnel_)
return false;
- // After this line, we only want to send a swap request once per frame.
- if (HasRequestedSwapThisFrame())
+ // Don't draw if we are waiting on the first commit after a surface.
+ if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false;
// Do not queue too many swaps.
@@ -394,40 +371,13 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
return pending_tree_is_ready_for_activation_;
}
-bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
- if (!settings_.impl_side_painting)
- return false;
- if (HasUpdatedVisibleTilesThisFrame())
- return false;
-
- // We don't want to update visible tiles right after drawing.
- if (HasRequestedSwapThisFrame())
- return false;
-
- // There's no reason to check for tiles if we don't have an output surface.
- if (!HasInitializedOutputSurface())
- return false;
-
- // We should not check for visible tiles until we've entered the deadline so
- // we check as late as possible and give the tiles more time to initialize.
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
- return false;
-
- // If the last swap drew with checkerboard or missing tiles, we should
- // poll for any new visible tiles so we can be notified to draw again
- // when there are.
- if (swap_used_incomplete_tile_)
- return true;
-
- return false;
-}
-
bool SchedulerStateMachine::ShouldAnimate() const {
- if (!can_draw_)
+ // Do not animate too many times in a single frame.
+ if (animate_funnel_)
return false;
- // If a commit occurred after our last call, we need to do animation again.
- if (HasAnimatedThisFrame() && !did_commit_after_animating_)
+ // Don't animate if we are waiting on the first commit after a surface.
+ if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
@@ -445,6 +395,10 @@ bool SchedulerStateMachine::CouldSendBeginMainFrame() const {
if (!visible_)
return false;
+ // Do not make a new commits when it is deferred.
+ if (defer_commits_)
+ return false;
+
return true;
}
@@ -452,6 +406,10 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (!CouldSendBeginMainFrame())
return false;
+ // Do not send begin main frame too many times in a single frame.
+ if (send_begin_main_frame_funnel_)
+ return false;
+
// Only send BeginMainFrame when there isn't another commit pending already.
if (commit_state_ != COMMIT_STATE_IDLE)
return false;
@@ -463,10 +421,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
return false;
}
- // We want to start the first commit after we get a new output surface ASAP.
- if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
- return true;
-
// We should not send BeginMainFrame while we are in
// BEGIN_IMPL_FRAME_STATE_IDLE since we might have new
// user input arriving soon.
@@ -481,10 +435,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
return true;
- // After this point, we only start a commit once per frame.
- if (HasSentBeginMainFrameThisFrame())
- return false;
-
// We shouldn't normally accept commits if there isn't an OutputSurface.
if (!HasInitializedOutputSurface())
return false;
@@ -493,7 +443,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
// TODO(brianderson): Remove this restriction to improve throughput.
bool just_swapped_in_deadline =
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
- HasSwappedThisFrame();
+ did_perform_swap_in_last_draw_;
if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline)
return false;
@@ -520,25 +470,41 @@ bool SchedulerStateMachine::ShouldCommit() const {
return true;
}
-bool SchedulerStateMachine::ShouldManageTiles() const {
- // ManageTiles only really needs to be called immediately after commit
+bool SchedulerStateMachine::ShouldPrepareTiles() const {
+ // PrepareTiles only really needs to be called immediately after commit
// and then periodically after that. Use a funnel to make sure we average
- // one ManageTiles per BeginImplFrame in the long run.
- if (manage_tiles_funnel_ > 0)
+ // one PrepareTiles per BeginImplFrame in the long run.
+ if (prepare_tiles_funnel_ > 0)
return false;
// Limiting to once per-frame is not enough, since we only want to
- // manage tiles _after_ draws. Polling for draw triggers and
- // begin-frame are mutually exclusive, so we limit to these two cases.
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
- !inside_poll_for_anticipated_draw_triggers_)
+ // prepare tiles _after_ draws.
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
return false;
- return needs_manage_tiles_;
+
+ return needs_prepare_tiles_;
+}
+
+bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const {
+ // Do not invalidate too many times in a frame.
+ if (invalidate_output_surface_funnel_)
+ return false;
+
+ // Only the synchronous compositor requires invalidations.
+ if (!settings_.using_synchronous_renderer_compositor)
+ return false;
+
+ // Invalidations are only performed inside a BeginFrame.
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
+ return false;
+
+ // TODO(sunnyps): needs_prepare_tiles_ is needed here because PrepareTiles is
+ // called only inside the deadline / draw phase. We could remove this if we
+ // allowed PrepareTiles to happen in OnBeginImplFrame.
+ return needs_redraw_ || needs_prepare_tiles_;
}
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
- if (ShouldUpdateVisibleTiles())
- return ACTION_UPDATE_VISIBLE_TILES;
if (ShouldActivatePendingTree())
return ACTION_ACTIVATE_SYNC_TREE;
if (ShouldCommit())
@@ -553,10 +519,12 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
else
return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
}
- if (ShouldManageTiles())
- return ACTION_MANAGE_TILES;
+ if (ShouldPrepareTiles())
+ return ACTION_PREPARE_TILES;
if (ShouldSendBeginMainFrame())
return ACTION_SEND_BEGIN_MAIN_FRAME;
+ if (ShouldInvalidateOutputSurface())
+ return ACTION_INVALIDATE_OUTPUT_SURFACE;
if (ShouldBeginOutputSurfaceCreation())
return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
return ACTION_NONE;
@@ -567,37 +535,21 @@ void SchedulerStateMachine::UpdateState(Action action) {
case ACTION_NONE:
return;
- case ACTION_UPDATE_VISIBLE_TILES:
- last_frame_number_update_visible_tiles_was_called_ =
- current_frame_number_;
- return;
-
case ACTION_ACTIVATE_SYNC_TREE:
UpdateStateOnActivation();
return;
case ACTION_ANIMATE:
- last_frame_number_animate_performed_ = current_frame_number_;
- needs_animate_ = false;
- did_commit_after_animating_ = false;
- // TODO(skyostil): Instead of assuming this, require the client to tell
- // us.
- SetNeedsRedraw();
+ UpdateStateOnAnimate();
return;
case ACTION_SEND_BEGIN_MAIN_FRAME:
- DCHECK(!has_pending_tree_ ||
- settings_.main_frame_before_activation_enabled);
- DCHECK(visible_);
- commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
- needs_commit_ = false;
- last_frame_number_begin_main_frame_sent_ =
- current_frame_number_;
+ UpdateStateOnSendBeginMainFrame();
return;
case ACTION_COMMIT: {
- bool commit_was_aborted = false;
- UpdateStateOnCommit(commit_was_aborted);
+ bool commit_has_no_updates = false;
+ UpdateStateOnCommit(commit_has_no_updates);
return;
}
@@ -615,40 +567,58 @@ void SchedulerStateMachine::UpdateState(Action action) {
}
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
- DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
- output_surface_state_ = OUTPUT_SURFACE_CREATING;
-
- // The following DCHECKs make sure we are in the proper quiescent state.
- // The pipeline should be flushed entirely before we start output
- // surface creation to avoid complicated corner cases.
- DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
- DCHECK(!has_pending_tree_);
- DCHECK(!active_tree_needs_first_draw_);
+ UpdateStateOnBeginOutputSurfaceCreation();
+ return;
+
+ case ACTION_PREPARE_TILES:
+ UpdateStateOnPrepareTiles();
return;
- case ACTION_MANAGE_TILES:
- UpdateStateOnManageTiles();
+ case ACTION_INVALIDATE_OUTPUT_SURFACE:
+ UpdateStateOnInvalidateOutputSurface();
return;
}
}
-void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
+void SchedulerStateMachine::UpdateStateOnAnimate() {
+ DCHECK(!animate_funnel_);
+ last_frame_number_animate_performed_ = current_frame_number_;
+ animate_funnel_ = true;
+ needs_animate_ = false;
+ // TODO(skyostil): Instead of assuming this, require the client to tell us.
+ SetNeedsRedraw();
+}
+
+void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() {
+ DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled);
+ DCHECK(visible_);
+ DCHECK(!send_begin_main_frame_funnel_);
+ commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
+ needs_commit_ = false;
+ send_begin_main_frame_funnel_ = true;
+ last_frame_number_begin_main_frame_sent_ = current_frame_number_;
+}
+
+void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
commit_count_++;
- if (!commit_was_aborted && HasAnimatedThisFrame())
- did_commit_after_animating_ = true;
+ // Animate after commit even if we've already animated.
+ if (!commit_has_no_updates)
+ animate_funnel_ = false;
- if (commit_was_aborted || settings_.main_frame_before_activation_enabled) {
+ if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) {
commit_state_ = COMMIT_STATE_IDLE;
+ } else if (settings_.impl_side_painting) {
+ commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION;
} else {
- commit_state_ = settings_.impl_side_painting
- ? COMMIT_STATE_WAITING_FOR_ACTIVATION
+ commit_state_ = settings_.main_thread_should_always_be_low_latency
+ ? COMMIT_STATE_WAITING_FOR_DRAW
: COMMIT_STATE_IDLE;
}
// If we are impl-side-painting but the commit was aborted, then we behave
// mostly as if we are not impl-side-painting since there is no pending tree.
- has_pending_tree_ = settings_.impl_side_painting && !commit_was_aborted;
+ has_pending_tree_ = settings_.impl_side_painting && !commit_has_no_updates;
// Update state related to forced draws.
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
@@ -671,7 +641,7 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
// Update state if we have a new active tree to draw, or if the active tree
// was unchanged but we need to do a forced draw.
if (!has_pending_tree_ &&
- (!commit_was_aborted ||
+ (!commit_has_no_updates ||
forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
needs_redraw_ = true;
active_tree_needs_first_draw_ = true;
@@ -682,11 +652,15 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
if (continuous_painting_)
needs_commit_ = true;
+ last_commit_had_no_updates_ = commit_has_no_updates;
}
void SchedulerStateMachine::UpdateStateOnActivation() {
- if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION)
- commit_state_ = COMMIT_STATE_IDLE;
+ if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION) {
+ commit_state_ = settings_.main_thread_should_always_be_low_latency
+ ? COMMIT_STATE_WAITING_FOR_DRAW
+ : COMMIT_STATE_IDLE;
+ }
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
@@ -704,15 +678,46 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
+ if (commit_state_ == COMMIT_STATE_WAITING_FOR_DRAW)
+ commit_state_ = COMMIT_STATE_IDLE;
+
needs_redraw_ = false;
active_tree_needs_first_draw_ = false;
- if (did_request_swap)
+ if (did_request_swap) {
+ DCHECK(!request_swap_funnel_);
+ request_swap_funnel_ = true;
+ did_request_swap_in_last_frame_ = true;
last_frame_number_swap_requested_ = current_frame_number_;
+ }
+}
+
+void SchedulerStateMachine::UpdateStateOnPrepareTiles() {
+ needs_prepare_tiles_ = false;
+}
+
+void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() {
+ DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
+ output_surface_state_ = OUTPUT_SURFACE_CREATING;
+
+ // The following DCHECKs make sure we are in the proper quiescent state.
+ // The pipeline should be flushed entirely before we start output
+ // surface creation to avoid complicated corner cases.
+ DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
+ DCHECK(!has_pending_tree_);
+ DCHECK(!active_tree_needs_first_draw_);
}
-void SchedulerStateMachine::UpdateStateOnManageTiles() {
- needs_manage_tiles_ = false;
+void SchedulerStateMachine::UpdateStateOnInvalidateOutputSurface() {
+ DCHECK(!invalidate_output_surface_funnel_);
+ invalidate_output_surface_funnel_ = true;
+ last_frame_number_invalidate_output_surface_performed_ =
+ current_frame_number_;
+
+ // The synchronous compositor makes no guarantees about a draw coming in after
+ // an invalidate so clear any flags that would cause the compositor's pipeline
+ // to stall.
+ active_tree_needs_first_draw_ = false; // blocks commit if true
}
void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() {
@@ -722,91 +727,69 @@ void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() {
skip_next_begin_main_frame_to_reduce_latency_ = true;
}
-bool SchedulerStateMachine::BeginFrameNeeded() const {
- // Proactive BeginFrames are bad for the synchronous compositor because we
- // have to draw when we get the BeginFrame and could end up drawing many
- // duplicate frames if our new frame isn't ready in time.
- // To poll for state with the synchronous compositor without having to draw,
- // we rely on ShouldPollForAnticipatedDrawTriggers instead.
- if (!SupportsProactiveBeginFrame())
- return BeginFrameNeededToAnimateOrDraw();
-
- return BeginFrameNeededToAnimateOrDraw() || ProactiveBeginFrameWanted();
-}
-
-bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
- // ShouldPollForAnticipatedDrawTriggers is what we use in place of
- // ProactiveBeginFrameWanted when we are using the synchronous
- // compositor.
- if (!SupportsProactiveBeginFrame()) {
- return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted();
- }
-
- // Non synchronous compositors should rely on
- // ProactiveBeginFrameWanted to poll for state instead.
- return false;
+bool SchedulerStateMachine::BeginFrameRequiredForChildren() const {
+ return children_need_begin_frames_;
}
-
-// Note: If SupportsProactiveBeginFrame is false, the scheduler should poll
-// for changes in it's draw state so it can request a BeginFrame when it's
-// actually ready.
-bool SchedulerStateMachine::SupportsProactiveBeginFrame() const {
- // It is undesirable to proactively request BeginFrames if we are
- // using a synchronous compositor because we *must* draw for every
- // BeginFrame, which could cause duplicate draws.
- return !settings_.using_synchronous_renderer_compositor;
+bool SchedulerStateMachine::BeginFrameNeededForVideo() const {
+ return video_needs_begin_frames_;
}
-// These are the cases where we definitely (or almost definitely) have a
-// new frame to animate and/or draw and can draw.
-bool SchedulerStateMachine::BeginFrameNeededToAnimateOrDraw() const {
- // The output surface is the provider of BeginImplFrames, so we are not going
- // to get them even if we ask for them.
+bool SchedulerStateMachine::BeginFrameNeeded() const {
+ // We can't handle BeginFrames when output surface isn't initialized.
+ // TODO(brianderson): Support output surface creation inside a BeginFrame.
if (!HasInitializedOutputSurface())
return false;
- // If we can't draw, don't tick until we are notified that we can draw again.
- if (!can_draw_)
+ // If we are not visible, we don't need BeginFrame messages.
+ if (!visible_)
return false;
- // The forced draw respects our normal draw scheduling, so we need to
- // request a BeginImplFrame for it.
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
- return true;
+ return (BeginFrameRequiredForAction() || BeginFrameRequiredForChildren() ||
+ BeginFrameNeededForVideo() || ProactiveBeginFrameWanted());
+}
- // There's no need to produce frames if we are not visible.
- if (!visible_)
- return false;
+void SchedulerStateMachine::SetChildrenNeedBeginFrames(
+ bool children_need_begin_frames) {
+ children_need_begin_frames_ = children_need_begin_frames;
+}
- // We need to draw a more complete frame than we did the last BeginImplFrame,
- // so request another BeginImplFrame in anticipation that we will have
- // additional visible tiles.
- if (swap_used_incomplete_tile_)
- return true;
+void SchedulerStateMachine::SetVideoNeedsBeginFrames(
+ bool video_needs_begin_frames) {
+ video_needs_begin_frames_ = video_needs_begin_frames;
+}
+
+void SchedulerStateMachine::SetDeferCommits(bool defer_commits) {
+ defer_commits_ = defer_commits;
+}
- if (needs_animate_)
+// These are the cases where we require a BeginFrame message to make progress
+// on requested actions.
+bool SchedulerStateMachine::BeginFrameRequiredForAction() const {
+ // The forced draw respects our normal draw scheduling, so we need to
+ // request a BeginImplFrame for it.
+ if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return true;
- return needs_redraw_;
+ return needs_animate_ || needs_redraw_ || (needs_commit_ && !defer_commits_);
}
-// These are cases where we are very likely to draw soon, but might not
-// actually have a new frame to draw when we receive the next BeginImplFrame.
-// Proactively requesting the BeginImplFrame helps hide the round trip latency
-// of the SetNeedsBeginFrame request that has to go to the Browser.
+// These are cases where we are very likely want a BeginFrame message in the
+// near future. Proactively requesting the BeginImplFrame helps hide the round
+// trip latency of the SetNeedsBeginFrame request that has to go to the
+// Browser.
+// This includes things like drawing soon, but might not actually have a new
+// frame to draw when we receive the next BeginImplFrame.
bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
- // The output surface is the provider of BeginImplFrames,
- // so we are not going to get them even if we ask for them.
- if (!HasInitializedOutputSurface())
- return false;
-
// Do not be proactive when invisible.
if (!visible_)
return false;
// We should proactively request a BeginImplFrame if a commit is pending
- // because we will want to draw if the commit completes quickly.
- if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE)
+ // because we will want to draw if the commit completes quickly. Do not
+ // request frames when commits are disabled, because the frame requests will
+ // not provide the needed commit (and will wake up the process when it could
+ // stay idle).
+ if ((commit_state_ != COMMIT_STATE_IDLE) && !defer_commits_)
return true;
// If the pending tree activates quickly, we'll want a BeginImplFrame soon
@@ -816,7 +799,7 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
// Changing priorities may allow us to activate (given the new priorities),
// which may result in a new frame.
- if (needs_manage_tiles_)
+ if (needs_prepare_tiles_)
return true;
// If we just sent a swap request, it's likely that we are going to produce
@@ -824,48 +807,93 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
// SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame
// provider and get sampled at an inopportune time, delaying the next
// BeginImplFrame.
- if (HasRequestedSwapThisFrame())
+ if (did_request_swap_in_last_frame_)
+ return true;
+
+ // If the last commit was aborted because of early out (no updates), we should
+ // still want a begin frame in case there is a commit coming again.
+ if (last_commit_had_no_updates_)
return true;
return false;
}
-void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
- AdvanceCurrentFrameNumber();
- begin_impl_frame_args_ = args;
- DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE)
- << AsValue()->ToString();
+void SchedulerStateMachine::OnBeginImplFrame() {
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
+ current_frame_number_++;
+
+ last_commit_had_no_updates_ = false;
+ did_request_swap_in_last_frame_ = false;
+
+ // Clear funnels for any actions we perform during the frame.
+ animate_funnel_ = false;
+ send_begin_main_frame_funnel_ = false;
+ invalidate_output_surface_funnel_ = false;
+
+ // "Drain" the PrepareTiles funnel.
+ if (prepare_tiles_funnel_ > 0)
+ prepare_tiles_funnel_--;
+
+ skip_begin_main_frame_to_reduce_latency_ =
+ skip_next_begin_main_frame_to_reduce_latency_;
+ skip_next_begin_main_frame_to_reduce_latency_ = false;
}
void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
- DCHECK_EQ(begin_impl_frame_state_,
- BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
- << AsValue()->ToString();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME;
}
void SchedulerStateMachine::OnBeginImplFrameDeadline() {
- DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
- << AsValue()->ToString();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
+
+ did_perform_swap_in_last_draw_ = false;
+
+ // Clear funnels for any actions we perform during the deadline.
+ request_swap_funnel_ = false;
+
+ // Allow one PrepareTiles per draw for synchronous compositor.
+ if (settings_.using_synchronous_renderer_compositor) {
+ if (prepare_tiles_funnel_ > 0)
+ prepare_tiles_funnel_--;
+ }
}
void SchedulerStateMachine::OnBeginImplFrameIdle() {
- DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
- << AsValue()->ToString();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
}
-bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
- // TODO(brianderson): This should take into account multiple commit sources.
+SchedulerStateMachine::BeginImplFrameDeadlineMode
+SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
+ if (settings_.using_synchronous_renderer_compositor) {
+ // No deadline for synchronous compositor.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE;
+ } else if (wait_for_active_tree_ready_to_draw_) {
+ // When we are waiting for ready to draw signal, we do not wait to post a
+ // deadline yet.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW;
+ } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) {
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE;
+ } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) {
+ // We have an animation or fast input path on the impl thread that wants
+ // to draw, so don't wait too long for a new active tree.
+ // If we are swap throttled we should wait until we are unblocked.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR;
+ } else {
+ // The impl thread doesn't have anything it wants to draw and we are just
+ // waiting for a new active tree or we are swap throttled. In short we are
+ // blocked.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE;
+ }
+}
+bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately()
+ const {
+ // TODO(brianderson): This should take into account multiple commit sources.
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
return false;
- // If we've lost the output surface, end the current BeginImplFrame ASAP
- // so we can start creating the next output surface.
- if (output_surface_state_ == OUTPUT_SURFACE_LOST)
+ // If we just forced activation, we should end the deadline right now.
+ if (PendingActivationsShouldBeForced() && !has_pending_tree_)
return true;
// SwapAck throttle the deadline since we wont draw and swap anyway.
@@ -890,11 +918,6 @@ bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
if (impl_latency_takes_priority_)
return true;
- // If we are on battery power and want to prioritize impl latency because
- // we don't trust deadline tasks to execute at the right time.
- if (impl_latency_takes_priority_on_battery_)
- return true;
-
return false;
}
@@ -906,7 +929,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
// If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
// thread is in a low latency mode.
- if (HasSentBeginMainFrameThisFrame() &&
+ if (send_begin_main_frame_funnel_ &&
(begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
return false;
@@ -930,8 +953,8 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
// Even if there's a new active tree to draw at the deadline or we've just
// swapped it, it may have been triggered by a previous BeginImplFrame, in
// which case the main thread is in a high latency mode.
- return (active_tree_needs_first_draw_ || HasSwappedThisFrame()) &&
- !HasSentBeginMainFrameThisFrame();
+ return (active_tree_needs_first_draw_ || did_perform_swap_in_last_draw_) &&
+ !send_begin_main_frame_funnel_;
}
// If the active tree needs its first draw in any other state, we know the
@@ -939,15 +962,6 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
return active_tree_needs_first_draw_;
}
-void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
- AdvanceCurrentFrameNumber();
- inside_poll_for_anticipated_draw_triggers_ = true;
-}
-
-void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() {
- inside_poll_for_anticipated_draw_triggers_ = false;
-}
-
void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
@@ -958,11 +972,15 @@ void SchedulerStateMachine::SetNeedsAnimate() {
needs_animate_ = true;
}
-void SchedulerStateMachine::SetNeedsManageTiles() {
- if (!needs_manage_tiles_) {
- TRACE_EVENT0("cc",
- "SchedulerStateMachine::SetNeedsManageTiles");
- needs_manage_tiles_ = true;
+void SchedulerStateMachine::SetWaitForReadyToDraw() {
+ DCHECK(settings_.impl_side_painting);
+ wait_for_active_tree_ready_to_draw_ = true;
+}
+
+void SchedulerStateMachine::SetNeedsPrepareTiles() {
+ if (!needs_prepare_tiles_) {
+ TRACE_EVENT0("cc", "SchedulerStateMachine::SetNeedsPrepareTiles");
+ needs_prepare_tiles_ = true;
}
}
@@ -974,14 +992,10 @@ void SchedulerStateMachine::DidSwapBuffers() {
pending_swaps_++;
DCHECK_LE(pending_swaps_, max_pending_swaps_);
+ did_perform_swap_in_last_draw_ = true;
last_frame_number_swap_performed_ = current_frame_number_;
}
-void SchedulerStateMachine::SetSwapUsedIncompleteTile(
- bool used_incomplete_tile) {
- swap_used_incomplete_tile_ = used_incomplete_tile;
-}
-
void SchedulerStateMachine::DidSwapBuffersComplete() {
DCHECK_GT(pending_swaps_, 0);
pending_swaps_--;
@@ -1043,23 +1057,33 @@ void SchedulerStateMachine::NotifyReadyToCommit() {
DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED)
<< AsValue()->ToString();
commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
+ // In main thread low latency mode, commit should happen right after
+ // BeginFrame, meaning when this function is called, next action should be
+ // commit.
+ if (settings_.main_thread_should_always_be_low_latency)
+ DCHECK(ShouldCommit());
}
-void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
+void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
- if (did_handle) {
- bool commit_was_aborted = true;
- UpdateStateOnCommit(commit_was_aborted);
- } else {
- commit_state_ = COMMIT_STATE_IDLE;
- SetNeedsCommit();
+ switch (reason) {
+ case CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST:
+ case CommitEarlyOutReason::ABORTED_NOT_VISIBLE:
+ case CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT:
+ commit_state_ = COMMIT_STATE_IDLE;
+ SetNeedsCommit();
+ return;
+ case CommitEarlyOutReason::FINISHED_NO_UPDATES:
+ bool commit_has_no_updates = true;
+ UpdateStateOnCommit(commit_has_no_updates);
+ return;
}
}
-void SchedulerStateMachine::DidManageTiles() {
- needs_manage_tiles_ = false;
- // "Fill" the ManageTiles funnel.
- manage_tiles_funnel_++;
+void SchedulerStateMachine::DidPrepareTiles() {
+ needs_prepare_tiles_ = false;
+ // "Fill" the PrepareTiles funnel.
+ prepare_tiles_funnel_++;
}
void SchedulerStateMachine::DidLoseOutputSurface() {
@@ -1068,6 +1092,7 @@ void SchedulerStateMachine::DidLoseOutputSurface() {
return;
output_surface_state_ = OUTPUT_SURFACE_LOST;
needs_redraw_ = false;
+ wait_for_active_tree_ready_to_draw_ = false;
}
void SchedulerStateMachine::NotifyReadyToActivate() {
@@ -1075,6 +1100,10 @@ void SchedulerStateMachine::NotifyReadyToActivate() {
pending_tree_is_ready_for_activation_ = true;
}
+void SchedulerStateMachine::NotifyReadyToDraw() {
+ wait_for_active_tree_ready_to_draw_ = false;
+}
+
void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index a63a683e907..cf29ca9b6a5 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -9,14 +9,14 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/scheduler/draw_result.h"
#include "cc/scheduler/scheduler_settings.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
class TracedValue;
}
@@ -50,10 +50,10 @@ class CC_EXPORT SchedulerStateMachine {
};
static const char* OutputSurfaceStateToString(OutputSurfaceState state);
- // Note: BeginImplFrameState will always cycle through all the states in
- // order. Whether or not it actually waits or draws, it will at least try to
- // wait in BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME and try to draw in
- // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE
+ // Note: BeginImplFrameState does not cycle through these states in a fixed
+ // order on all platforms. It's up to the scheduler to set these correctly.
+ // TODO(sunnyps): Rename the states to IDLE, ANIMATE, WAITING_FOR_DEADLINE and
+ // DRAW.
enum BeginImplFrameState {
BEGIN_IMPL_FRAME_STATE_IDLE,
BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
@@ -62,12 +62,23 @@ class CC_EXPORT SchedulerStateMachine {
};
static const char* BeginImplFrameStateToString(BeginImplFrameState state);
+ enum BeginImplFrameDeadlineMode {
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW,
+ };
+ static const char* BeginImplFrameDeadlineModeToString(
+ BeginImplFrameDeadlineMode mode);
+
enum CommitState {
COMMIT_STATE_IDLE,
COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
COMMIT_STATE_READY_TO_COMMIT,
COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ COMMIT_STATE_WAITING_FOR_DRAW,
};
static const char* CommitStateToString(CommitState state);
@@ -88,25 +99,25 @@ class CC_EXPORT SchedulerStateMachine {
CommitState commit_state() const { return commit_state_; }
bool RedrawPending() const { return needs_redraw_; }
- bool ManageTilesPending() const { return needs_manage_tiles_; }
+ bool PrepareTilesPending() const { return needs_prepare_tiles_; }
enum Action {
ACTION_NONE,
ACTION_ANIMATE,
ACTION_SEND_BEGIN_MAIN_FRAME,
ACTION_COMMIT,
- ACTION_UPDATE_VISIBLE_TILES,
ACTION_ACTIVATE_SYNC_TREE,
ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
ACTION_DRAW_AND_SWAP_FORCED,
ACTION_DRAW_AND_SWAP_ABORT,
ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- ACTION_MANAGE_TILES,
+ ACTION_PREPARE_TILES,
+ ACTION_INVALIDATE_OUTPUT_SURFACE,
};
static const char* ActionToString(Action action);
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
- void AsValueInto(base::debug::TracedValue* dict, base::TimeTicks now) const;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
Action NextAction() const;
void UpdateState(Action action);
@@ -115,39 +126,28 @@ class CC_EXPORT SchedulerStateMachine {
// to make progress.
bool BeginFrameNeeded() const;
- // Indicates that we need to independently poll for new state and actions
- // because we can't expect a BeginImplFrame. This is mostly used to avoid
- // drawing repeat frames with the synchronous compositor without dropping
- // necessary actions on the floor.
- bool ShouldPollForAnticipatedDrawTriggers() const;
-
// Indicates that the system has entered and left a BeginImplFrame callback.
// The scheduler will not draw more than once in a given BeginImplFrame
// callback nor send more than one BeginMainFrame message.
- void OnBeginImplFrame(const BeginFrameArgs& args);
+ void OnBeginImplFrame();
void OnBeginImplFrameDeadlinePending();
+ // Indicates that the scheduler has entered the draw phase. The scheduler
+ // will not draw more than once in a single draw phase.
+ // TODO(sunnyps): Rename OnBeginImplFrameDeadline to OnDraw or similar.
void OnBeginImplFrameDeadline();
void OnBeginImplFrameIdle();
- bool ShouldTriggerBeginImplFrameDeadlineEarly() const;
BeginImplFrameState begin_impl_frame_state() const {
return begin_impl_frame_state_;
}
+ BeginImplFrameDeadlineMode CurrentBeginImplFrameDeadlineMode() const;
// If the main thread didn't manage to produce a new frame in time for the
// impl thread to draw, it is in a high latency mode.
bool MainThreadIsInHighLatencyMode() const;
- // PollForAnticipatedDrawTriggers is used by the synchronous compositor to
- // avoid requesting BeginImplFrames when we won't actually draw but still
- // need to advance our state at vsync intervals.
- void DidEnterPollForAnticipatedDrawTriggers();
- void DidLeavePollForAnticipatedDrawTriggers();
- bool inside_poll_for_anticipated_draw_triggers() const {
- return inside_poll_for_anticipated_draw_triggers_;
- }
-
// Indicates whether the LayerTreeHostImpl is visible.
void SetVisible(bool visible);
+ bool visible() const { return visible_; }
// Indicates that a redraw is required, either due to the impl tree changing
// or the screen being damaged and simply needing redisplay.
@@ -157,9 +157,12 @@ class CC_EXPORT SchedulerStateMachine {
void SetNeedsAnimate();
bool needs_animate() const { return needs_animate_; }
- // Indicates that manage-tiles is required. This guarantees another
- // ManageTiles will occur shortly (even if no redraw is required).
- void SetNeedsManageTiles();
+ // Indicates that prepare-tiles is required. This guarantees another
+ // PrepareTiles will occur shortly (even if no redraw is required).
+ void SetNeedsPrepareTiles();
+
+ // Make deadline wait for ReadyToDraw signal.
+ void SetWaitForReadyToDraw();
// Sets how many swaps can be pending to the OutputSurface.
void SetMaxSwapsPending(int max);
@@ -198,11 +201,12 @@ class CC_EXPORT SchedulerStateMachine {
// Call this only in response to receiving an ACTION_SEND_BEGIN_MAIN_FRAME
// from NextAction if the client rejects the BeginMainFrame message.
- // If did_handle is false, then another commit will be retried soon.
- void BeginMainFrameAborted(bool did_handle);
+ void BeginMainFrameAborted(CommitEarlyOutReason reason);
// Set that we can create the first OutputSurface and start the scheduler.
void SetCanStart() { can_start_ = true; }
+ // Allow access of the can_start_ state in tests.
+ bool CanStartForTesting() const { return can_start_; }
void SetSkipNextBeginMainFrameToReduceLatency();
@@ -217,12 +221,15 @@ class CC_EXPORT SchedulerStateMachine {
// Indicates that the pending tree is ready for activation.
void NotifyReadyToActivate();
+ // Indicates the active tree's visible tiles are ready to be drawn.
+ void NotifyReadyToDraw();
+
bool has_pending_tree() const { return has_pending_tree_; }
bool active_tree_needs_first_draw() const {
return active_tree_needs_first_draw_;
}
- void DidManageTiles();
+ void DidPrepareTiles();
void DidLoseOutputSurface();
void DidCreateAndInitializeOutputSurface();
bool HasInitializedOutputSurface() const;
@@ -230,52 +237,54 @@ class CC_EXPORT SchedulerStateMachine {
// True if we need to abort draws to make forward progress.
bool PendingDrawsShouldBeAborted() const;
- bool SupportsProactiveBeginFrame() const;
-
void SetContinuousPainting(bool continuous_painting) {
continuous_painting_ = continuous_painting;
}
bool CouldSendBeginMainFrame() const;
- void SetImplLatencyTakesPriorityOnBattery(
- bool impl_latency_takes_priority_on_battery) {
- impl_latency_takes_priority_on_battery_ =
- impl_latency_takes_priority_on_battery;
- }
+ void SetDeferCommits(bool defer_commits);
// TODO(zmo): This is temporary for debugging crbug.com/393331.
// We should remove it afterwards.
std::string GetStatesForDebugging() const;
+ void SetChildrenNeedBeginFrames(bool children_need_begin_frames);
+ bool children_need_begin_frames() const {
+ return children_need_begin_frames_;
+ }
+
+ void SetVideoNeedsBeginFrames(bool video_needs_begin_frames);
+ bool video_needs_begin_frames() const { return video_needs_begin_frames_; }
+
protected:
- bool BeginFrameNeededToAnimateOrDraw() const;
+ bool BeginFrameRequiredForAction() const;
+ bool BeginFrameRequiredForChildren() const;
+ bool BeginFrameNeededForVideo() const;
bool ProactiveBeginFrameWanted() const;
+ bool ShouldTriggerBeginImplFrameDeadlineImmediately() const;
+
// True if we need to force activations to make forward progress.
bool PendingActivationsShouldBeForced() const;
bool ShouldAnimate() const;
bool ShouldBeginOutputSurfaceCreation() const;
- bool ShouldDrawForced() const;
bool ShouldDraw() const;
bool ShouldActivatePendingTree() const;
- bool ShouldUpdateVisibleTiles() const;
bool ShouldSendBeginMainFrame() const;
bool ShouldCommit() const;
- bool ShouldManageTiles() const;
+ bool ShouldPrepareTiles() const;
+ bool ShouldInvalidateOutputSurface() const;
- void AdvanceCurrentFrameNumber();
- bool HasAnimatedThisFrame() const;
- bool HasSentBeginMainFrameThisFrame() const;
- bool HasUpdatedVisibleTilesThisFrame() const;
- bool HasRequestedSwapThisFrame() const;
- bool HasSwappedThisFrame() const;
-
- void UpdateStateOnCommit(bool commit_was_aborted);
+ void UpdateStateOnAnimate();
+ void UpdateStateOnSendBeginMainFrame();
+ void UpdateStateOnCommit(bool commit_had_no_updates);
void UpdateStateOnActivation();
void UpdateStateOnDraw(bool did_request_swap);
- void UpdateStateOnManageTiles();
+ void UpdateStateOnBeginOutputSurfaceCreation();
+ void UpdateStateOnPrepareTiles();
+ void UpdateStateOnInvalidateOutputSurface();
const SchedulerSettings settings_;
@@ -284,43 +293,52 @@ class CC_EXPORT SchedulerStateMachine {
CommitState commit_state_;
ForcedRedrawOnTimeoutState forced_redraw_state_;
- BeginFrameArgs begin_impl_frame_args_;
-
+ // These are used for tracing only.
int commit_count_;
int current_frame_number_;
int last_frame_number_animate_performed_;
int last_frame_number_swap_performed_;
int last_frame_number_swap_requested_;
int last_frame_number_begin_main_frame_sent_;
- int last_frame_number_update_visible_tiles_was_called_;
-
- // manage_tiles_funnel_ is "filled" each time ManageTiles is called
+ int last_frame_number_invalidate_output_surface_performed_;
+
+ // These are used to ensure that an action only happens once per frame,
+ // deadline, etc.
+ bool animate_funnel_;
+ bool request_swap_funnel_;
+ bool send_begin_main_frame_funnel_;
+ bool invalidate_output_surface_funnel_;
+ // prepare_tiles_funnel_ is "filled" each time PrepareTiles is called
// and "drained" on each BeginImplFrame. If the funnel gets too full,
- // we start throttling ACTION_MANAGE_TILES such that we average one
- // ManageTile per BeginImplFrame.
- int manage_tiles_funnel_;
+ // we start throttling ACTION_PREPARE_TILES such that we average one
+ // PrepareTiles per BeginImplFrame.
+ int prepare_tiles_funnel_;
+
int consecutive_checkerboard_animations_;
int max_pending_swaps_;
int pending_swaps_;
bool needs_redraw_;
bool needs_animate_;
- bool needs_manage_tiles_;
- bool swap_used_incomplete_tile_;
+ bool needs_prepare_tiles_;
bool needs_commit_;
- bool inside_poll_for_anticipated_draw_triggers_;
bool visible_;
bool can_start_;
bool can_draw_;
bool has_pending_tree_;
bool pending_tree_is_ready_for_activation_;
bool active_tree_needs_first_draw_;
- bool did_commit_after_animating_;
bool did_create_and_initialize_first_output_surface_;
bool impl_latency_takes_priority_;
bool skip_next_begin_main_frame_to_reduce_latency_;
bool skip_begin_main_frame_to_reduce_latency_;
bool continuous_painting_;
- bool impl_latency_takes_priority_on_battery_;
+ bool children_need_begin_frames_;
+ bool defer_commits_;
+ bool video_needs_begin_frames_;
+ bool last_commit_had_no_updates_;
+ bool wait_for_active_tree_ready_to_draw_;
+ bool did_request_swap_in_last_frame_;
+ bool did_perform_swap_in_last_draw_;
private:
DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine);
diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
index e3530c877f4..7b332a3fbf3 100644
--- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -4,31 +4,58 @@
#include "cc/scheduler/scheduler_state_machine.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/scheduler/scheduler.h"
#include "cc/test/begin_frame_args_test.h"
#include "testing/gtest/include/gtest/gtest.h"
-#define EXPECT_ACTION_UPDATE_STATE(action) \
- EXPECT_STREQ(SchedulerStateMachine::ActionToString(action), \
- SchedulerStateMachine::ActionToString(state.NextAction())) \
- << state.AsValue()->ToString(); \
- if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE || \
- action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) { \
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, \
- state.begin_impl_frame_state()) \
- << state.AsValue()->ToString(); \
- } \
- state.UpdateState(action); \
- if (action == SchedulerStateMachine::ACTION_NONE) { \
- if (state.begin_impl_frame_state() == \
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \
- state.OnBeginImplFrameDeadlinePending(); \
- if (state.begin_impl_frame_state() == \
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) \
- state.OnBeginImplFrameIdle(); \
+// Macro to compare two enum values and get nice output.
+// Without:
+// Value of: actual() Actual: 7
+// Expected: expected() Which is: 0
+// With:
+// Value of: actual() Actual: "ACTION_ANIMATE"
+// Expected: expected() Which is: "ACTION_NONE"
+#define EXPECT_ENUM_EQ(enum_tostring, expected, actual) \
+ EXPECT_STREQ(SchedulerStateMachine::enum_tostring(expected), \
+ SchedulerStateMachine::enum_tostring(actual))
+
+#define EXPECT_IMPL_FRAME_STATE(expected) \
+ EXPECT_ENUM_EQ(BeginImplFrameStateToString, expected, \
+ state.begin_impl_frame_state()) \
+ << state.AsValue()->ToString()
+
+#define EXPECT_COMMIT_STATE(expected) \
+ EXPECT_ENUM_EQ(CommitStateToString, expected, state.CommitState())
+
+#define EXPECT_ACTION(expected) \
+ EXPECT_ENUM_EQ(ActionToString, expected, state.NextAction()) \
+ << state.AsValue()->ToString()
+
+#define EXPECT_ACTION_UPDATE_STATE(action) \
+ EXPECT_ACTION(action); \
+ if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE || \
+ action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) { \
+ EXPECT_IMPL_FRAME_STATE( \
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); \
+ } \
+ state.UpdateState(action); \
+ if (action == SchedulerStateMachine::ACTION_NONE) { \
+ if (state.begin_impl_frame_state() == \
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \
+ state.OnBeginImplFrameDeadlinePending(); \
+ if (state.begin_impl_frame_state() == \
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) \
+ state.OnBeginImplFrameIdle(); \
}
+#define SET_UP_STATE(state) \
+ state.SetCanStart(); \
+ state.UpdateState(state.NextAction()); \
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); \
+ state.SetVisible(true); \
+ state.SetCanDraw(true);
+
namespace cc {
namespace {
@@ -44,7 +71,8 @@ const SchedulerStateMachine::CommitState all_commit_states[] = {
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION};
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW};
// Exposes the protected state fields of the SchedulerStateMachine for testing
class StateMachine : public SchedulerStateMachine {
@@ -76,9 +104,17 @@ class StateMachine : public SchedulerStateMachine {
return output_surface_state_;
}
+ void SetNeedsCommitForTest(bool needs_commit) {
+ needs_commit_ = needs_commit;
+ }
+
bool NeedsCommit() const { return needs_commit_; }
- void SetNeedsRedraw(bool b) { needs_redraw_ = b; }
+ void SetNeedsAnimateForTest(bool needs_animate) {
+ needs_animate_ = needs_animate;
+ }
+
+ void SetNeedsRedraw(bool needs_redraw) { needs_redraw_ = needs_redraw; }
void SetNeedsForcedRedrawForTimeout(bool b) {
forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
@@ -102,8 +138,56 @@ class StateMachine : public SchedulerStateMachine {
void SetHasPendingTree(bool has_pending_tree) {
has_pending_tree_ = has_pending_tree;
}
+
+ using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately;
+ using SchedulerStateMachine::ProactiveBeginFrameWanted;
+ using SchedulerStateMachine::UpdateStateOnCommit;
};
+TEST(SchedulerStateMachineTest, BeginFrameNeeded) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION)
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
+
+ // Don't request BeginFrames if we are idle.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(false);
+ state.SetNeedsAnimateForTest(false);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ // Request BeginFrames if we are ready to draw.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(true);
+ state.SetNeedsAnimateForTest(false);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Don't background tick for needs_redraw.
+ state.SetVisible(false);
+ state.SetNeedsRedraw(true);
+ state.SetNeedsAnimateForTest(false);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ // Proactively request BeginFrames when commit is pending.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(false);
+ state.SetNeedsAnimateForTest(false);
+ state.SetNeedsCommitForTest(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Don't request BeginFrames when commit is pending if
+ // we are currently deferring commits.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(false);
+ state.SetNeedsAnimateForTest(false);
+ state.SetNeedsCommitForTest(true);
+ state.SetDeferCommits(true);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+}
+
TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
SchedulerSettings default_scheduler_settings;
@@ -122,7 +206,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -140,7 +224,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
}
@@ -158,7 +242,36 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ // Expect nothing to happen until after OnBeginImplFrame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ }
+
+ // If commit requested and can't draw, still begin a main frame.
+ {
+ StateMachine state(default_scheduler_settings);
+ state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetNeedsRedraw(false);
+ state.SetVisible(true);
+ state.SetNeedsCommit();
+ state.SetCanDraw(false);
+
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Expect nothing to happen until after OnBeginImplFrame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -171,8 +284,8 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(true);
state.UpdateState(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
}
}
@@ -184,18 +297,14 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
scheduler_settings.main_frame_before_activation_enabled = true;
StateMachine state(scheduler_settings);
state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ SET_UP_STATE(state)
state.SetNeedsRedraw(false);
- state.SetVisible(true);
- state.SetCanDraw(true);
state.SetNeedsCommit();
EXPECT_TRUE(state.BeginFrameNeeded());
// Commit to the pending tree.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -204,14 +313,14 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Verify that the next commit starts while there is still a pending tree.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -228,7 +337,7 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
@@ -237,22 +346,18 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
}
TEST(SchedulerStateMachineTest,
TestFailedDrawForAnimationCheckerboardSetsNeedsCommitAndDoesNotDrawAgain) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -269,7 +374,7 @@ TEST(SchedulerStateMachineTest,
// Failing the draw makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -280,16 +385,12 @@ TEST(SchedulerStateMachineTest,
TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResNeedsCommit) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -303,7 +404,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResNeedsCommit) {
// Missing high res content requires a commit (but not a redraw)
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_FALSE(state.RedrawPending());
@@ -314,16 +415,11 @@ TEST(SchedulerStateMachineTest,
TestsetNeedsRedrawDuringFailedDrawDoesNotRemoveNeedsRedraw) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -344,7 +440,7 @@ TEST(SchedulerStateMachineTest,
// Failing the draw for animation checkerboards makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -356,16 +452,12 @@ TEST(SchedulerStateMachineTest,
SchedulerSettings scheduler_settings;
scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -395,7 +487,7 @@ TEST(SchedulerStateMachineTest,
EXPECT_TRUE(state.RedrawPending());
// The redraw should be forced at the end of the next BeginImplFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -414,16 +506,12 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) {
draw_limit;
scheduler_settings.impl_side_painting = true;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -471,16 +559,12 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) {
TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start a draw.
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -497,7 +581,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
// We should not be trying to draw again now, but we have a commit pending.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -514,16 +598,12 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
// Draw the first frame.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -542,7 +622,7 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
// Move to another frame. This should now draw.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -615,19 +695,16 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) {
expected_action = SchedulerStateMachine::ACTION_COMMIT;
} else {
expected_action = SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
- EXPECT_EQ(state.NextAction(), SchedulerStateMachine::ACTION_ANIMATE)
- << state.AsValue()->ToString();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_ANIMATE);
state.UpdateState(state.NextAction());
}
// Case 1: needs_commit=false.
- EXPECT_EQ(state.NextAction(), expected_action)
- << state.AsValue()->ToString();
+ EXPECT_ACTION(expected_action);
// Case 2: needs_commit=true.
state.SetNeedsCommit();
- EXPECT_EQ(state.NextAction(), expected_action)
- << state.AsValue()->ToString();
+ EXPECT_ACTION(expected_action);
}
}
@@ -680,7 +757,7 @@ TEST(SchedulerStateMachineTest, TestCanRedraw_StopsDraw) {
state.SetVisible(false);
state.SetNeedsRedraw(true);
if (j == 1)
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
state.SetCanDraw(false);
EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
@@ -702,7 +779,8 @@ TEST(SchedulerStateMachineTest,
state.SetNeedsRedraw(true);
state.SetVisible(true);
state.SetCanDraw(false);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -711,6 +789,7 @@ TEST(SchedulerStateMachineTest,
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
@@ -718,21 +797,17 @@ TEST(SchedulerStateMachineTest,
TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ SET_UP_STATE(state)
state.SetNeedsCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
// Now, while the frame is in progress, set another commit.
state.SetNeedsCommit();
@@ -741,33 +816,31 @@ TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) {
// Let the frame finish.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
// Expect to commit regardless of BeginImplFrame state.
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadlinePending();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameIdle();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
// Finish the commit, then make sure we start the next commit immediately
// and draw on the next BeginImplFrame.
@@ -791,29 +864,24 @@ TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) {
TEST(SchedulerStateMachineTest, TestFullCycle) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start clean and set commit.
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Tell the scheduler the frame finished.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
// Commit.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
@@ -834,28 +902,166 @@ TEST(SchedulerStateMachineTest, TestFullCycle) {
// Should be synchronized, no draw needed, no action needed.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
EXPECT_FALSE(state.needs_redraw());
}
+TEST(SchedulerStateMachineTest, TestFullCycleWithMainThreadLowLatencyMode) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.main_thread_should_always_be_low_latency = true;
+ StateMachine state(scheduler_settings);
+ SET_UP_STATE(state)
+
+ // Start clean and set commit.
+ state.SetNeedsCommit();
+
+ // Begin the frame.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Tell the scheduler the frame finished.
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
+
+ // Commit.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+
+ // Now commit should wait for draw.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW);
+
+ // Swap throttled. Do not draw.
+ state.DidSwapBuffers();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
+
+ // Haven't draw since last commit, do not begin new main frame.
+ state.SetNeedsCommit();
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // At BeginImplFrame deadline, draw.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
+
+ // Now will be able to start main frame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_FALSE(state.needs_redraw());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
+TEST(SchedulerStateMachineTest,
+ TestFullCycleWithMainThreadLowLatencyMode_ImplSidePaint) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.main_thread_should_always_be_low_latency = true;
+ scheduler_settings.impl_side_painting = true;
+ StateMachine state(scheduler_settings);
+ SET_UP_STATE(state)
+
+ // Start clean and set commit.
+ state.SetNeedsCommit();
+
+ // Begin the frame.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Tell the scheduler the frame finished.
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
+
+ // Commit.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+
+ // Now commit should wait for activation.
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION);
+
+ // No activation yet, so this commit is not drawn yet. Force to draw this
+ // frame, and still block BeginMainFrame.
+ state.SetNeedsRedraw(true);
+ state.SetNeedsCommit();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Cannot BeginMainFrame yet since last commit is not yet activated and drawn.
+ state.OnBeginImplFrame();
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Now activate sync tree.
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW);
+
+ // Swap throttled. Do not draw.
+ state.DidSwapBuffers();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
+
+ // Haven't draw since last commit, do not begin new main frame.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // At BeginImplFrame deadline, draw. This draws unblocks BeginMainFrame.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
+
+ // Now will be able to start main frame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_FALSE(state.needs_redraw());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start clean and set commit.
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -866,8 +1072,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
// Tell the scheduler the frame finished.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
// First commit.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
@@ -888,11 +1093,11 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
// Should be synchronized, no draw needed, no action needed.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
EXPECT_FALSE(state.needs_redraw());
// Next BeginImplFrame should initiate second commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -907,33 +1112,35 @@ TEST(SchedulerStateMachineTest, TestRequestCommitInvisible) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
+// See ThreadProxy::BeginMainFrame "EarlyOut_NotVisible" /
+// "EarlyOut_OutputSurfaceLost" cases.
+TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start clean and set commit.
state.SetNeedsCommit();
// Begin the frame while visible.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Become invisible and abort BeginMainFrame.
state.SetVisible(false);
- state.BeginMainFrameAborted(false);
+ state.BeginMainFrameAborted(CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
+
+ // NeedsCommit should now be true again because we never actually did a
+ // commit.
+ EXPECT_TRUE(state.NeedsCommit());
// We should now be back in the idle state as if we never started the frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// We shouldn't do anything on the BeginImplFrame deadline.
@@ -945,22 +1152,23 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
// Although we have aborted on this frame and haven't cancelled the commit
// (i.e. need another), don't send another BeginMainFrame yet.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.NeedsCommit());
// Start a new frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
// We should be starting the commit now.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
+// See ThreadProxy::BeginMainFrame "EarlyOut_NoUpdates" case.
+TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
@@ -971,25 +1179,22 @@ TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
// Get into a begin frame / commit state.
state.SetNeedsCommit();
-
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
- // Abort the commit, cancelling future commits.
- state.BeginMainFrameAborted(true);
+ // Abort the commit, true means that the BeginMainFrame was sent but there
+ // was no work to do on the main thread.
+ state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- // Verify that another commit doesn't start on the same frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ // NeedsCommit should now be false because the commit was actually handled.
EXPECT_FALSE(state.NeedsCommit());
- // Start a new frame; draw because this is the first frame since output
- // surface init'd.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ // Even though the commit was aborted, we still expect to draw the new frame.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -997,163 +1202,22 @@ TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
state.DidSwapBuffers();
state.DidSwapBuffersComplete();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Verify another commit doesn't start on another frame either.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_FALSE(state.NeedsCommit());
-
- // Verify another commit can start if requested, though.
- state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
-}
-
-TEST(SchedulerStateMachineTest,
- AbortBeginMainFrameAndCancelCommitWhenInvisible) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.DidCreateAndInitializeOutputSurface();
- state.SetVisible(true);
- state.SetCanDraw(true);
-
- // Get into a begin frame / commit state.
- state.SetNeedsCommit();
-
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
- EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- // Become invisible and abort BeginMainFrame.
- state.SetVisible(false);
- state.BeginMainFrameAborted(true);
-
- // Verify that another commit doesn't start on the same frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
- // Become visible and start a new frame.
- state.SetVisible(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-
- // Draw because this is the first frame since output surface init'd.
state.OnBeginImplFrameDeadline();
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- state.DidSwapBuffers();
- state.DidSwapBuffersComplete();
-
- // Verify another commit doesn't start on another frame either.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Verify another commit can start if requested, though.
state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
-}
-
-TEST(SchedulerStateMachineTest,
- AbortBeginMainFrameAndRequestCommitWhenInvisible) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.DidCreateAndInitializeOutputSurface();
- state.SetVisible(true);
- state.SetCanDraw(true);
-
- // Get into a begin frame / commit state.
- state.SetNeedsCommit();
-
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
- EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- // Become invisible and abort BeginMainFrame.
- state.SetVisible(false);
- state.BeginMainFrameAborted(true);
-
- // Verify that another commit doesn't start on the same frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_FALSE(state.NeedsCommit());
-
- // Asking for a commit while not visible won't make it happen.
- state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // Become visible but nothing happens until the next frame.
- state.SetVisible(true);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // We should get that commit when we begin the next frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-}
-
-TEST(SchedulerStateMachineTest,
- AbortBeginMainFrameAndRequestCommitAndBeginImplFrameWhenInvisible) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.DidCreateAndInitializeOutputSurface();
- state.SetVisible(true);
- state.SetCanDraw(true);
-
- // Get into a begin frame / commit state.
- state.SetNeedsCommit();
-
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
- EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- // Become invisible and abort BeginMainFrame.
- state.SetVisible(false);
- state.BeginMainFrameAborted(true);
-
- // Asking for a commit while not visible won't make it happen.
- state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // Begin a frame when not visible, the scheduler animates but does not commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // Become visible and the requested commit happens immediately.
- state.SetVisible(true);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ state.OnBeginImplFrame();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
@@ -1169,14 +1233,14 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that the first init does not SetNeedsCommit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that a needs commit initiates a BeginMainFrame.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1184,19 +1248,13 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
EXPECT_NE(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
state.DidLoseOutputSurface();
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
state.UpdateState(state.NextAction());
// Once context recreation begins, nothing should happen.
@@ -1206,7 +1264,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
// When the context is recreated, we should begin a commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1214,84 +1272,140 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
TEST(SchedulerStateMachineTest,
TestContextLostWhenIdleAndCommitRequestedWhileRecreating) {
SchedulerSettings default_scheduler_settings;
+ // We use impl side painting because it's the more complicated version.
+ default_scheduler_settings.impl_side_painting = true;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
EXPECT_NE(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
state.DidLoseOutputSurface();
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_LOST);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Once context recreation begins, nothing should happen.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// While context is recreating, commits shouldn't begin.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Recreate the context
state.DidCreateAndInitializeOutputSurface();
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT);
EXPECT_FALSE(state.RedrawPending());
- // When the context is recreated, we should begin a commit
+ // When the context is recreated, we wait until the next BeginImplFrame
+ // before starting.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // When the BeginFrame comes in we should begin a commit
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+
+ // Until that commit finishes, we shouldn't be drawing or animate.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ // Finish the commit, which should make the surface active.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_ACTIVE);
+
// Finishing the first commit after initializing an output surface should
// automatically cause a redraw.
EXPECT_TRUE(state.RedrawPending());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.RedrawPending());
+
+ // Next frame as no work to do.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Once the context is recreated, whether we draw should be based on
- // SetCanDraw.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ // SetCanDraw if waiting on first draw after activate.
+ state.SetNeedsRedraw(true);
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
state.SetCanDraw(false);
- EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.SetCanDraw(true);
- EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
- state.NextAction());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Once the context is recreated, whether we draw should be based on
+ // SetCanDraw if waiting on first draw after activate.
+ state.SetNeedsRedraw(true);
+ state.SetNeedsCommit();
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ // Activate so we need the first draw
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.SetCanDraw(false);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
+ state.SetCanDraw(true);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
}
TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Get a commit in flight.
state.SetNeedsCommit();
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1308,7 +1422,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
// Ask for another draw. Expect nothing happens.
state.SetNeedsRedraw(true);
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
// Finish the frame, and commit.
state.NotifyBeginMainFrameStarted();
@@ -1321,36 +1435,30 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
// Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadlinePending();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
}
TEST(SchedulerStateMachineTest,
TestContextLostWhileCommitInProgressAndAnotherCommitRequested) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Get a commit in flight.
state.SetNeedsCommit();
@@ -1358,7 +1466,7 @@ TEST(SchedulerStateMachineTest,
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1388,25 +1496,23 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
// Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadlinePending();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(
@@ -1414,7 +1520,7 @@ TEST(SchedulerStateMachineTest,
// After we get a new output surface, the commit flow should start.
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1434,25 +1540,19 @@ TEST(SchedulerStateMachineTest,
TEST(SchedulerStateMachineTest, DontDrawBeforeCommitAfterLostOutputSurface) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
// Cause a lost output surface, and restore it.
state.DidLoseOutputSurface();
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
state.UpdateState(state.NextAction());
state.DidCreateAndInitializeOutputSurface();
EXPECT_FALSE(state.RedrawPending());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest,
@@ -1460,11 +1560,7 @@ TEST(SchedulerStateMachineTest,
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetCommitState(
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
@@ -1483,6 +1579,25 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
}
+TEST(SchedulerStateMachineTest, TestNoBeginFrameNeededWhenInvisible) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetVisible(true);
+
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ state.SetNeedsRedraw(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ state.SetVisible(false);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ state.SetVisible(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+}
+
TEST(SchedulerStateMachineTest, TestNoBeginMainFrameWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
@@ -1491,7 +1606,15 @@ TEST(SchedulerStateMachineTest, TestNoBeginMainFrameWhenInvisible) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(false);
state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ // When become visible again, the needs commit should still be pending.
+ state.SetVisible(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
@@ -1507,7 +1630,7 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.UpdateState(state.NextAction());
EXPECT_TRUE(state.active_tree_needs_first_draw());
@@ -1517,11 +1640,7 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsCommit();
state.DidLoseOutputSurface();
@@ -1538,19 +1657,13 @@ TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) {
// lost the output surface and are trying to get the first commit, since the
// main thread will just abort anyway.
state.SetVisible(false);
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction())
- << state.AsValue()->ToString();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
}
TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-
- state.SetCanDraw(true);
- state.SetVisible(true);
+ SET_UP_STATE(state)
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(false);
@@ -1570,19 +1683,16 @@ TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
}
-TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyAfterAbortedCommit) {
+TEST(SchedulerStateMachineTest,
+ TestTriggerDeadlineImmediatelyAfterAbortedCommit) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// This test mirrors what happens during the first frame of a scroll gesture.
// First we get the input event and a BeginFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
// As a response the compositor requests a redraw and a commit to tell the
// main thread about the new scroll offset.
@@ -1597,11 +1707,11 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyAfterAbortedCommit) {
// Since only the scroll offset changed, the main thread will abort the
// commit.
- state.BeginMainFrameAborted(true);
+ state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
// Since the commit was aborted, we should draw right away instead of waiting
// for the deadline.
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
void FinishPreviousCommitAndDrawWithoutExitingDeadline(
@@ -1617,11 +1727,11 @@ void FinishPreviousCommitAndDrawWithoutExitingDeadline(
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
@@ -1632,17 +1742,13 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// This test ensures that impl-draws are prioritized over main thread updates
// in prefer impl latency mode.
state.SetNeedsRedraw(true);
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1650,9 +1756,9 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
// Verify the deadline is not triggered early until we enter
// prefer impl latency mode.
- EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.SetImplLatencyTakesPriority(true);
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
// Trigger the deadline.
state.OnBeginImplFrameDeadline();
@@ -1679,52 +1785,64 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
// and did not just swap.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyOnLostOutputSurface) {
+TEST(SchedulerStateMachineTest,
+ TestTriggerDeadlineImmediatelyOnLostOutputSurface) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.DidLoseOutputSurface();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// The deadline should be triggered immediately when output surface is lost.
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
+}
+
+TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyWhenInvisible) {
+ SchedulerSettings settings;
+ settings.impl_side_painting = true;
+ StateMachine state(settings);
+ SET_UP_STATE(state)
+
+ state.SetNeedsCommit();
+
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
+
+ state.SetVisible(false);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
TEST(SchedulerStateMachineTest, TestSetNeedsAnimate) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Test requesting an animation that, when run, causes us to draw.
state.SetNeedsAnimate();
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.OnBeginImplFrameDeadlinePending();
@@ -1737,11 +1855,7 @@ TEST(SchedulerStateMachineTest, TestAnimateBeforeCommit) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Check that animations are updated before we start a commit.
state.SetNeedsAnimate();
@@ -1750,7 +1864,7 @@ TEST(SchedulerStateMachineTest, TestAnimateBeforeCommit) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1765,11 +1879,7 @@ TEST(SchedulerStateMachineTest, TestAnimateAfterCommitBeforeDraw) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Check that animations are updated before we start a commit.
state.SetNeedsAnimate();
@@ -1778,7 +1888,7 @@ TEST(SchedulerStateMachineTest, TestAnimateAfterCommitBeforeDraw) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1798,11 +1908,7 @@ TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Test requesting an animation after we have already animated during this
// frame.
@@ -1810,7 +1916,7 @@ TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) {
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.SetNeedsAnimate();
@@ -1821,5 +1927,51 @@ TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) {
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
}
+TEST(SchedulerStateMachineTest, TestForwardBeginFramesToChildren) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state)
+
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ state.SetChildrenNeedBeginFrames(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+}
+
+TEST(SchedulerStateMachineTest, TestDeferCommit) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state)
+
+ state.SetDeferCommits(true);
+
+ state.SetNeedsCommit();
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.SetDeferCommits(false);
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
+TEST(SchedulerStateMachineTest, EarlyOutCommitWantsProactiveBeginFrame) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state);
+
+ EXPECT_FALSE(state.ProactiveBeginFrameWanted());
+ bool commit_has_no_updates = true;
+ state.UpdateStateOnCommit(commit_has_no_updates);
+ EXPECT_TRUE(state.ProactiveBeginFrameWanted());
+ state.OnBeginImplFrame();
+ EXPECT_FALSE(state.ProactiveBeginFrameWanted());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index 7da62676c6c..d2b12d768a5 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -1,35 +1,34 @@
// 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/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/power_monitor/power_monitor_source.h"
#include "base/run_loop.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "cc/test/begin_frame_args_test.h"
#include "cc/test/ordered_simple_task_runner.h"
#include "cc/test/scheduler_test_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
- do { \
- EXPECT_EQ(expected_num_actions, client.num_actions_()); \
- if (action_index >= 0) { \
- ASSERT_LT(action_index, client.num_actions_()) << scheduler; \
- EXPECT_STREQ(action, client.Action(action_index)); \
- } \
- for (int i = expected_num_actions; i < client.num_actions_(); ++i) \
- ADD_FAILURE() << "Unexpected action: " << client.Action(i) \
- << " with state:\n" << client.StateForAction(i); \
+#define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
+ do { \
+ EXPECT_EQ(expected_num_actions, client->num_actions_()); \
+ if (action_index >= 0) { \
+ ASSERT_LT(action_index, client->num_actions_()) << scheduler_.get(); \
+ EXPECT_STREQ(action, client->Action(action_index)); \
+ } \
+ for (int i = expected_num_actions; i < client->num_actions_(); ++i) \
+ ADD_FAILURE() << "Unexpected action: " << client->Action(i) \
+ << " with state:\n" << client->StateForAction(i); \
} while (false)
#define EXPECT_NO_ACTION(client) EXPECT_ACTION("", client, -1, 0)
@@ -37,64 +36,20 @@
#define EXPECT_SINGLE_ACTION(action, client) \
EXPECT_ACTION(action, client, 0, 1)
+#define EXPECT_SCOPED(statements) \
+ { \
+ SCOPED_TRACE(""); \
+ statements; \
+ }
+
namespace cc {
namespace {
-class FakeSchedulerClient;
-
-void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
- FakeSchedulerClient* client);
-
class FakeSchedulerClient : public SchedulerClient {
public:
- struct FakeBeginFrameSourceForFakeSchedulerClient
- : public FakeBeginFrameSource {
- FakeSchedulerClient* client_;
-
- explicit FakeBeginFrameSourceForFakeSchedulerClient(
- FakeSchedulerClient* client)
- : client_(client) {}
-
- void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
- if (needs_begin_frames) {
- client_->actions_.push_back("SetNeedsBeginFrames(true)");
- } else {
- client_->actions_.push_back("SetNeedsBeginFrames(false)");
- }
- client_->states_.push_back(client_->scheduler_->AsValue());
- }
- };
-
- class FakePowerMonitorSource : public base::PowerMonitorSource {
- public:
- FakePowerMonitorSource() {}
- ~FakePowerMonitorSource() override {}
- void GeneratePowerStateEvent(bool on_battery_power) {
- on_battery_power_impl_ = on_battery_power;
- ProcessPowerEvent(POWER_STATE_EVENT);
- base::MessageLoop::current()->RunUntilIdle();
- }
- bool IsOnBatteryPowerImpl() override { return on_battery_power_impl_; }
-
- private:
- bool on_battery_power_impl_;
- };
-
FakeSchedulerClient()
: automatic_swap_ack_(true),
- swap_contains_incomplete_tile_(false),
- redraw_will_happen_if_update_visible_tiles_happens_(false),
- now_src_(TestNowSource::Create()),
- task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
- fake_frame_source_(this),
- fake_power_monitor_source_(new FakePowerMonitorSource),
- power_monitor_(make_scoped_ptr<base::PowerMonitorSource>(
- fake_power_monitor_source_)),
scheduler_(nullptr) {
- // A bunch of tests require Now() to be > BeginFrameArgs::DefaultInterval()
- now_src_->AdvanceNow(base::TimeDelta::FromMilliseconds(100));
- // Fail if we need to run 100 tasks in a row.
- task_runner_->SetRunTaskLimit(100);
Reset();
}
@@ -105,21 +60,19 @@ class FakeSchedulerClient : public SchedulerClient {
swap_will_happen_if_draw_happens_ = true;
num_draws_ = 0;
log_anticipated_draw_time_change_ = false;
+ begin_frame_args_sent_to_children_ = BeginFrameArgs();
}
- TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
- scheduler_ = TestScheduler::Create(
- now_src_, this, settings, 0, task_runner_, &power_monitor_);
- DCHECK(scheduler_);
- return scheduler_.get();
- }
+ void set_scheduler(TestScheduler* scheduler) { scheduler_ = scheduler; }
// Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
// for tests that do.
void set_log_anticipated_draw_time_change(bool log) {
log_anticipated_draw_time_change_ = log;
}
- bool needs_begin_frames() { return fake_frame_source_.NeedsBeginFrames(); }
+ bool needs_begin_frames() {
+ return scheduler_->frame_source().NeedsBeginFrames();
+ }
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]; }
@@ -128,40 +81,6 @@ class FakeSchedulerClient : public SchedulerClient {
return posted_begin_impl_frame_deadline_;
}
- bool ExternalBeginFrame() {
- return scheduler_->settings().begin_frame_scheduling_enabled &&
- scheduler_->settings().throttle_frame_production;
- }
- FakeBeginFrameSource* ExternalBeginFrameSource() override {
- return &fake_frame_source_;
- }
-
- base::PowerMonitor* PowerMonitor() { return &power_monitor_; }
-
- FakePowerMonitorSource* PowerMonitorSource() {
- return fake_power_monitor_source_;
- }
-
- void AdvanceFrame() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
- "FakeSchedulerClient::AdvanceFrame");
- // EXPECT_TRUE(needs_begin_frames());
- if (ExternalBeginFrame()) {
- // Creep the time forward so that any BeginFrameArgs is not equal to the
- // last one otherwise we violate the BeginFrameSource contract.
- now_src_->AdvanceNowMicroseconds(1);
- fake_frame_source_.TestOnBeginFrame(
- CreateBeginFrameArgsForTesting(now_src_));
- EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- }
-
- EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false)));
- EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- }
-
- OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
- TestNowSource* now_src() { return now_src_.get(); }
-
int ActionIndex(const char* action) const {
for (size_t i = 0; i < actions_.size(); i++)
if (!strcmp(actions_[i], action))
@@ -169,10 +88,6 @@ class FakeSchedulerClient : public SchedulerClient {
return -1;
}
- void SetSwapContainsIncompleteTile(bool contain) {
- swap_contains_incomplete_tile_ = contain;
- }
-
bool HasAction(const char* action) const {
return ActionIndex(action) >= 0;
}
@@ -186,25 +101,20 @@ class FakeSchedulerClient : public SchedulerClient {
void SetAutomaticSwapAck(bool automatic_swap_ack) {
automatic_swap_ack_ = automatic_swap_ack;
}
- void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
- redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
- }
// SchedulerClient implementation.
void WillBeginImplFrame(const BeginFrameArgs& args) override {
- actions_.push_back("WillBeginImplFrame");
- states_.push_back(scheduler_->AsValue());
+ PushAction("WillBeginImplFrame");
}
+ void DidFinishImplFrame() override {}
+
void ScheduledActionSendBeginMainFrame() override {
- actions_.push_back("ScheduledActionSendBeginMainFrame");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionSendBeginMainFrame");
}
void ScheduledActionAnimate() override {
- actions_.push_back("ScheduledActionAnimate");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionAnimate");
}
DrawResult ScheduledActionDrawAndSwapIfPossible() override {
- actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionDrawAndSwapIfPossible");
num_draws_++;
DrawResult result =
draw_will_happen_ ? DRAW_SUCCESS : DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
@@ -212,12 +122,6 @@ class FakeSchedulerClient : public SchedulerClient {
draw_will_happen_ && swap_will_happen_if_draw_happens_;
if (swap_will_happen) {
scheduler_->DidSwapBuffers();
- if (swap_contains_incomplete_tile_) {
- scheduler_->SetSwapUsedIncompleteTile(true);
- swap_contains_incomplete_tile_ = false;
- } else {
- scheduler_->SetSwapUsedIncompleteTile(false);
- }
if (automatic_swap_ack_)
scheduler_->DidSwapBuffersComplete();
@@ -225,35 +129,26 @@ class FakeSchedulerClient : public SchedulerClient {
return result;
}
DrawResult ScheduledActionDrawAndSwapForced() override {
- actions_.push_back("ScheduledActionDrawAndSwapForced");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionDrawAndSwapForced");
return DRAW_SUCCESS;
}
- void ScheduledActionCommit() override {
- actions_.push_back("ScheduledActionCommit");
- states_.push_back(scheduler_->AsValue());
- }
- void ScheduledActionUpdateVisibleTiles() override {
- actions_.push_back("ScheduledActionUpdateVisibleTiles");
- states_.push_back(scheduler_->AsValue());
- if (redraw_will_happen_if_update_visible_tiles_happens_)
- scheduler_->SetNeedsRedraw();
- }
+ void ScheduledActionCommit() override { PushAction("ScheduledActionCommit"); }
void ScheduledActionActivateSyncTree() override {
- actions_.push_back("ScheduledActionActivateSyncTree");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionActivateSyncTree");
}
void ScheduledActionBeginOutputSurfaceCreation() override {
- actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionBeginOutputSurfaceCreation");
+ }
+ void ScheduledActionPrepareTiles() override {
+ PushAction("ScheduledActionPrepareTiles");
}
- void ScheduledActionManageTiles() override {
- actions_.push_back("ScheduledActionManageTiles");
+ void ScheduledActionInvalidateOutputSurface() override {
+ actions_.push_back("ScheduledActionInvalidateOutputSurface");
states_.push_back(scheduler_->AsValue());
}
void DidAnticipatedDrawTimeChange(base::TimeTicks) override {
if (log_anticipated_draw_time_change_)
- actions_.push_back("DidAnticipatedDrawTimeChange");
+ PushAction("DidAnticipatedDrawTimeChange");
}
base::TimeDelta DrawDurationEstimate() override { return base::TimeDelta(); }
base::TimeDelta BeginMainFrameToCommitDurationEstimate() override {
@@ -263,7 +158,13 @@ class FakeSchedulerClient : public SchedulerClient {
return base::TimeDelta();
}
- void DidBeginImplFrameDeadline() override {}
+ void SendBeginFramesToChildren(const BeginFrameArgs& args) override {
+ begin_frame_args_sent_to_children_ = args;
+ }
+
+ void SendBeginMainFrameNotExpectedSoon() override {
+ PushAction("SendBeginMainFrameNotExpectedSoon");
+ }
base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) {
return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback,
@@ -271,6 +172,19 @@ class FakeSchedulerClient : public SchedulerClient {
state);
}
+ bool begin_frame_is_sent_to_children() const {
+ return begin_frame_args_sent_to_children_.IsValid();
+ }
+
+ const BeginFrameArgs& begin_frame_args_sent_to_children() const {
+ return begin_frame_args_sent_to_children_;
+ }
+
+ void PushAction(const char* description) {
+ actions_.push_back(description);
+ states_.push_back(scheduler_->AsValue());
+ }
+
protected:
bool ImplFrameDeadlinePendingCallback(bool state) {
return scheduler_->BeginImplFrameDeadlinePending() == state;
@@ -281,217 +195,548 @@ class FakeSchedulerClient : public SchedulerClient {
bool automatic_swap_ack_;
int num_draws_;
bool log_anticipated_draw_time_change_;
- bool swap_contains_incomplete_tile_;
- bool redraw_will_happen_if_update_visible_tiles_happens_;
+ BeginFrameArgs begin_frame_args_sent_to_children_;
base::TimeTicks posted_begin_impl_frame_deadline_;
std::vector<const char*> actions_;
- std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_;
+ std::vector<scoped_refptr<base::trace_event::ConvertableToTraceFormat>>
+ states_;
+ TestScheduler* scheduler_;
+};
+
+class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
+ public:
+ SchedulerClientWithFixedEstimates(
+ base::TimeDelta draw_duration,
+ base::TimeDelta begin_main_frame_to_commit_duration,
+ base::TimeDelta commit_to_activate_duration)
+ : draw_duration_(draw_duration),
+ begin_main_frame_to_commit_duration_(
+ begin_main_frame_to_commit_duration),
+ commit_to_activate_duration_(commit_to_activate_duration) {}
+
+ base::TimeDelta DrawDurationEstimate() override { return draw_duration_; }
+ base::TimeDelta BeginMainFrameToCommitDurationEstimate() override {
+ return begin_main_frame_to_commit_duration_;
+ }
+ base::TimeDelta CommitToActivateDurationEstimate() override {
+ return commit_to_activate_duration_;
+ }
+
+ private:
+ base::TimeDelta draw_duration_;
+ base::TimeDelta begin_main_frame_to_commit_duration_;
+ base::TimeDelta commit_to_activate_duration_;
+};
+
+class FakeExternalBeginFrameSource : public BeginFrameSourceMixIn {
+ public:
+ explicit FakeExternalBeginFrameSource(FakeSchedulerClient* client)
+ : client_(client) {}
+ ~FakeExternalBeginFrameSource() override {}
+
+ void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
+ if (needs_begin_frames) {
+ client_->PushAction("SetNeedsBeginFrames(true)");
+ } else {
+ client_->PushAction("SetNeedsBeginFrames(false)");
+ }
+ }
+
+ void TestOnBeginFrame(const BeginFrameArgs& args) {
+ return CallOnBeginFrame(args);
+ }
+
+ private:
+ FakeSchedulerClient* client_;
+};
+
+class SchedulerTest : public testing::Test {
+ public:
+ SchedulerTest()
+ : now_src_(TestNowSource::Create()),
+ task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
+ fake_external_begin_frame_source_(nullptr) {
+ // A bunch of tests require Now() to be > BeginFrameArgs::DefaultInterval()
+ now_src_->AdvanceNow(base::TimeDelta::FromMilliseconds(100));
+ // Fail if we need to run 100 tasks in a row.
+ task_runner_->SetRunTaskLimit(100);
+ }
+
+ ~SchedulerTest() override {}
+
+ protected:
+ TestScheduler* CreateScheduler() {
+ scoped_ptr<FakeExternalBeginFrameSource> fake_external_begin_frame_source;
+ if (scheduler_settings_.use_external_begin_frame_source) {
+ fake_external_begin_frame_source.reset(
+ new FakeExternalBeginFrameSource(client_.get()));
+ fake_external_begin_frame_source_ =
+ fake_external_begin_frame_source.get();
+ }
+ scheduler_ = TestScheduler::Create(now_src_, client_.get(),
+ scheduler_settings_, 0, task_runner_,
+ fake_external_begin_frame_source.Pass());
+ DCHECK(scheduler_);
+ client_->set_scheduler(scheduler_.get());
+ return scheduler_.get();
+ }
+
+ void CreateSchedulerAndInitSurface() {
+ CreateScheduler();
+ EXPECT_SCOPED(InitializeOutputSurfaceAndFirstCommit());
+ }
+
+ void SetUpScheduler(bool initSurface) {
+ SetUpScheduler(make_scoped_ptr(new FakeSchedulerClient), initSurface);
+ }
+
+ void SetUpScheduler(scoped_ptr<FakeSchedulerClient> client,
+ bool initSurface) {
+ client_ = client.Pass();
+ if (initSurface)
+ CreateSchedulerAndInitSurface();
+ else
+ CreateScheduler();
+ }
+
+ OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
+ TestNowSource* now_src() { return now_src_.get(); }
+
+ // As this function contains EXPECT macros, to allow debugging it should be
+ // called inside EXPECT_SCOPED like so;
+ // EXPECT_SCOPED(client.InitializeOutputSurfaceAndFirstCommit(scheduler));
+ void InitializeOutputSurfaceAndFirstCommit() {
+ TRACE_EVENT0("cc",
+ "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit");
+ DCHECK(scheduler_);
+
+ // Check the client doesn't have any actions queued when calling this
+ // function.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(client_->needs_begin_frames());
+
+ // Start the initial output surface creation.
+ EXPECT_FALSE(scheduler_->CanStart());
+ scheduler_->SetCanStart();
+ scheduler_->SetVisible(true);
+ scheduler_->SetCanDraw(true);
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+
+ client_->Reset();
+
+ // We don't see anything happening until the first impl frame.
+ scheduler_->DidCreateAndInitializeOutputSurface();
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ {
+ SCOPED_TRACE("Do first frame to commit after initialize.");
+ AdvanceFrame();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommitThenActivateIfNeeded();
+
+ EXPECT_FALSE(scheduler_->CommitPending());
+
+ if (scheduler_settings_.using_synchronous_renderer_compositor) {
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ } else {
+ // Run the posted deadline task.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ }
+
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ }
+
+ client_->Reset();
+
+ {
+ SCOPED_TRACE(
+ "Run second frame so Scheduler calls SetNeedsBeginFrame(false).");
+ AdvanceFrame();
+
+ if (!scheduler_settings_.using_synchronous_renderer_compositor) {
+ // Run the posted deadline task.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ }
+
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ }
+
+ EXPECT_FALSE(client_->needs_begin_frames());
+ client_->Reset();
+ }
+
+ // As this function contains EXPECT macros, to allow debugging it should be
+ // called inside EXPECT_SCOPED like so;
+ // EXPECT_SCOPED(client.AdvanceFrame());
+ void AdvanceFrame() {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
+ "FakeSchedulerClient::AdvanceFrame");
+ // Consume any previous deadline first, if no deadline is currently
+ // pending, ImplFrameDeadlinePending will return false straight away and we
+ // will run no tasks.
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Send the next BeginFrame message if using an external source, otherwise
+ // it will be already in the task queue.
+ if (scheduler_->settings().use_external_begin_frame_source &&
+ scheduler_->FrameProductionThrottled()) {
+ EXPECT_TRUE(client_->needs_begin_frames());
+ SendNextBeginFrame();
+ }
+
+ if (!scheduler_->settings().using_synchronous_renderer_compositor) {
+ // Then run tasks until new deadline is scheduled.
+ EXPECT_TRUE(task_runner_->RunTasksWhile(
+ client_->ImplFrameDeadlinePending(false)));
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ }
+ }
+
+ void SendNextBeginFrame() {
+ DCHECK(scheduler_->settings().use_external_begin_frame_source);
+ // Creep the time forward so that any BeginFrameArgs is not equal to the
+ // last one otherwise we violate the BeginFrameSource contract.
+ now_src_->AdvanceNow(BeginFrameArgs::DefaultInterval());
+ fake_external_begin_frame_source_->TestOnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src()));
+ }
+
+ FakeExternalBeginFrameSource* fake_external_begin_frame_source() const {
+ return fake_external_begin_frame_source_;
+ }
+
+ void MainFrameInHighLatencyMode(
+ int64 begin_main_frame_to_commit_estimate_in_ms,
+ int64 commit_to_activate_estimate_in_ms,
+ bool impl_latency_takes_priority,
+ bool should_send_begin_main_frame);
+ void BeginFramesNotFromClient(bool use_external_begin_frame_source,
+ bool throttle_frame_production);
+ void BeginFramesNotFromClient_SwapThrottled(
+ bool use_external_begin_frame_source,
+ bool throttle_frame_production);
+ void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
+ bool impl_side_painting);
+ void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting);
+
scoped_refptr<TestNowSource> now_src_;
scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
- FakeBeginFrameSourceForFakeSchedulerClient fake_frame_source_;
- FakePowerMonitorSource* fake_power_monitor_source_;
- base::PowerMonitor power_monitor_;
+ FakeExternalBeginFrameSource* fake_external_begin_frame_source_;
+ SchedulerSettings scheduler_settings_;
+ scoped_ptr<FakeSchedulerClient> client_;
scoped_ptr<TestScheduler> scheduler_;
};
-void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
- FakeSchedulerClient* client) {
- TRACE_EVENT0("cc",
- "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit");
-
- scheduler->DidCreateAndInitializeOutputSurface();
- scheduler->SetNeedsCommit();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- if (scheduler->settings().impl_side_painting)
- scheduler->NotifyReadyToActivate();
-
- {
- SCOPED_TRACE("Go through the motions to draw the commit");
- client->AdvanceFrame();
- }
+TEST_F(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(false);
+ scheduler_->SetCanStart();
+ scheduler_->SetVisible(true);
+ scheduler_->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ client_->Reset();
+ scheduler_->DidCreateAndInitializeOutputSurface();
+ EXPECT_NO_ACTION(client_);
+}
- // Run the posted deadline task.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+TEST_F(SchedulerTest, SendBeginFramesToChildren) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- {
- SCOPED_TRACE(
- "We need another BeginImplFrame so Scheduler calls "
- "SetNeedsBeginFrame(false).");
- client->AdvanceFrame();
- }
+ EXPECT_FALSE(client_->begin_frame_is_sent_to_children());
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ scheduler_->SetChildrenNeedBeginFrames(true);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(client_->needs_begin_frames());
+}
- // Run the posted deadline task.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+TEST_F(SchedulerTest, SendBeginFramesToChildrenWithoutCommit) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- // EXPECT_FALSE(client->needs_begin_frames());
+ EXPECT_FALSE(client_->needs_begin_frames());
+ scheduler_->SetChildrenNeedBeginFrames(true);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
}
-TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- client.Reset();
- scheduler->DidCreateAndInitializeOutputSurface();
- EXPECT_NO_ACTION(client);
+TEST_F(SchedulerTest, SendBeginFramesToChildrenDeadlineNotAdjusted) {
+ // Set up client with specified estimates.
+ SchedulerClientWithFixedEstimates* client =
+ new SchedulerClientWithFixedEstimates(
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(2),
+ base::TimeDelta::FromMilliseconds(4));
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ EXPECT_FALSE(client_->needs_begin_frames());
+ scheduler_->SetChildrenNeedBeginFrames(true);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+
+ BeginFrameArgs frame_args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
+ fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
+
+ EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
+ EXPECT_EQ(client_->begin_frame_args_sent_to_children().deadline,
+ frame_args.deadline);
}
-TEST(SchedulerTest, RequestCommit) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+TEST_F(SchedulerTest, VideoNeedsBeginFrames) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetVideoNeedsBeginFrames(true);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ // WillBeginImplFrame is responsible for sending BeginFrames to video.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+
+ client_->Reset();
+ scheduler_->SetVideoNeedsBeginFrames(false);
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(client_->needs_begin_frames());
+}
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, RequestCommit) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame should prepare the draw.
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame deadline should draw.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ client_->Reset();
+}
+
+TEST_F(SchedulerTest, RequestCommitAfterSetDeferCommit) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetDeferCommits(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ // There are no pending tasks or actions.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(client_->needs_begin_frames());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- client.Reset();
+ client_->Reset();
+ scheduler_->SetDeferCommits(false);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ // Start new BeginMainFrame after defer commit is off.
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
}
-TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+TEST_F(SchedulerTest, DeferCommitWithRedraw) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetDeferCommits(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+
+ // The SetNeedsRedraw will override the SetDeferCommits(true), to allow a
+ // begin frame to be needed.
+ client_->Reset();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ AdvanceFrame();
+ // BeginMainFrame is not sent during the defer commit is on.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ AdvanceFrame();
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+}
+
+TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Now SetNeedsCommit again. Calling here means we need a second commit.
- scheduler->SetNeedsCommit();
- EXPECT_EQ(client.num_actions_(), 0);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_EQ(client_->num_actions_(), 0);
+ client_->Reset();
// Finish the first commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
// Because we just swapped, the Scheduler should also request the next
// BeginImplFrame from the OutputSurface.
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Since another commit is needed, the next BeginImplFrame should initiate
// the second commit.
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// Finishing the commit before the deadline should post a new deadline task
// to trigger the deadline early.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// On the next BeginImplFrame, verify we go back to a quiescent state and
// no longer request BeginImplFrames.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(client_->needs_begin_frames());
+ client_->Reset();
}
class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
public:
+ SchedulerClientThatsetNeedsDrawInsideDraw()
+ : FakeSchedulerClient(), request_redraws_(false) {}
+
void ScheduledActionSendBeginMainFrame() override {}
+
+ void SetRequestRedrawsInsideDraw(bool enable) { request_redraws_ = enable; }
+
DrawResult ScheduledActionDrawAndSwapIfPossible() override {
// Only SetNeedsRedraw the first time this is called
- if (!num_draws_)
+ if (request_redraws_) {
scheduler_->SetNeedsRedraw();
+ }
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
@@ -501,95 +746,95 @@ class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
}
void ScheduledActionCommit() override {}
- void ScheduledActionBeginOutputSurfaceCreation() override {}
void DidAnticipatedDrawTimeChange(base::TimeTicks) override {}
+
+ private:
+ bool request_redraws_;
};
// Tests for two different situations:
// 1. the scheduler dropping SetNeedsRedraw requests that happen inside
// a ScheduledActionDrawAndSwap
// 2. the scheduler drawing twice inside a single tick
-TEST(SchedulerTest, RequestRedrawInsideDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
-
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+TEST_F(SchedulerTest, RequestRedrawInsideDraw) {
+ SchedulerClientThatsetNeedsDrawInsideDraw* client =
+ new SchedulerClientThatsetNeedsDrawInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+ client->SetRequestRedrawsInsideDraw(true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
+
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+
+ client->SetRequestRedrawsInsideDraw(false);
+
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client_->num_draws());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(client.needs_begin_frames());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(client->needs_begin_frames());
}
// Test that requesting redraw inside a failed draw doesn't lose the request.
-TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- client.SetDrawWillHappen(false);
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
+TEST_F(SchedulerTest, RequestRedrawInsideFailedDraw) {
+ SchedulerClientThatsetNeedsDrawInsideDraw* client =
+ new SchedulerClientThatsetNeedsDrawInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ client->SetRequestRedrawsInsideDraw(true);
+ client->SetDrawWillHappen(false);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// Fail the draw.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
// We have a commit pending and the draw failed, and we didn't lose the redraw
// request.
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+
+ client->SetRequestRedrawsInsideDraw(false);
// Fail the draw again.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Draw successfully.
- client.SetDrawWillHappen(true);
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(3, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client->SetDrawWillHappen(true);
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(3, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
}
class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
@@ -613,7 +858,6 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
}
void ScheduledActionCommit() override {}
- void ScheduledActionBeginOutputSurfaceCreation() override {}
void DidAnticipatedDrawTimeChange(base::TimeTicks) override {}
void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; }
@@ -624,1521 +868,1844 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
// Tests for the scheduler infinite-looping on SetNeedsCommit requests that
// happen inside a ScheduledActionDrawAndSwap
-TEST(SchedulerTest, RequestCommitInsideDraw) {
- SchedulerClientThatSetNeedsCommitInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- EXPECT_FALSE(client.needs_begin_frames());
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_EQ(0, client.num_draws());
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.SetNeedsCommitOnNextDraw();
- client.AdvanceFrame();
- client.SetNeedsCommitOnNextDraw();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(client.needs_begin_frames());
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
-
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
-
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->CommitPending());
- EXPECT_TRUE(client.needs_begin_frames());
+TEST_F(SchedulerTest, RequestCommitInsideDraw) {
+ SchedulerClientThatSetNeedsCommitInsideDraw* client =
+ new SchedulerClientThatSetNeedsCommitInsideDraw;
+
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ EXPECT_FALSE(client->needs_begin_frames());
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_EQ(0, client->num_draws());
+ EXPECT_TRUE(client->needs_begin_frames());
+
+ client->SetNeedsCommitOnNextDraw();
+ EXPECT_SCOPED(AdvanceFrame());
+ client->SetNeedsCommitOnNextDraw();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->CommitPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->CommitPending());
- EXPECT_FALSE(client.needs_begin_frames());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->CommitPending());
+ EXPECT_FALSE(client->needs_begin_frames());
}
// Tests that when a draw fails then the pending commit should not be dropped.
-TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- client.SetDrawWillHappen(false);
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
+TEST_F(SchedulerTest, RequestCommitInsideFailedDraw) {
+ SchedulerClientThatsetNeedsDrawInsideDraw* client =
+ new SchedulerClientThatsetNeedsDrawInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ client->SetDrawWillHappen(false);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// Fail the draw.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
// We have a commit pending and the draw failed, and we didn't lose the commit
// request.
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Fail the draw again.
- client.AdvanceFrame();
+ EXPECT_SCOPED(AdvanceFrame());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Draw successfully.
- client.SetDrawWillHappen(true);
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(3, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client->SetDrawWillHappen(true);
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(3, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
}
-TEST(SchedulerTest, NoSwapWhenDrawFails) {
- SchedulerClientThatSetNeedsCommitInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
+TEST_F(SchedulerTest, NoSwapWhenDrawFails) {
+ SchedulerClientThatSetNeedsCommitInsideDraw* client =
+ new SchedulerClientThatSetNeedsCommitInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// Draw successfully, this starts a new frame.
- client.SetNeedsCommitOnNextDraw();
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
+ client->SetNeedsCommitOnNextDraw();
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Fail to draw, this should not start a frame.
- client.SetDrawWillHappen(false);
- client.SetNeedsCommitOnNextDraw();
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
+ client->SetDrawWillHappen(false);
+ client->SetNeedsCommitOnNextDraw();
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
}
-class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
+class SchedulerClientNeedsPrepareTilesInDraw : public FakeSchedulerClient {
public:
DrawResult ScheduledActionDrawAndSwapIfPossible() override {
- scheduler_->SetNeedsManageTiles();
+ scheduler_->SetNeedsPrepareTiles();
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
};
-// Test manage tiles is independant of draws.
-TEST(SchedulerTest, ManageTiles) {
- SchedulerClientNeedsManageTilesInDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // Request both draw and manage tiles. ManageTiles shouldn't
+// Test prepare tiles is independant of draws.
+TEST_F(SchedulerTest, PrepareTiles) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ // Request both draw and prepare tiles. PrepareTiles shouldn't
// be trigged until BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(scheduler->ManageTilesPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ client->Reset();
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
+ EXPECT_FALSE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
- client.Reset();
- client.AdvanceFrame();
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
// On the deadline, he actions should have occured in the right order.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- 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());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // 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_frames());
- EXPECT_EQ(0, client.num_draws());
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Request a draw. We don't need a PrepareTiles yet.
+ client->Reset();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
- client.Reset();
- client.AdvanceFrame();
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- // 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();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- 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());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Draw. The draw will trigger SetNeedsPrepareTiles, and
+ // then the PrepareTiles action will be triggered after the Draw.
+ // Afterwards, neither a draw nor PrepareTiles are pending.
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
// We need a BeginImplFrame where we don't swap to go idle.
- client.Reset();
- client.AdvanceFrame();
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- 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_frames());
- scheduler->SetNeedsManageTiles();
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_TRUE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->RedrawPending());
-
- // BeginImplFrame. There will be no draw, only ManageTiles.
- client.Reset();
- client.AdvanceFrame();
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_EQ(0, client->num_draws());
+
+ // Now trigger a PrepareTiles outside of a draw. We will then need
+ // a begin-frame for the PrepareTiles, but we don't need a draw.
+ client->Reset();
+ EXPECT_FALSE(client->needs_begin_frames());
+ scheduler_->SetNeedsPrepareTiles();
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+
+ // BeginImplFrame. There will be no draw, only PrepareTiles.
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client.num_draws());
- EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(0, client->num_draws());
+ EXPECT_FALSE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
}
-// Test that ManageTiles only happens once per frame. If an external caller
-// initiates it, then the state machine should not ManageTiles on that frame.
-TEST(SchedulerTest, ManageTilesOncePerFrame) {
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // If DidManageTiles during a frame, then ManageTiles should not occur again.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- EXPECT_TRUE(scheduler->ManageTilesPending());
- scheduler->DidManageTiles(); // An explicit ManageTiles.
- EXPECT_FALSE(scheduler->ManageTilesPending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // Next frame without DidManageTiles should ManageTiles with draw.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- 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());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
-
- // If we get another DidManageTiles within the same frame, we should
- // not ManageTiles on the next frame.
- scheduler->DidManageTiles(); // An explicit ManageTiles.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- EXPECT_TRUE(scheduler->ManageTilesPending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // If we get another DidManageTiles, we should not ManageTiles on the next
- // frame. This verifies we don't alternate calling ManageTiles once and twice.
- EXPECT_TRUE(scheduler->ManageTilesPending());
- scheduler->DidManageTiles(); // An explicit ManageTiles.
- EXPECT_FALSE(scheduler->ManageTilesPending());
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- EXPECT_TRUE(scheduler->ManageTilesPending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // Next frame without DidManageTiles should ManageTiles with draw.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- 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());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
+// Test that PrepareTiles only happens once per frame. If an external caller
+// initiates it, then the state machine should not PrepareTiles on that frame.
+TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // If DidPrepareTiles during a frame, then PrepareTiles should not occur
+ // again.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Next frame without DidPrepareTiles should PrepareTiles with draw.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client_->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client_->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ scheduler_->DidPrepareTiles(); // Corresponds to ScheduledActionPrepareTiles
+
+ // If we get another DidPrepareTiles within the same frame, we should
+ // not PrepareTiles on the next frame.
+ scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // If we get another DidPrepareTiles, we should not PrepareTiles on the next
+ // frame. This verifies we don't alternate calling PrepareTiles once and
+ // twice.
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Next frame without DidPrepareTiles should PrepareTiles with draw.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client_->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client_->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ scheduler_->DidPrepareTiles(); // Corresponds to ScheduledActionPrepareTiles
}
-TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = true;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
+TEST_F(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
- // SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SCOPED(AdvanceFrame());
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-
- client.Reset();
- scheduler->NotifyReadyToActivate();
- EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
-
- client.Reset();
- client.SetSwapContainsIncompleteTile(true);
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->RedrawPending());
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
+ // The deadline should be zero since there is no work other than drawing
+ // pending.
+ EXPECT_EQ(base::TimeTicks(), client->posted_begin_impl_frame_deadline());
+}
- client.Reset();
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
- // No more UpdateVisibleTiles().
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Begin new frame.
+ EXPECT_SCOPED(AdvanceFrame());
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+
+ // Set scheduler to wait for ready to draw. Schedule won't post deadline in
+ // the mode.
+ scheduler_->SetWaitForReadyToDraw();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Try to run posted deadline.
+ // There is no posted deadline.
+ EXPECT_NO_ACTION(client_);
+
+ // Scheduler received ready to draw signal, and posted deadline.
+ scheduler_->NotifyReadyToDraw();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
}
-TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
- SchedulerClientNeedsManageTilesInDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- client.Reset();
- scheduler->SetNeedsRedraw();
- client.AdvanceFrame();
+TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostOutputSurface) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
- // The deadline should be zero since there is no work other than drawing
- // pending.
- EXPECT_EQ(base::TimeTicks(), client.posted_begin_impl_frame_deadline());
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Begin new frame.
+ EXPECT_SCOPED(AdvanceFrame());
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+
+ // Set scheduler to wait for ready to draw. Schedule won't post deadline in
+ // the mode.
+ scheduler_->SetWaitForReadyToDraw();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Try to run posted deadline.
+ // There is no posted deadline.
+ EXPECT_NO_ACTION(client_);
+
+ // Scheduler loses output surface, and stops waiting for ready to draw signal.
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
- public:
- SchedulerClientWithFixedEstimates(
- base::TimeDelta draw_duration,
- base::TimeDelta begin_main_frame_to_commit_duration,
- base::TimeDelta commit_to_activate_duration)
- : draw_duration_(draw_duration),
- begin_main_frame_to_commit_duration_(
- begin_main_frame_to_commit_duration),
- commit_to_activate_duration_(commit_to_activate_duration) {}
-
- base::TimeDelta DrawDurationEstimate() override { return draw_duration_; }
- base::TimeDelta BeginMainFrameToCommitDurationEstimate() override {
- return begin_main_frame_to_commit_duration_;
- }
- base::TimeDelta CommitToActivateDurationEstimate() override {
- return commit_to_activate_duration_;
- }
+void SchedulerTest::MainFrameInHighLatencyMode(
+ int64 begin_main_frame_to_commit_estimate_in_ms,
+ int64 commit_to_activate_estimate_in_ms,
+ bool impl_latency_takes_priority,
+ bool should_send_begin_main_frame) {
+ // Set up client with specified estimates (draw duration is set to 1).
+ SchedulerClientWithFixedEstimates* client =
+ new SchedulerClientWithFixedEstimates(
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(
+ begin_main_frame_to_commit_estimate_in_ms),
+ base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
- private:
- base::TimeDelta draw_duration_;
- base::TimeDelta begin_main_frame_to_commit_duration_;
- base::TimeDelta commit_to_activate_duration_;
-};
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
-void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
- int64 commit_to_activate_estimate_in_ms,
- bool impl_latency_takes_priority,
- bool should_send_begin_main_frame) {
- // Set up client with specified estimates (draw duration is set to 1).
- SchedulerClientWithFixedEstimates client(
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(
- begin_main_frame_to_commit_estimate_in_ms),
- base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- scheduler->SetImplLatencyTakesPriority(impl_latency_takes_priority);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ scheduler_->SetImplLatencyTakesPriority(impl_latency_takes_priority);
// Impl thread hits deadline before commit finishes.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
- client.AdvanceFrame();
- EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
-
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- client.AdvanceFrame();
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
+ scheduler_->SetNeedsCommit();
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ EXPECT_TRUE(client->HasAction("ScheduledActionSendBeginMainFrame"));
+
+ client->Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(scheduler_->MainThreadIsInHighLatencyMode(),
should_send_begin_main_frame);
- EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"),
+ EXPECT_EQ(client->HasAction("ScheduledActionSendBeginMainFrame"),
should_send_begin_main_frame);
}
-TEST(SchedulerTest,
- SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
+TEST_F(SchedulerTest,
+ SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
// Set up client so that estimates indicate that we can commit and activate
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(1, 1, false, false);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, false, false));
}
-TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
+TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
// Set up client so that estimates indicate that the commit cannot finish
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(10, 1, false, true);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(10, 1, false, true));
}
-TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
+TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
// Set up client so that estimates indicate that the activate cannot finish
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(1, 10, false, true);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 10, false, true));
}
-TEST(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
+TEST_F(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
// Set up client so that estimates indicate that we can commit and activate
// before the deadline (~8ms by default), but also enable impl latency takes
// priority mode.
- MainFrameInHighLatencyMode(1, 1, true, true);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, true, true));
}
-TEST(SchedulerTest, PollForCommitCompletion) {
+TEST_F(SchedulerTest, PollForCommitCompletion) {
// Since we are simulating a long commit, set up a client with draw duration
// estimates that prevent skipping main frames to get to low latency mode.
- SchedulerClientWithFixedEstimates client(
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(32),
- base::TimeDelta::FromMilliseconds(32));
- client.set_log_anticipated_draw_time_change(true);
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
- scheduler->SetCanDraw(true);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->DidCreateAndInitializeOutputSurface();
-
- scheduler->SetNeedsCommit();
- EXPECT_TRUE(scheduler->CommitPending());
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- scheduler->SetNeedsRedraw();
-
- BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
+ SchedulerClientWithFixedEstimates* client =
+ new SchedulerClientWithFixedEstimates(
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(32),
+ base::TimeDelta::FromMilliseconds(32));
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ client->set_log_anticipated_draw_time_change(true);
+
+ BeginFrameArgs frame_args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
-
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- scheduler->DidSwapBuffers();
- scheduler->DidSwapBuffersComplete();
// At this point, we've drawn a frame. Start another commit, but hold off on
// the NotifyReadyToCommit for now.
- EXPECT_FALSE(scheduler->CommitPending());
- scheduler->SetNeedsCommit();
- client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
- EXPECT_TRUE(scheduler->CommitPending());
+ EXPECT_FALSE(scheduler_->CommitPending());
+ scheduler_->SetNeedsCommit();
+ fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
+ EXPECT_TRUE(scheduler_->CommitPending());
// Draw and swap the frame, but don't ack the swap to simulate the Browser
// blocking on the renderer.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- scheduler->DidSwapBuffers();
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ scheduler_->DidSwapBuffers();
// Spin the event loop a few times and make sure we get more
// DidAnticipateDrawTimeChange calls every time.
- int actions_so_far = client.num_actions_();
+ int actions_so_far = client->num_actions_();
// Does three iterations to make sure that the timer is properly repeating.
for (int i = 0; i < 3; ++i) {
EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
- client.task_runner().DelayToNextTaskTime().InMicroseconds())
- << scheduler->AsValue()->ToString();
- client.task_runner().RunPendingTasks();
- EXPECT_GT(client.num_actions_(), actions_so_far);
- EXPECT_STREQ(client.Action(client.num_actions_() - 1),
+ task_runner().DelayToNextTaskTime().InMicroseconds())
+ << scheduler_->AsValue()->ToString();
+ task_runner().RunPendingTasks();
+ EXPECT_GT(client->num_actions_(), actions_so_far);
+ EXPECT_STREQ(client->Action(client->num_actions_() - 1),
"DidAnticipatedDrawTimeChange");
- actions_so_far = client.num_actions_();
+ actions_so_far = client->num_actions_();
}
// Do the same thing after BeginMainFrame starts but still before activation.
- scheduler->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyBeginMainFrameStarted();
for (int i = 0; i < 3; ++i) {
EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
- client.task_runner().DelayToNextTaskTime().InMicroseconds())
- << scheduler->AsValue()->ToString();
- client.task_runner().RunPendingTasks();
- EXPECT_GT(client.num_actions_(), actions_so_far);
- EXPECT_STREQ(client.Action(client.num_actions_() - 1),
+ task_runner().DelayToNextTaskTime().InMicroseconds())
+ << scheduler_->AsValue()->ToString();
+ task_runner().RunPendingTasks();
+ EXPECT_GT(client->num_actions_(), actions_so_far);
+ EXPECT_STREQ(client->Action(client->num_actions_() - 1),
"DidAnticipatedDrawTimeChange");
- actions_so_far = client.num_actions_();
+ actions_so_far = client->num_actions_();
}
}
-TEST(SchedulerTest, BeginRetroFrame) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, BeginRetroFrame) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame should prepare the draw.
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame deadline should draw.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
-
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ client_->Reset();
}
-TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, BeginRetroFrame_SwapThrottled) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1));
// To test swap ack throttling, this test disables automatic swap acks.
- scheduler->SetMaxSwapsPending(1);
- client.SetAutomaticSwapAck(false);
+ scheduler_->SetMaxSwapsPending(1);
+ client_->SetAutomaticSwapAck(false);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
- client.Reset();
-
- // Create a BeginFrame with a long deadline to avoid race conditions.
- // This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
- args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ client_->Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Queue BeginFrame while we are still handling the previous BeginFrame.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_NO_ACTION(client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ SendNextBeginFrame();
+ EXPECT_NO_ACTION(client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// NotifyReadyToCommit should trigger the pending commit and draw.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Swapping will put us into a swap throttled state.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ // Run posted deadline.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// While swap throttled, BeginRetroFrames should trigger BeginImplFrames
// but not a BeginMainFrame or draw.
- scheduler->SetNeedsCommit();
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
-
- // Queue BeginFrame while we are still handling the previous BeginFrame.
- args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_NO_ACTION(client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ scheduler_->SetNeedsRedraw();
+ // Run posted BeginRetroFrame.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(false));
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+
+ // Let time pass sufficiently beyond the regular deadline but not beyond the
+ // late deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+ base::TimeDelta::FromMicroseconds(1));
+ task_runner().RunUntilTime(now_src()->Now());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
// Take us out of a swap throttled state.
- scheduler->DidSwapBuffersComplete();
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
-
- // BeginImplFrame deadline should draw.
- scheduler->SetNeedsRedraw();
+ scheduler_->DidSwapBuffersComplete();
+ EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+
+ // Verify that the deadline was rescheduled.
+ task_runner().RunUntilTime(now_src()->Now());
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+}
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
+TEST_F(SchedulerTest, RetroFrameDoesNotExpireTooEarly) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+
+ client_->Reset();
+ SendNextBeginFrame();
+ // This BeginFrame is queued up as a retro frame.
+ EXPECT_NO_ACTION(client_);
+ // The previous deadline is still pending.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ // This commit should schedule the (previous) deadline to trigger immediately.
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ // The deadline task should trigger causing a draw.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+
+ // Keep animating.
+ client_->Reset();
+ scheduler_->SetNeedsAnimate();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client_);
+
+ // Let's advance sufficiently past the next frame's deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+ BeginFrameArgs::DefaultEstimatedParentDrawTime() +
+ base::TimeDelta::FromMicroseconds(1));
+
+ // The retro frame hasn't expired yet.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(false));
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // This is an immediate deadline case.
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+}
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+TEST_F(SchedulerTest, RetroFrameDoesNotExpireTooLate) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+
+ client_->Reset();
+ SendNextBeginFrame();
+ // This BeginFrame is queued up as a retro frame.
+ EXPECT_NO_ACTION(client_);
+ // The previous deadline is still pending.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ // This commit should schedule the (previous) deadline to trigger immediately.
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ // The deadline task should trigger causing a draw.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+
+ // Keep animating.
+ client_->Reset();
+ scheduler_->SetNeedsAnimate();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client_);
+
+ // Let's advance sufficiently past the next frame's deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() +
+ base::TimeDelta::FromMicroseconds(1));
+
+ // The retro frame should've expired.
+ EXPECT_NO_ACTION(client_);
}
-void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled,
- bool throttle_frame_production) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled =
- begin_frame_scheduling_enabled;
- scheduler_settings.throttle_frame_production = throttle_frame_production;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+void SchedulerTest::BeginFramesNotFromClient(
+ bool use_external_begin_frame_source,
+ bool throttle_frame_production) {
+ scheduler_settings_.use_external_begin_frame_source =
+ use_external_begin_frame_source;
+ scheduler_settings_.throttle_frame_production = throttle_frame_production;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame
// without calling SetNeedsBeginFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_FALSE(client.needs_begin_frames());
- EXPECT_NO_ACTION(client);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
// When the client-driven BeginFrame are disabled, the scheduler posts it's
// own BeginFrame tasks.
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
// BeginImplFrame should prepare the draw.
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// BeginImplFrame deadline should draw.
- client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// Make sure SetNeedsBeginFrame isn't called on the client
// when the BeginFrame is no longer needed.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("SendBeginMainFrameNotExpectedSoon", client_);
+ client_->Reset();
}
-TEST(SchedulerTest, SyntheticBeginFrames) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest, SyntheticBeginFrames) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = true;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, VSyncThrottlingDisabled) {
- bool begin_frame_scheduling_enabled = true;
+TEST_F(SchedulerTest, VSyncThrottlingDisabled) {
+ bool use_external_begin_frame_source = true;
bool throttle_frame_production = false;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = false;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
-void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled,
- bool throttle_frame_production) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled =
- begin_frame_scheduling_enabled;
- scheduler_settings.throttle_frame_production = throttle_frame_production;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+void SchedulerTest::BeginFramesNotFromClient_SwapThrottled(
+ bool use_external_begin_frame_source,
+ bool throttle_frame_production) {
+ scheduler_settings_.use_external_begin_frame_source =
+ use_external_begin_frame_source;
+ scheduler_settings_.throttle_frame_production = throttle_frame_production;
+ SetUpScheduler(true);
+
+ scheduler_->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1));
// To test swap ack throttling, this test disables automatic swap acks.
- scheduler->SetMaxSwapsPending(1);
- client.SetAutomaticSwapAck(false);
+ scheduler_->SetMaxSwapsPending(1);
+ client_->SetAutomaticSwapAck(false);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_FALSE(client.needs_begin_frames());
- EXPECT_NO_ACTION(client);
- client.Reset();
+ client_->Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
// Trigger the first BeginImplFrame and BeginMainFrame
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// NotifyReadyToCommit should trigger the pending commit and draw.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
// Swapping will put us into a swap throttled state.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ // Run posted deadline.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// While swap throttled, BeginFrames should trigger BeginImplFrames,
// but not a BeginMainFrame or draw.
- scheduler->SetNeedsCommit();
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SCOPED(AdvanceFrame()); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Let time pass sufficiently beyond the regular deadline but not beyond the
+ // late deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+ base::TimeDelta::FromMicroseconds(1));
+ task_runner().RunUntilTime(now_src()->Now());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
// Take us out of a swap throttled state.
- scheduler->DidSwapBuffersComplete();
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
-
- // BeginImplFrame deadline should draw.
- scheduler->SetNeedsRedraw();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->DidSwapBuffersComplete();
+ EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Verify that the deadline was rescheduled.
+ // We can't use RunUntilTime(now) here because the next frame is also
+ // scheduled if throttle_frame_production = false.
+ base::TimeTicks before_deadline = now_src()->Now();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ base::TimeTicks after_deadline = now_src()->Now();
+ EXPECT_EQ(after_deadline, before_deadline);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
}
-TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = true;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
- bool begin_frame_scheduling_enabled = true;
+TEST_F(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
+ bool use_external_begin_frame_source = true;
bool throttle_frame_production = false;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest,
- SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest,
+ SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = false;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- client.Reset();
- scheduler->DidCreateAndInitializeOutputSurface();
- EXPECT_NO_ACTION(client);
-
- scheduler->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-}
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(false);
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+ scheduler_->SetCanStart();
+ scheduler_->SetVisible(true);
+ scheduler_->SetCanDraw(true);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- // SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ client_->Reset();
+ scheduler_->DidCreateAndInitializeOutputSurface();
+ EXPECT_NO_ACTION(client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
- // Do nothing when impl frame is in deadine pending state.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+}
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 1);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ // SetNeedsCommit should begin the frame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 1);
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
+void SchedulerTest::DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
bool impl_side_painting) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = impl_side_painting;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ scheduler_settings_.impl_side_painting = impl_side_painting;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- client.Reset();
- scheduler->DidLoseOutputSurface();
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
// Do nothing when impl frame is in deadine pending state.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ EXPECT_NO_ACTION(client_);
- client.Reset();
+ client_->Reset();
// Run posted deadline.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
- // OnBeginImplFrameDeadline didn't schedule any actions because main frame is
- // not yet completed.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ // OnBeginImplFrameDeadline didn't schedule output surface creation because
+ // main frame is not yet completed.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
// BeginImplFrame is not started.
- client.task_runner().RunUntilTime(client.now_src()->Now() +
- base::TimeDelta::FromMilliseconds(10));
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
+ client_->Reset();
+ task_runner().RunUntilTime(now_src()->Now() +
+ base::TimeDelta::FromMilliseconds(10));
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
if (impl_side_painting) {
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 3);
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 3);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 2, 3);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 2, 3);
} else {
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 1, 2);
}
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
+TEST_F(SchedulerTest,
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
bool impl_side_painting = false;
DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
}
-TEST(SchedulerTest,
- DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
+TEST_F(SchedulerTest,
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
bool impl_side_painting = true;
DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
}
-void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = impl_side_painting;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+void SchedulerTest::DidLoseOutputSurfaceAfterReadyToCommit(
+ bool impl_side_painting) {
+ scheduler_settings_.impl_side_painting = impl_side_painting;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
if (impl_side_painting) {
// Sync tree should be forced to activate.
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client, 0, 2);
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 2);
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
} else {
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ EXPECT_NO_ACTION(client_);
}
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
DidLoseOutputSurfaceAfterReadyToCommit(false);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
DidLoseOutputSurfaceAfterReadyToCommit(true);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- client.Reset();
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionManageTiles", client, 0, 2);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsPrepareTiles) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 1, 4);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 2, 4);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- client.Reset();
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ client_->Reset();
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// NotifyReadyToCommit should trigger the commit.
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.Reset();
- EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
- scheduler->DidLoseOutputSurface();
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client, 0, 2);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
- EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_FALSE(scheduler_->IsBeginRetroFrameArgsEmpty());
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_TRUE(scheduler_->IsBeginRetroFrameArgsEmpty());
// Posted BeginRetroFrame is aborted.
- client.Reset();
- client.task_runner().RunPendingTasks();
- EXPECT_NO_ACTION(client);
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client_);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- client.Reset();
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ client_->Reset();
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// NotifyReadyToCommit should trigger the commit.
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
// BeginImplFrame should prepare the draw.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.Reset();
- EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
- scheduler->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_FALSE(scheduler_->IsBeginRetroFrameArgsEmpty());
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_NO_ACTION(client_);
+ EXPECT_TRUE(scheduler_->IsBeginRetroFrameArgsEmpty());
// BeginImplFrame deadline should abort drawing.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client_->needs_begin_frames());
// No more BeginRetroFrame because BeginRetroFrame queue is cleared.
- client.Reset();
- client.task_runner().RunPendingTasks();
- EXPECT_NO_ACTION(client);
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client_);
}
-TEST(SchedulerTest,
- StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled = false;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- EXPECT_FALSE(scheduler->frame_source().NeedsBeginFrames());
- scheduler->SetNeedsCommit();
- EXPECT_TRUE(scheduler->frame_source().NeedsBeginFrames());
+ EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames());
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted Tick.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(scheduler->frame_source().NeedsBeginFrames());
+ client_->Reset();
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
// NotifyReadyToCommit should trigger the commit.
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(scheduler->frame_source().NeedsBeginFrames());
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->frame_source().NeedsBeginFrames());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- EXPECT_FALSE(scheduler->frame_source().NeedsBeginFrames());
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames());
}
-TEST(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = true;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceWhenIdle) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ // SetNeedsCommit should begin the frame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+
+ // Idle time between BeginFrames.
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+}
+
+TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
+ scheduler_settings_.impl_side_painting = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->SetVisible(false);
+ task_runner().RunPendingTasks(); // Run posted deadline.
- client.Reset();
- scheduler->SetVisible(false);
// Sync tree should be forced to activate.
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client, 0, 2);
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 2);
+ EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-TEST(SchedulerTest, SchedulerPowerMonitoring) {
- FakeSchedulerClient client;
- SchedulerSettings settings;
- settings.disable_hi_res_timer_tasks_on_battery = true;
- TestScheduler* scheduler = client.CreateScheduler(settings);
-
- base::TimeTicks before_deadline, after_deadline;
+// Tests to ensure frame sources can be successfully changed while drawing.
+TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ scheduler_->SetNeedsRedraw();
+
+ // Switch to an unthrottled frame source.
+ scheduler_->SetThrottleFrameProduction(false);
+ client_->Reset();
+
+ // Unthrottled frame source will immediately begin a new frame.
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+ // If we don't swap on the deadline, we wait for the next BeginFrame.
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+// Tests to ensure frame sources can be successfully changed while a frame
+// deadline is pending.
+TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+
+ // Switch to an unthrottled frame source before the frame deadline is hit.
+ scheduler_->SetThrottleFrameProduction(false);
+ client_->Reset();
+
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline and BeginFrame.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 2);
+ // Unthrottled frame source will immediately begin a new frame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2);
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
+// Tests to ensure that the active frame source can successfully be changed from
+// unthrottled to throttled.
+TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
+ scheduler_settings_.throttle_frame_production = false;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Switch to a throttled frame source.
+ scheduler_->SetThrottleFrameProduction(true);
+ client_->Reset();
+
+ // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsRedraw();
+ task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+}
- // On non-battery power
- EXPECT_FALSE(client.PowerMonitor()->IsOnBatteryPower());
+// Tests to ensure that we send a BeginMainFrameNotExpectedSoon when expected.
+TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- client.AdvanceFrame();
- client.Reset();
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Trigger a frame draw.
+ EXPECT_SCOPED(AdvanceFrame());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ task_runner().RunPendingTasks();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 5);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 5);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 2, 5);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 3, 5);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 5);
+ client_->Reset();
- before_deadline = client.now_src()->Now();
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
- after_deadline = client.now_src()->Now();
+ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
+ // and send a SendBeginMainFrameNotExpectedSoon.
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ client_->Reset();
+}
- // We post a non-zero deadline task when not on battery
- EXPECT_LT(before_deadline, after_deadline);
+TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsAnimate();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Continue with animation.
+ scheduler_->SetNeedsAnimate();
+ EXPECT_NO_ACTION(client_);
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Idle on next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- // Switch to battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(true);
- EXPECT_TRUE(client.PowerMonitor()->IsOnBatteryPower());
+TEST_F(SchedulerTest, SynchronousCompositorOnDrawDuringIdle) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Idle on next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
+TEST_F(SchedulerTest, SynchronousCompositorCommit) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_NO_ACTION(client_);
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
+
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Idle on next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- before_deadline = client.now_src()->Now();
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
- after_deadline = client.now_src()->Now();
+TEST_F(SchedulerTest, SynchronousCompositorDoubleCommitWithoutDraw) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_NO_ACTION(client_);
+
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
+
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+ client_->Reset();
+
+ // Ask for another commit.
+ scheduler_->SetNeedsCommit();
+
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 4);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 4);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 3, 4);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_NO_ACTION(client_);
+
+ // Allow new commit even though previous commit hasn't been drawn.
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
+}
- // We post a zero deadline task when on battery
- EXPECT_EQ(before_deadline, after_deadline);
+class SchedulerClientSetNeedsPrepareTilesOnDraw : public FakeSchedulerClient {
+ public:
+ SchedulerClientSetNeedsPrepareTilesOnDraw() : FakeSchedulerClient() {}
- // Switch to non-battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(false);
- EXPECT_FALSE(client.PowerMonitor()->IsOnBatteryPower());
+ protected:
+ DrawResult ScheduledActionDrawAndSwapIfPossible() override {
+ scheduler_->SetNeedsPrepareTiles();
+ return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
+ }
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
+ void ScheduledActionPrepareTiles() override {
+ FakeSchedulerClient::ScheduledActionPrepareTiles();
+ scheduler_->DidPrepareTiles();
+ }
+};
- // Same as before
- before_deadline = client.now_src()->Now();
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
- after_deadline = client.now_src()->Now();
+TEST_F(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+
+ scoped_ptr<FakeSchedulerClient> client =
+ make_scoped_ptr(new SchedulerClientSetNeedsPrepareTilesOnDraw);
+ SetUpScheduler(client.Pass(), true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ client_->Reset();
+
+ // Next vsync.
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(client_->needs_begin_frames());
+ client_->Reset();
}
-TEST(SchedulerTest,
- SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOff) {
- FakeSchedulerClient client;
- SchedulerSettings settings;
- TestScheduler* scheduler = client.CreateScheduler(settings);
-
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // Set needs commit so that the scheduler tries to wait for the main thread
- scheduler->SetNeedsCommit();
- // Set needs redraw so that the scheduler doesn't wait too long
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Switch to battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(true);
- EXPECT_TRUE(client.PowerMonitor()->IsOnBatteryPower());
-
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Disable auto-advancing of now_src
- client.task_runner().SetAutoAdvanceNowToPendingTasks(false);
-
- // Deadline task is pending
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks();
- // Deadline task is still pending
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- // Advance now by 15 ms - same as windows low res timer
- client.now_src()->AdvanceNowMicroseconds(15000);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks();
- // Deadline task finally completes
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-}
+TEST_F(SchedulerTest, AuthoritativeVSyncInterval) {
+ SetUpScheduler(true);
+
+ base::TimeDelta initial_interval =
+ scheduler_->begin_impl_frame_args().interval;
+ base::TimeDelta authoritative_interval =
+ base::TimeDelta::FromMilliseconds(33);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_SCOPED(AdvanceFrame());
+
+ EXPECT_EQ(initial_interval, scheduler_->begin_impl_frame_args().interval);
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+
+ scheduler_->SetAuthoritativeVSyncInterval(authoritative_interval);
+
+ EXPECT_SCOPED(AdvanceFrame());
-TEST(SchedulerTest,
- SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOn) {
- FakeSchedulerClient client;
- SchedulerSettings settings;
- settings.disable_hi_res_timer_tasks_on_battery = true;
- TestScheduler* scheduler = client.CreateScheduler(settings);
-
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // Set needs commit so that the scheduler tries to wait for the main thread
- scheduler->SetNeedsCommit();
- // Set needs redraw so that the scheduler doesn't wait too long
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Switch to battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(true);
- EXPECT_TRUE(client.PowerMonitor()->IsOnBatteryPower());
-
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Disable auto-advancing of now_src
- client.task_runner().SetAutoAdvanceNowToPendingTasks(false);
-
- // Deadline task is pending
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks();
- // Deadline task runs immediately
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ // At the next BeginFrame, authoritative interval is used instead of previous
+ // interval.
+ EXPECT_NE(initial_interval, scheduler_->begin_impl_frame_args().interval);
+ EXPECT_EQ(authoritative_interval,
+ scheduler_->begin_impl_frame_args().interval);
}
} // namespace
diff --git a/chromium/cc/scheduler/video_frame_controller.h b/chromium/cc/scheduler/video_frame_controller.h
new file mode 100644
index 00000000000..0307cd5e402
--- /dev/null
+++ b/chromium/cc/scheduler/video_frame_controller.h
@@ -0,0 +1,40 @@
+// Copyright 2013 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.
+
+#ifndef CC_SCHEDULER_VIDEO_FRAME_CONTROLLER_H_
+#define CC_SCHEDULER_VIDEO_FRAME_CONTROLLER_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/output/begin_frame_args.h"
+
+namespace cc {
+
+class VideoFrameController;
+
+class CC_EXPORT VideoFrameControllerClient {
+ public:
+ virtual void AddVideoFrameController(VideoFrameController* controller) = 0;
+ virtual void RemoveVideoFrameController(VideoFrameController* controller) = 0;
+
+ protected:
+ virtual ~VideoFrameControllerClient() {}
+};
+
+// TODO(sunnyps): Consider making this a BeginFrameObserver some day.
+class CC_EXPORT VideoFrameController {
+ public:
+ virtual void OnBeginFrame(const BeginFrameArgs& args) = 0;
+
+ // Called upon completion of LayerTreeHostImpl::DidDrawAllLayers(), regardless
+ // of whether the controller issued a SetNeedsRedraw(). May be used to
+ // determine when SetNeedsRedraw() is called but the draw is aborted.
+ virtual void DidDrawFrame() = 0;
+
+ protected:
+ virtual ~VideoFrameController() {}
+};
+
+} // namespace cc
+
+#endif // CC_SCHEDULER_VIDEO_FRAME_CONTROLLER_H_