summaryrefslogtreecommitdiffstats
path: root/cc/scheduler
diff options
context:
space:
mode:
Diffstat (limited to 'cc/scheduler')
-rw-r--r--cc/scheduler/frame_rate_controller.cc26
-rw-r--r--cc/scheduler/frame_rate_controller.h21
-rw-r--r--cc/scheduler/frame_rate_controller_unittest.cc6
-rw-r--r--cc/scheduler/scheduler.cc125
-rw-r--r--cc/scheduler/scheduler.h32
-rw-r--r--cc/scheduler/scheduler_settings.cc3
-rw-r--r--cc/scheduler/scheduler_settings.h1
-rw-r--r--cc/scheduler/scheduler_state_machine.cc15
-rw-r--r--cc/scheduler/scheduler_state_machine.h6
-rw-r--r--cc/scheduler/scheduler_state_machine_unittest.cc2
-rw-r--r--cc/scheduler/scheduler_unittest.cc283
-rw-r--r--cc/scheduler/vsync_time_source.cc76
-rw-r--r--cc/scheduler/vsync_time_source.h78
-rw-r--r--cc/scheduler/vsync_time_source_unittest.cc124
14 files changed, 546 insertions, 252 deletions
diff --git a/cc/scheduler/frame_rate_controller.cc b/cc/scheduler/frame_rate_controller.cc
index 90cf0d7..b4f1272 100644
--- a/cc/scheduler/frame_rate_controller.cc
+++ b/cc/scheduler/frame_rate_controller.cc
@@ -21,9 +21,7 @@ class FrameRateControllerTimeSourceAdapter : public TimeSourceClient {
}
virtual ~FrameRateControllerTimeSourceAdapter() {}
- virtual void OnTimerTick() OVERRIDE {
- frame_rate_controller_->OnTimerTick();
- }
+ virtual void OnTimerTick() OVERRIDE { frame_rate_controller_->OnTimerTick(); }
private:
explicit FrameRateControllerTimeSourceAdapter(
@@ -36,7 +34,7 @@ class FrameRateControllerTimeSourceAdapter : public TimeSourceClient {
FrameRateController::FrameRateController(scoped_refptr<TimeSource> timer)
: client_(NULL),
num_frames_pending_(0),
- max_swaps_pending_(0),
+ max_frames_pending_(0),
time_source_(timer),
active_(false),
is_time_source_throttling_(true),
@@ -50,7 +48,7 @@ FrameRateController::FrameRateController(scoped_refptr<TimeSource> timer)
FrameRateController::FrameRateController(Thread* thread)
: client_(NULL),
num_frames_pending_(0),
- max_swaps_pending_(0),
+ max_frames_pending_(0),
active_(false),
is_time_source_throttling_(false),
weak_factory_(this),
@@ -77,9 +75,9 @@ void FrameRateController::SetActive(bool active) {
}
}
-void FrameRateController::SetMaxSwapsPending(int max_swaps_pending) {
- DCHECK_GE(max_swaps_pending, 0);
- max_swaps_pending_ = max_swaps_pending;
+void FrameRateController::SetMaxFramesPending(int max_frames_pending) {
+ DCHECK_GE(max_frames_pending, 0);
+ max_frames_pending_ = max_frames_pending;
}
void FrameRateController::SetTimebaseAndInterval(base::TimeTicks timebase,
@@ -89,17 +87,15 @@ void FrameRateController::SetTimebaseAndInterval(base::TimeTicks timebase,
}
void FrameRateController::OnTimerTick() {
- TRACE_EVENT0("cc", "FrameRateController::OnTimerTick");
DCHECK(active_);
// Check if we have too many frames in flight.
bool throttled =
- max_swaps_pending_ && num_frames_pending_ >= max_swaps_pending_;
+ max_frames_pending_ && num_frames_pending_ >= max_frames_pending_;
TRACE_COUNTER_ID1("cc", "ThrottledCompositor", thread_, throttled);
- if (client_) {
- client_->FrameRateControllerTick(throttled);
- }
+ if (client_)
+ client_->BeginFrame(throttled);
if (!is_time_source_throttling_ && !throttled)
PostManualTick();
@@ -112,9 +108,7 @@ void FrameRateController::PostManualTick() {
}
}
-void FrameRateController::ManualTick() {
- OnTimerTick();
-}
+void FrameRateController::ManualTick() { OnTimerTick(); }
void FrameRateController::DidSwapBuffers() {
num_frames_pending_++;
diff --git a/cc/scheduler/frame_rate_controller.h b/cc/scheduler/frame_rate_controller.h
index 70964e2..070c26a 100644
--- a/cc/scheduler/frame_rate_controller.h
+++ b/cc/scheduler/frame_rate_controller.h
@@ -15,21 +15,18 @@ namespace cc {
class Thread;
class TimeSource;
-class FrameRateController;
class CC_EXPORT FrameRateControllerClient {
- protected:
- virtual ~FrameRateControllerClient() {}
-
public:
// Throttled is true when we have a maximum number of frames pending.
- virtual void FrameRateControllerTick(bool throttled) = 0;
+ virtual void BeginFrame(bool throttled) = 0;
+
+ protected:
+ virtual ~FrameRateControllerClient() {}
};
class FrameRateControllerTimeSourceAdapter;
-// The FrameRateController is used in cases where we self-tick (i.e. BeginFrame
-// is not sent by a parent compositor.
class CC_EXPORT FrameRateController {
public:
enum {
@@ -44,7 +41,6 @@ class CC_EXPORT FrameRateController {
void SetClient(FrameRateControllerClient* client) { client_ = client; }
void SetActive(bool active);
- bool IsActive() { return active_; }
// Use the following methods to adjust target frame rate.
//
@@ -55,9 +51,9 @@ class CC_EXPORT FrameRateController {
void DidSwapBuffers();
void DidSwapBuffersComplete();
void DidAbortAllPendingFrames();
- void SetMaxSwapsPending(int max_swaps_pending); // 0 for unlimited.
- int MaxSwapsPending() const { return max_swaps_pending_; }
- int NumSwapsPendingForTesting() const { return num_frames_pending_; }
+ void SetMaxFramesPending(int max_frames_pending); // 0 for unlimited.
+ int MaxFramesPending() const { return max_frames_pending_; }
+ int NumFramesPendingForTesting() const { return num_frames_pending_; }
// This returns null for unthrottled frame-rate.
base::TimeTicks NextTickTime();
@@ -77,7 +73,7 @@ class CC_EXPORT FrameRateController {
FrameRateControllerClient* client_;
int num_frames_pending_;
- int max_swaps_pending_;
+ int max_frames_pending_;
scoped_refptr<TimeSource> time_source_;
scoped_ptr<FrameRateControllerTimeSourceAdapter> time_source_client_adapter_;
bool active_;
@@ -87,7 +83,6 @@ class CC_EXPORT FrameRateController {
base::WeakPtrFactory<FrameRateController> weak_factory_;
Thread* thread_;
- private:
DISALLOW_COPY_AND_ASSIGN(FrameRateController);
};
diff --git a/cc/scheduler/frame_rate_controller_unittest.cc b/cc/scheduler/frame_rate_controller_unittest.cc
index 3fcf4a7..183f576 100644
--- a/cc/scheduler/frame_rate_controller_unittest.cc
+++ b/cc/scheduler/frame_rate_controller_unittest.cc
@@ -17,7 +17,7 @@ class FakeFrameRateControllerClient : public cc::FrameRateControllerClient {
void Reset() { began_frame_ = false; }
bool BeganFrame() const { return began_frame_; }
- virtual void FrameRateControllerTick(bool throttled) OVERRIDE {
+ virtual void BeginFrame(bool throttled) OVERRIDE {
began_frame_ = !throttled;
}
@@ -74,7 +74,7 @@ TEST(FrameRateControllerTest, TestFrameThrottling_TwoFramesInFlight) {
controller.SetClient(&client);
controller.SetActive(true);
- controller.SetMaxSwapsPending(2);
+ controller.SetMaxFramesPending(2);
base::TimeTicks elapsed; // Muck around with time a bit
@@ -132,7 +132,7 @@ TEST(FrameRateControllerTest, TestFrameThrottling_Unthrottled) {
FrameRateController controller(&thread);
controller.SetClient(&client);
- controller.SetMaxSwapsPending(2);
+ controller.SetMaxFramesPending(2);
// SetActive triggers 1st frame, make sure the BeginFrame callback
// is called
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 7110bff..d308b0d 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -7,29 +7,23 @@
#include "base/auto_reset.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
-#include "cc/base/thread.h"
namespace cc {
Scheduler::Scheduler(SchedulerClient* client,
+ scoped_ptr<FrameRateController> frame_rate_controller,
const SchedulerSettings& scheduler_settings)
: settings_(scheduler_settings),
client_(client),
- weak_factory_(this),
- last_set_needs_begin_frame_(false),
- has_pending_begin_frame_(false),
- last_begin_frame_time_(base::TimeTicks()),
- // TODO(brianderson): Pass with BeginFrame in the near future.
- interval_(base::TimeDelta::FromMicroseconds(16666)),
+ frame_rate_controller_(frame_rate_controller.Pass()),
state_machine_(scheduler_settings),
inside_process_scheduled_actions_(false) {
DCHECK(client_);
+ frame_rate_controller_->SetClient(this);
DCHECK(!state_machine_.BeginFrameNeededByImplThread());
}
-Scheduler::~Scheduler() {
- client_->SetNeedsBeginFrameOnImplThread(false);
-}
+Scheduler::~Scheduler() { frame_rate_controller_->SetActive(false); }
void Scheduler::SetCanStart() {
state_machine_.SetCanStart();
@@ -94,6 +88,23 @@ void Scheduler::BeginFrameAbortedByMainThread() {
ProcessScheduledActions();
}
+void Scheduler::SetMaxFramesPending(int max_frames_pending) {
+ frame_rate_controller_->SetMaxFramesPending(max_frames_pending);
+}
+
+int Scheduler::MaxFramesPending() const {
+ return frame_rate_controller_->MaxFramesPending();
+}
+
+int Scheduler::NumFramesPendingForTesting() const {
+ return frame_rate_controller_->NumFramesPendingForTesting();
+}
+
+void Scheduler::DidSwapBuffersComplete() {
+ TRACE_EVENT0("cc", "Scheduler::DidSwapBuffersComplete");
+ frame_rate_controller_->DidSwapBuffersComplete();
+}
+
void Scheduler::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
state_machine_.DidLoseOutputSurface();
@@ -102,69 +113,31 @@ void Scheduler::DidLoseOutputSurface() {
void Scheduler::DidCreateAndInitializeOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
+ frame_rate_controller_->DidAbortAllPendingFrames();
state_machine_.DidCreateAndInitializeOutputSurface();
- has_pending_begin_frame_ = false;
- last_set_needs_begin_frame_ = false;
ProcessScheduledActions();
}
+void Scheduler::SetTimebaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
+}
+
base::TimeTicks Scheduler::AnticipatedDrawTime() {
- TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime");
- base::TimeTicks now = base::TimeTicks::Now();
- int64 intervals = ((now - last_begin_frame_time_) / interval_) + 1;
- return last_begin_frame_time_ + (interval_ * intervals);
+ return frame_rate_controller_->NextTickTime();
}
base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() {
- return last_begin_frame_time_;
-}
-
-void Scheduler::SetupNextBeginFrameIfNeeded() {
- // Determine if we need BeginFrame notifications.
- // If we do, always request the BeginFrame immediately.
- // If not, only disable on the next BeginFrame to avoid unnecessary toggles.
- // The synchronous renderer compositor requires immediate disables though.
- bool needs_begin_frame = state_machine_.BeginFrameNeededByImplThread();
- if ((needs_begin_frame ||
- state_machine_.inside_begin_frame() ||
- settings_.using_synchronous_renderer_compositor) &&
- (needs_begin_frame != last_set_needs_begin_frame_)) {
- client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame);
- last_set_needs_begin_frame_ = needs_begin_frame;
- }
-
- // Request another BeginFrame if we haven't drawn for now until we have
- // deadlines implemented.
- if (state_machine_.inside_begin_frame() && has_pending_begin_frame_) {
- has_pending_begin_frame_ = false;
- client_->SetNeedsBeginFrameOnImplThread(true);
- }
+ return frame_rate_controller_->LastTickTime();
}
-void Scheduler::BeginFrame(base::TimeTicks frame_time) {
- TRACE_EVENT0("cc", "Scheduler::BeginFrame");
- DCHECK(!has_pending_begin_frame_);
- has_pending_begin_frame_ = true;
- last_begin_frame_time_ = frame_time;
- state_machine_.DidEnterBeginFrame();
- state_machine_.SetFrameTime(frame_time);
+void Scheduler::BeginFrame(bool throttled) {
+ TRACE_EVENT1("cc", "Scheduler::BeginFrame", "throttled", throttled);
+ if (!throttled)
+ state_machine_.DidEnterBeginFrame();
ProcessScheduledActions();
- state_machine_.DidLeaveBeginFrame();
-}
-
-void Scheduler::DrawAndSwapIfPossible() {
- ScheduledActionDrawAndSwapResult result =
- client_->ScheduledActionDrawAndSwapIfPossible();
- state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
- if (result.did_swap)
- has_pending_begin_frame_ = false;
-}
-
-void Scheduler::DrawAndSwapForced() {
- ScheduledActionDrawAndSwapResult result =
- client_->ScheduledActionDrawAndSwapForced();
- if (result.did_swap)
- has_pending_begin_frame_ = false;
+ if (!throttled)
+ state_machine_.DidLeaveBeginFrame();
}
void Scheduler::ProcessScheduledActions() {
@@ -178,6 +151,9 @@ void Scheduler::ProcessScheduledActions() {
SchedulerStateMachine::Action action = state_machine_.NextAction();
while (action != SchedulerStateMachine::ACTION_NONE) {
state_machine_.UpdateState(action);
+ TRACE_EVENT1(
+ "cc", "Scheduler::ProcessScheduledActions()", "action", action);
+
switch (action) {
case SchedulerStateMachine::ACTION_NONE:
break;
@@ -193,12 +169,23 @@ void Scheduler::ProcessScheduledActions() {
case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:
client_->ScheduledActionActivatePendingTreeIfNeeded();
break;
- case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE:
- DrawAndSwapIfPossible();
+ case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE: {
+ frame_rate_controller_->DidSwapBuffers();
+ ScheduledActionDrawAndSwapResult result =
+ client_->ScheduledActionDrawAndSwapIfPossible();
+ state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
+ if (!result.did_swap)
+ frame_rate_controller_->DidSwapBuffersComplete();
break;
- case SchedulerStateMachine::ACTION_DRAW_FORCED:
- DrawAndSwapForced();
+ }
+ case SchedulerStateMachine::ACTION_DRAW_FORCED: {
+ frame_rate_controller_->DidSwapBuffers();
+ ScheduledActionDrawAndSwapResult result =
+ client_->ScheduledActionDrawAndSwapForced();
+ if (!result.did_swap)
+ frame_rate_controller_->DidSwapBuffersComplete();
break;
+ }
case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
client_->ScheduledActionBeginOutputSurfaceCreation();
break;
@@ -209,8 +196,10 @@ void Scheduler::ProcessScheduledActions() {
action = state_machine_.NextAction();
}
- SetupNextBeginFrameIfNeeded();
- client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
+ // Activate or deactivate the frame rate controller.
+ frame_rate_controller_->SetActive(
+ state_machine_.BeginFrameNeededByImplThread());
+ client_->DidAnticipatedDrawTimeChange(frame_rate_controller_->NextTickTime());
}
bool Scheduler::WillDrawIfNeeded() const {
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index d8151fa..6ecd889 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/time.h"
#include "cc/base/cc_export.h"
+#include "cc/scheduler/frame_rate_controller.h"
#include "cc/scheduler/scheduler_settings.h"
#include "cc/scheduler/scheduler_state_machine.h"
#include "cc/trees/layer_tree_host.h"
@@ -32,7 +33,6 @@ struct ScheduledActionDrawAndSwapResult {
class SchedulerClient {
public:
- virtual void SetNeedsBeginFrameOnImplThread(bool enable) = 0;
virtual void ScheduledActionSendBeginFrameToMainThread() = 0;
virtual ScheduledActionDrawAndSwapResult
ScheduledActionDrawAndSwapIfPossible() = 0;
@@ -49,12 +49,14 @@ class SchedulerClient {
virtual ~SchedulerClient() {}
};
-class CC_EXPORT Scheduler {
+class CC_EXPORT Scheduler : FrameRateControllerClient {
public:
static scoped_ptr<Scheduler> Create(
SchedulerClient* client,
+ scoped_ptr<FrameRateController> frame_rate_controller,
const SchedulerSettings& scheduler_settings) {
- return make_scoped_ptr(new Scheduler(client, scheduler_settings));
+ return make_scoped_ptr(new Scheduler(
+ client, frame_rate_controller.Pass(), scheduler_settings));
}
virtual ~Scheduler();
@@ -84,6 +86,12 @@ class CC_EXPORT Scheduler {
void FinishCommit();
void BeginFrameAbortedByMainThread();
+ void SetMaxFramesPending(int max);
+ int MaxFramesPending() const;
+ int NumFramesPendingForTesting() const;
+
+ void DidSwapBuffersComplete();
+
void DidLoseOutputSurface();
void DidCreateAndInitializeOutputSurface();
bool HasInitializedOutputSurface() const {
@@ -95,32 +103,28 @@ class CC_EXPORT Scheduler {
bool WillDrawIfNeeded() const;
+ void SetTimebaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval);
+
base::TimeTicks AnticipatedDrawTime();
base::TimeTicks LastBeginFrameOnImplThreadTime();
- void BeginFrame(base::TimeTicks frame_time);
+ // FrameRateControllerClient implementation
+ virtual void BeginFrame(bool throttled) OVERRIDE;
std::string StateAsStringForTesting() { return state_machine_.ToString(); }
private:
Scheduler(SchedulerClient* client,
+ scoped_ptr<FrameRateController> frame_rate_controller,
const SchedulerSettings& scheduler_settings);
- void SetupNextBeginFrameIfNeeded();
- void DrawAndSwapIfPossible();
- void DrawAndSwapForced();
void ProcessScheduledActions();
const SchedulerSettings settings_;
SchedulerClient* client_;
-
- base::WeakPtrFactory<Scheduler> weak_factory_;
- bool last_set_needs_begin_frame_;
- bool has_pending_begin_frame_;
- base::TimeTicks last_begin_frame_time_;
- base::TimeDelta interval_;
-
+ scoped_ptr<FrameRateController> frame_rate_controller_;
SchedulerStateMachine state_machine_;
bool inside_process_scheduled_actions_;
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index 4850a108..29c525b 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -8,8 +8,7 @@ namespace cc {
SchedulerSettings::SchedulerSettings()
: impl_side_painting(false),
- timeout_and_draw_when_animation_checkerboards(true),
- using_synchronous_renderer_compositor(false) {}
+ timeout_and_draw_when_animation_checkerboards(true) {}
SchedulerSettings::~SchedulerSettings() {}
diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h
index c06e28f..ebcfc6a 100644
--- a/cc/scheduler/scheduler_settings.h
+++ b/cc/scheduler/scheduler_settings.h
@@ -16,7 +16,6 @@ class CC_EXPORT SchedulerSettings {
bool impl_side_painting;
bool timeout_and_draw_when_animation_checkerboards;
- bool using_synchronous_renderer_compositor;
};
} // namespace cc
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index fda6e6b..76f7bb1 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -4,7 +4,6 @@
#include "cc/scheduler/scheduler_state_machine.h"
-#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
@@ -13,7 +12,6 @@ namespace cc {
SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
: settings_(settings),
commit_state_(COMMIT_STATE_IDLE),
- commit_count_(0),
current_frame_number_(0),
last_frame_number_where_draw_was_called_(-1),
last_frame_number_where_tree_activation_attempted_(-1),
@@ -44,7 +42,6 @@ std::string SchedulerStateMachine::ToString() {
"settings_.impl_side_painting = %d; ",
settings_.impl_side_painting);
base::StringAppendF(&str, "commit_state_ = %d; ", commit_state_);
- base::StringAppendF(&str, "commit_count_ = %d; ", commit_count_);
base::StringAppendF(
&str, "current_frame_number_ = %d; ", current_frame_number_);
base::StringAppendF(&str,
@@ -83,8 +80,6 @@ std::string SchedulerStateMachine::ToString() {
main_thread_needs_layer_textures_);
base::StringAppendF(&str, "inside_begin_frame_ = %d; ",
inside_begin_frame_);
- base::StringAppendF(&str, "last_frame_time_ = %"PRId64"; ",
- (last_frame_time_ - base::TimeTicks()).InMilliseconds());
base::StringAppendF(&str, "visible_ = %d; ", visible_);
base::StringAppendF(&str, "can_start_ = %d; ", can_start_);
base::StringAppendF(&str, "can_draw_ = %d; ", can_draw_);
@@ -278,7 +273,6 @@ void SchedulerStateMachine::UpdateState(Action action) {
return;
case ACTION_COMMIT:
- commit_count_++;
if (expect_immediate_begin_frame_for_main_thread_)
commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW;
else
@@ -338,11 +332,6 @@ void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
}
bool SchedulerStateMachine::BeginFrameNeededByImplThread() const {
- // We should proactively request a BeginFrame if a commit is pending.
- if (needs_commit_ || needs_forced_commit_ ||
- commit_state_ != COMMIT_STATE_IDLE)
- return true;
-
// If we have a pending tree, need to keep getting notifications until
// the tree is ready to be swapped.
if (has_pending_tree_)
@@ -366,10 +355,6 @@ void SchedulerStateMachine::DidEnterBeginFrame() {
inside_begin_frame_ = true;
}
-void SchedulerStateMachine::SetFrameTime(base::TimeTicks frame_time) {
- last_frame_time_ = frame_time;
-}
-
void SchedulerStateMachine::DidLeaveBeginFrame() {
current_frame_number_++;
inside_begin_frame_ = false;
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 59e940c..1be0749 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -8,7 +8,6 @@
#include <string>
#include "base/basictypes.h"
-#include "base/time.h"
#include "cc/base/cc_export.h"
#include "cc/scheduler/scheduler_settings.h"
@@ -79,9 +78,7 @@ class CC_EXPORT SchedulerStateMachine {
// The scheduler will not draw more than once in a given BeginFrame
// callback.
void DidEnterBeginFrame();
- void SetFrameTime(base::TimeTicks frame_time);
void DidLeaveBeginFrame();
- bool inside_begin_frame() const { return inside_begin_frame_; }
// Indicates whether the LayerTreeHostImpl is visible.
void SetVisible(bool visible);
@@ -171,7 +168,6 @@ class CC_EXPORT SchedulerStateMachine {
const SchedulerSettings settings_;
CommitState commit_state_;
- int commit_count_;
int current_frame_number_;
int last_frame_number_where_draw_was_called_;
@@ -188,7 +184,6 @@ class CC_EXPORT SchedulerStateMachine {
bool expect_immediate_begin_frame_for_main_thread_;
bool main_thread_needs_layer_textures_;
bool inside_begin_frame_;
- base::TimeTicks last_frame_time_;
bool visible_;
bool can_start_;
bool can_draw_;
@@ -198,7 +193,6 @@ class CC_EXPORT SchedulerStateMachine {
OutputSurfaceState output_surface_state_;
bool did_create_and_initialize_first_output_surface_;
- private:
DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine);
};
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index c535212..001a229 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -98,7 +98,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
state.CommitState());
EXPECT_FALSE(state.NeedsCommit());
- EXPECT_TRUE(state.BeginFrameNeededByImplThread());
+ EXPECT_FALSE(state.BeginFrameNeededByImplThread());
}
}
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index bc7d575..68aecaf 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -30,11 +30,7 @@ namespace {
class FakeSchedulerClient : public SchedulerClient {
public:
- FakeSchedulerClient()
- : needs_begin_frame_(false) {
- Reset();
- }
-
+ FakeSchedulerClient() { Reset(); }
void Reset() {
actions_.clear();
states_.clear();
@@ -43,12 +39,15 @@ class FakeSchedulerClient : public SchedulerClient {
num_draws_ = 0;
}
- Scheduler* CreateScheduler(const SchedulerSettings& settings) {
- scheduler_ = Scheduler::Create(this, settings);
+ Scheduler* CreateScheduler(
+ scoped_ptr<FrameRateController> frame_rate_controller,
+ const SchedulerSettings& settings) {
+ scheduler_ =
+ Scheduler::Create(this, frame_rate_controller.Pass(), settings);
return scheduler_.get();
}
- bool needs_begin_frame() { return needs_begin_frame_; }
+
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]; }
@@ -69,11 +68,6 @@ class FakeSchedulerClient : public SchedulerClient {
}
// Scheduler Implementation.
- virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE {
- actions_.push_back("SetNeedsBeginFrameOnImplThread");
- states_.push_back(scheduler_->StateAsStringForTesting());
- needs_begin_frame_ = enable;
- }
virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {
actions_.push_back("ScheduledActionSendBeginFrameToMainThread");
states_.push_back(scheduler_->StateAsStringForTesting());
@@ -117,7 +111,6 @@ class FakeSchedulerClient : public SchedulerClient {
virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
protected:
- bool needs_begin_frame_;
bool draw_will_happen_;
bool swap_will_happen_if_draw_happens_;
int num_draws_;
@@ -128,8 +121,11 @@ class FakeSchedulerClient : public SchedulerClient {
TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginFrame) {
FakeSchedulerClient client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -142,8 +138,11 @@ TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginFrame) {
TEST(SchedulerTest, RequestCommit) {
FakeSchedulerClient client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -154,29 +153,33 @@ TEST(SchedulerTest, RequestCommit) {
// SetNeedsCommit should begin the frame.
scheduler->SetNeedsCommit();
- EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("ScheduledActionSendBeginFrameToMainThread", client);
+ EXPECT_FALSE(time_source->Active());
client.Reset();
// FinishCommit should commit
scheduler->FinishCommit();
EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
client.Reset();
- // BeginFrame should draw.
- scheduler->BeginFrame(base::TimeTicks::Now());
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
- EXPECT_FALSE(client.needs_begin_frame());
+ // Tick should draw.
+ time_source->Tick();
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client);
+ EXPECT_FALSE(time_source->Active());
client.Reset();
+
+ // Timer should be off.
+ EXPECT_FALSE(time_source->Active());
}
TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread) {
FakeSchedulerClient client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -187,8 +190,7 @@ TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread) {
// SetNedsCommit should begin the frame.
scheduler->SetNeedsCommit();
- EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
+ EXPECT_SINGLE_ACTION("ScheduledActionSendBeginFrameToMainThread", client);
client.Reset();
// Now SetNeedsCommit again. Calling here means we need a second frame.
@@ -201,85 +203,78 @@ TEST(SchedulerTest, RequestCommitAfterBeginFrameSentToMainThread) {
client.Reset();
// Tick should draw but then begin another frame.
- scheduler->BeginFrame(base::TimeTicks::Now());
- EXPECT_TRUE(client.needs_begin_frame());
+ time_source->Tick();
+ EXPECT_FALSE(time_source->Active());
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 2);
client.Reset();
-
- // Go back to quiescent state and verify we no longer request BeginFrames.
- scheduler->FinishCommit();
- scheduler->BeginFrame(base::TimeTicks::Now());
- EXPECT_FALSE(client.needs_begin_frame());
}
TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
FakeSchedulerClient client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
client.Reset();
scheduler->DidCreateAndInitializeOutputSurface();
+
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client);
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
- client.Reset();
- scheduler->BeginFrame(base::TimeTicks::Now());
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
+ time_source->Tick();
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(client.needs_begin_frame());
-
+ EXPECT_FALSE(time_source->Active());
client.Reset();
+
scheduler->SetMainThreadNeedsLayerTextures();
EXPECT_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
client,
0,
- 3);
+ 2);
// A commit was started by SetMainThreadNeedsLayerTextures().
- EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 3);
- EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 2, 3);
-
- // We should request a BeginFrame in anticipation of a draw.
+ EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 1, 2);
client.Reset();
+
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
// No draw happens since the textures are acquired by the main thread.
- client.Reset();
- scheduler->BeginFrame(base::TimeTicks::Now());
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrameOnImplThread", client);
+ time_source->Tick();
+ EXPECT_EQ(0, client.num_actions_());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
- // Commit will release the texture.
- client.Reset();
scheduler->FinishCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_ACTION("ScheduledActionCommit", client, 0, 1);
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
+ client.Reset();
// Now we can draw again after the commit happens.
- client.Reset();
- scheduler->BeginFrame(base::TimeTicks::Now());
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 2);
+ time_source->Tick();
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(client.needs_begin_frame());
+ EXPECT_FALSE(time_source->Active());
client.Reset();
}
TEST(SchedulerTest, TextureAcquisitionCollision) {
FakeSchedulerClient client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -290,22 +285,19 @@ TEST(SchedulerTest, TextureAcquisitionCollision) {
scheduler->SetNeedsCommit();
scheduler->SetMainThreadNeedsLayerTextures();
- EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 3);
- EXPECT_ACTION("SetNeedsBeginFrameOnImplThread", client, 1, 3);
+ EXPECT_ACTION("ScheduledActionSendBeginFrameToMainThread", client, 0, 2);
EXPECT_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
client,
- 2,
- 3);
+ 1,
+ 2);
client.Reset();
- // Although the compositor cannot draw because textures are locked by main
- // thread, we continue requesting SetNeedsBeginFrame in anticipation of the
- // unlock.
- EXPECT_TRUE(client.needs_begin_frame());
+ // Compositor not scheduled to draw because textures are locked by main thread
+ EXPECT_FALSE(time_source->Active());
// Trigger the commit
scheduler->FinishCommit();
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
client.Reset();
// Between commit and draw, texture acquisition for main thread delayed,
@@ -315,7 +307,7 @@ TEST(SchedulerTest, TextureAcquisitionCollision) {
client.Reset();
// Once compositor draw complete, the delayed texture acquisition fires.
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
EXPECT_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
client,
@@ -327,8 +319,11 @@ TEST(SchedulerTest, TextureAcquisitionCollision) {
TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
FakeSchedulerClient client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -384,8 +379,11 @@ class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
// 2. the scheduler drawing twice inside a single tick
TEST(SchedulerTest, RequestRedrawInsideDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -393,25 +391,28 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) {
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
EXPECT_EQ(0, client.num_draws());
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(client.needs_begin_frame());
+ EXPECT_FALSE(time_source->Active());
}
// Test that requesting redraw inside a failed draw doesn't lose the request.
TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -421,33 +422,33 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
EXPECT_EQ(0, client.num_draws());
// Fail the draw.
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
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_frame());
+ EXPECT_TRUE(time_source->Active());
// Fail the draw again.
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(2, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
// Draw successfully.
client.SetDrawWillHappen(true);
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(3, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_FALSE(time_source->Active());
}
class SchedulerClientThatsetNeedsCommitInsideDraw : public FakeSchedulerClient {
@@ -476,8 +477,11 @@ class SchedulerClientThatsetNeedsCommitInsideDraw : public FakeSchedulerClient {
// happen inside a ScheduledActionDrawAndSwap
TEST(SchedulerTest, RequestCommitInsideDraw) {
SchedulerClientThatsetNeedsCommitInsideDraw client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -486,26 +490,28 @@ TEST(SchedulerTest, RequestCommitInsideDraw) {
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
EXPECT_EQ(0, client.num_draws());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
+ EXPECT_FALSE(time_source->Active());
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(client.needs_begin_frame());
scheduler->FinishCommit();
- scheduler->BeginFrame(base::TimeTicks::Now());
- EXPECT_EQ(2, client.num_draws());;
+ time_source->Tick();
+ EXPECT_EQ(2, client.num_draws());
+ EXPECT_FALSE(time_source->Active());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->CommitPending());
- EXPECT_FALSE(client.needs_begin_frame());
}
// Tests that when a draw fails then the pending commit should not be dropped.
TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ make_scoped_ptr(new FrameRateController(time_source)),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -515,77 +521,128 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
EXPECT_EQ(0, client.num_draws());
// Fail the draw.
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
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_frame());
+ EXPECT_TRUE(time_source->Active());
// Fail the draw again.
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(2, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
// Draw successfully.
client.SetDrawWillHappen(true);
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(3, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_FALSE(time_source->Active());
}
TEST(SchedulerTest, NoSwapWhenDrawFails) {
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
SchedulerClientThatsetNeedsCommitInsideDraw client;
+ scoped_ptr<FakeFrameRateController> controller(
+ new FakeFrameRateController(time_source));
+ FakeFrameRateController* controller_ptr = controller.get();
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ controller.PassAs<FrameRateController>(),
+ default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
scheduler->DidCreateAndInitializeOutputSurface();
+ EXPECT_EQ(0, controller_ptr->NumFramesPending());
+
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
EXPECT_EQ(0, client.num_draws());
// Draw successfully, this starts a new frame.
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(1, client.num_draws());
+ EXPECT_EQ(1, controller_ptr->NumFramesPending());
+ scheduler->DidSwapBuffersComplete();
+ EXPECT_EQ(0, controller_ptr->NumFramesPending());
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(time_source->Active());
// Fail to draw, this should not start a frame.
client.SetDrawWillHappen(false);
- scheduler->BeginFrame(base::TimeTicks::Now());
+ time_source->Tick();
EXPECT_EQ(2, client.num_draws());
+ EXPECT_EQ(0, controller_ptr->NumFramesPending());
}
TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
FakeSchedulerClient client;
+ scoped_ptr<FakeFrameRateController> controller(
+ new FakeFrameRateController(time_source));
+ FakeFrameRateController* controller_ptr = controller.get();
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ Scheduler* scheduler = client.CreateScheduler(
+ controller.PassAs<FrameRateController>(),
+ default_scheduler_settings);
+
+ EXPECT_EQ(0, controller_ptr->NumFramesPending());
// Tell the client that it will fail to swap.
client.SetDrawWillHappen(true);
client.SetSwapWillHappenIfDrawHappens(false);
// Get the compositor to do a ScheduledActionDrawAndSwapForced.
- scheduler->SetCanDraw(true);
scheduler->SetNeedsRedraw();
scheduler->SetNeedsForcedRedraw();
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapForced"));
+
+ // We should not have told the frame rate controller that we began a frame.
+ EXPECT_EQ(0, controller_ptr->NumFramesPending());
+}
+
+TEST(SchedulerTest, RecreateOutputSurfaceClearsPendingDrawCount) {
+ scoped_refptr<FakeTimeSource> time_source(new FakeTimeSource());
+ FakeSchedulerClient client;
+ scoped_ptr<FakeFrameRateController> controller(
+ new FakeFrameRateController(time_source));
+ FakeFrameRateController* controller_ptr = controller.get();
+ SchedulerSettings default_scheduler_settings;
+ Scheduler* scheduler = client.CreateScheduler(
+ controller.PassAs<FrameRateController>(),
+ default_scheduler_settings);
+
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ scheduler->DidCreateAndInitializeOutputSurface();
+
+ // Draw successfully, this starts a new frame.
+ scheduler->SetNeedsRedraw();
+ time_source->Tick();
+ EXPECT_EQ(1, controller_ptr->NumFramesPending());
+
+ scheduler->DidLoseOutputSurface();
+ // Verifying that it's 1 so that we know that it's reset on recreate.
+ EXPECT_EQ(1, controller_ptr->NumFramesPending());
+
+ scheduler->DidCreateAndInitializeOutputSurface();
+ EXPECT_EQ(0, controller_ptr->NumFramesPending());
}
} // namespace
diff --git a/cc/scheduler/vsync_time_source.cc b/cc/scheduler/vsync_time_source.cc
new file mode 100644
index 0000000..206e2376
--- /dev/null
+++ b/cc/scheduler/vsync_time_source.cc
@@ -0,0 +1,76 @@
+// 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.
+
+#include "cc/scheduler/vsync_time_source.h"
+
+#include "base/logging.h"
+
+namespace cc {
+
+scoped_refptr<VSyncTimeSource> VSyncTimeSource::Create(
+ VSyncProvider* vsync_provider, NotificationDisableOption option) {
+ return make_scoped_refptr(new VSyncTimeSource(vsync_provider, option));
+}
+
+VSyncTimeSource::VSyncTimeSource(
+ VSyncProvider* vsync_provider, NotificationDisableOption option)
+ : active_(false),
+ notification_requested_(false),
+ vsync_provider_(vsync_provider),
+ client_(NULL),
+ disable_option_(option) {}
+
+VSyncTimeSource::~VSyncTimeSource() {}
+
+void VSyncTimeSource::SetClient(TimeSourceClient* client) {
+ client_ = client;
+}
+
+void VSyncTimeSource::SetActive(bool active) {
+ if (active_ == active)
+ return;
+ active_ = active;
+ if (active_ && !notification_requested_) {
+ notification_requested_ = true;
+ vsync_provider_->RequestVSyncNotification(this);
+ }
+ if (!active_ && disable_option_ == DISABLE_SYNCHRONOUSLY) {
+ notification_requested_ = false;
+ vsync_provider_->RequestVSyncNotification(NULL);
+ }
+}
+
+bool VSyncTimeSource::Active() const {
+ return active_;
+}
+
+base::TimeTicks VSyncTimeSource::LastTickTime() {
+ return last_tick_time_;
+}
+
+base::TimeTicks VSyncTimeSource::NextTickTime() {
+ return Active() ? last_tick_time_ + interval_ : base::TimeTicks();
+}
+
+void VSyncTimeSource::SetTimebaseAndInterval(base::TimeTicks,
+ base::TimeDelta interval) {
+ interval_ = interval;
+}
+
+void VSyncTimeSource::DidVSync(base::TimeTicks frame_time) {
+ last_tick_time_ = frame_time;
+ if (disable_option_ == DISABLE_SYNCHRONOUSLY) {
+ DCHECK(active_);
+ } else if (!active_) {
+ if (notification_requested_) {
+ notification_requested_ = false;
+ vsync_provider_->RequestVSyncNotification(NULL);
+ }
+ return;
+ }
+ if (client_)
+ client_->OnTimerTick();
+}
+
+} // namespace cc
diff --git a/cc/scheduler/vsync_time_source.h b/cc/scheduler/vsync_time_source.h
new file mode 100644
index 0000000..4cd0441
--- /dev/null
+++ b/cc/scheduler/vsync_time_source.h
@@ -0,0 +1,78 @@
+// 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_VSYNC_TIME_SOURCE_H_
+#define CC_SCHEDULER_VSYNC_TIME_SOURCE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/scheduler/time_source.h"
+
+namespace cc {
+
+class CC_EXPORT VSyncClient {
+ public:
+ virtual void DidVSync(base::TimeTicks frame_time) = 0;
+
+ protected:
+ virtual ~VSyncClient() {}
+};
+
+class VSyncProvider {
+ public:
+ // Request to be notified of future vsync events. The notifications will be
+ // delivered until they are disabled by calling this function with a null
+ // client.
+ virtual void RequestVSyncNotification(VSyncClient* client) = 0;
+
+ protected:
+ virtual ~VSyncProvider() {}
+};
+
+// This timer implements a time source that is explicitly triggered by an
+// external vsync signal.
+class CC_EXPORT VSyncTimeSource : public TimeSource, public VSyncClient {
+ public:
+ enum NotificationDisableOption {
+ // The notification will be lazily disabled in the callback to ensure
+ // we get notified of the frame immediately following a quick on-off-on
+ // transition.
+ DISABLE_ON_NEXT_TICK,
+ DISABLE_SYNCHRONOUSLY
+ };
+
+ static scoped_refptr<VSyncTimeSource> Create(
+ VSyncProvider* vsync_provider, NotificationDisableOption option);
+
+ // TimeSource implementation
+ virtual void SetClient(TimeSourceClient* client) OVERRIDE;
+ virtual void SetTimebaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) OVERRIDE;
+ virtual void SetActive(bool active) OVERRIDE;
+ virtual bool Active() const OVERRIDE;
+ virtual base::TimeTicks LastTickTime() OVERRIDE;
+ virtual base::TimeTicks NextTickTime() OVERRIDE;
+
+ // VSyncClient implementation
+ virtual void DidVSync(base::TimeTicks frame_time) OVERRIDE;
+
+ protected:
+ explicit VSyncTimeSource(VSyncProvider* vsync_provider,
+ NotificationDisableOption option);
+ virtual ~VSyncTimeSource();
+
+ base::TimeTicks last_tick_time_;
+ base::TimeDelta interval_;
+ bool active_;
+ bool notification_requested_;
+
+ VSyncProvider* vsync_provider_;
+ TimeSourceClient* client_;
+ NotificationDisableOption disable_option_;
+
+ DISALLOW_COPY_AND_ASSIGN(VSyncTimeSource);
+};
+
+} // namespace cc
+
+#endif // CC_SCHEDULER_VSYNC_TIME_SOURCE_H_
diff --git a/cc/scheduler/vsync_time_source_unittest.cc b/cc/scheduler/vsync_time_source_unittest.cc
new file mode 100644
index 0000000..4834630
--- /dev/null
+++ b/cc/scheduler/vsync_time_source_unittest.cc
@@ -0,0 +1,124 @@
+// 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.
+
+#include "cc/scheduler/vsync_time_source.h"
+
+#include "cc/test/scheduler_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class FakeVSyncProvider : public VSyncProvider {
+ public:
+ FakeVSyncProvider() : client_(NULL) {}
+
+ // VSyncProvider implementation.
+ virtual void RequestVSyncNotification(VSyncClient* client) OVERRIDE {
+ client_ = client;
+ }
+
+ bool IsVSyncNotificationEnabled() const { return client_ != NULL; }
+
+ void Trigger(base::TimeTicks frame_time) {
+ if (client_)
+ client_->DidVSync(frame_time);
+ }
+
+ private:
+ VSyncClient* client_;
+};
+
+class VSyncTimeSourceTest : public testing::Test {
+ public:
+ VSyncTimeSourceTest()
+ : timer_(VSyncTimeSource::Create(
+ &provider_, VSyncTimeSource::DISABLE_ON_NEXT_TICK)) {
+ timer_->SetClient(&client_);
+ }
+
+ protected:
+ FakeTimeSourceClient client_;
+ FakeVSyncProvider provider_;
+ scoped_refptr<VSyncTimeSource> timer_;
+};
+
+TEST_F(VSyncTimeSourceTest, TaskPostedAndTickCalled) {
+ EXPECT_FALSE(provider_.IsVSyncNotificationEnabled());
+
+ timer_->SetActive(true);
+ EXPECT_TRUE(provider_.IsVSyncNotificationEnabled());
+
+ base::TimeTicks frame_time = base::TimeTicks::Now();
+ provider_.Trigger(frame_time);
+ EXPECT_TRUE(client_.TickCalled());
+ EXPECT_EQ(timer_->LastTickTime(), frame_time);
+}
+
+TEST_F(VSyncTimeSourceTest, NotificationDisabledLazily) {
+ base::TimeTicks frame_time = base::TimeTicks::Now();
+
+ // Enable timer and trigger sync once.
+ timer_->SetActive(true);
+ EXPECT_TRUE(provider_.IsVSyncNotificationEnabled());
+ provider_.Trigger(frame_time);
+ EXPECT_TRUE(client_.TickCalled());
+
+ // Disabling the timer should not disable vsync notification immediately.
+ client_.Reset();
+ timer_->SetActive(false);
+ EXPECT_TRUE(provider_.IsVSyncNotificationEnabled());
+
+ // At the next vsync the notification is disabled, but the timer isn't ticked.
+ provider_.Trigger(frame_time);
+ EXPECT_FALSE(provider_.IsVSyncNotificationEnabled());
+ EXPECT_FALSE(client_.TickCalled());
+
+ // The notification should not be disabled multiple times.
+ provider_.RequestVSyncNotification(timer_.get());
+ provider_.Trigger(frame_time);
+ EXPECT_TRUE(provider_.IsVSyncNotificationEnabled());
+ EXPECT_FALSE(client_.TickCalled());
+}
+
+TEST_F(VSyncTimeSourceTest, NotificationDisabledImmediatelyForSetting) {
+ timer_ = VSyncTimeSource::Create(&provider_,
+ VSyncTimeSource::DISABLE_SYNCHRONOUSLY);
+ timer_->SetClient(&client_);
+ base::TimeTicks frame_time = base::TimeTicks::Now();
+
+ // Enable timer and trigger sync once.
+ timer_->SetActive(true);
+ EXPECT_TRUE(provider_.IsVSyncNotificationEnabled());
+ provider_.Trigger(frame_time);
+ EXPECT_TRUE(client_.TickCalled());
+
+ // Disable timer should disable vsync notification immediately.
+ timer_->SetActive(false);
+ EXPECT_FALSE(provider_.IsVSyncNotificationEnabled());
+
+ // Enable again and timer can be ticked again.
+ client_.Reset();
+ timer_->SetActive(true);
+ EXPECT_TRUE(provider_.IsVSyncNotificationEnabled());
+ provider_.Trigger(frame_time);
+ EXPECT_TRUE(client_.TickCalled());
+}
+
+TEST_F(VSyncTimeSourceTest, ValidNextTickTime) {
+ base::TimeTicks frame_time = base::TimeTicks::Now();
+ base::TimeDelta interval = base::TimeDelta::FromSeconds(1);
+
+ ASSERT_EQ(timer_->NextTickTime(), base::TimeTicks());
+
+ timer_->SetActive(true);
+ provider_.Trigger(frame_time);
+ ASSERT_EQ(timer_->NextTickTime(), frame_time);
+
+ timer_->SetTimebaseAndInterval(frame_time, interval);
+ ASSERT_EQ(timer_->NextTickTime(), frame_time + interval);
+}
+
+} // namespace
+} // namespace cc