Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9108)

Unified Diff: cc/scheduler/scheduler.cc

Issue 267783004: Refactoring the way begin frame sources inside scheduler work. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Scheduler tests now pass and the code is cleaner. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/scheduler/scheduler.h ('k') | cc/scheduler/scheduler_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/scheduler/scheduler.cc
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index e924d33884bf6dec6a758b4d640b8fef0fee8059..f39df56c693906236ff0ed70ef953d2bf8f39f77 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -11,76 +11,21 @@
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/scheduler/frame_source.h"
#include "ui/gfx/frame_time.h"
namespace cc {
-class SyntheticBeginFrameSource : public TimeSourceClient {
- public:
- SyntheticBeginFrameSource(Scheduler* scheduler,
- base::SingleThreadTaskRunner* task_runner)
- : scheduler_(scheduler) {
- if (gfx::FrameTime::TimestampsAreHighRes()) {
- time_source_ = DelayBasedTimeSourceHighRes::Create(
- scheduler_->VSyncInterval(), task_runner);
- } else {
- time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(),
- task_runner);
- }
- time_source_->SetClient(this);
- }
-
- virtual ~SyntheticBeginFrameSource() {}
-
- // Updates the phase and frequency of the timer.
- void CommitVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) {
- time_source_->SetTimebaseAndInterval(timebase, interval);
- }
-
- // Activates future BeginFrames and, if activating, pushes the most
- // recently missed BeginFrame to the back of a retroactive queue.
- void SetNeedsBeginFrame(bool needs_begin_frame,
- std::deque<BeginFrameArgs>* begin_retro_frame_args) {
- base::TimeTicks missed_tick_time =
- time_source_->SetActive(needs_begin_frame);
- if (!missed_tick_time.is_null()) {
- begin_retro_frame_args->push_back(
- CreateSyntheticBeginFrameArgs(missed_tick_time));
- }
- }
-
- // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame.
- virtual void OnTimerTick() OVERRIDE {
- BeginFrameArgs begin_frame_args(
- CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
- scheduler_->BeginFrame(begin_frame_args);
- }
-
- private:
- BeginFrameArgs CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time) {
- base::TimeTicks deadline =
- time_source_->NextTickTime() - scheduler_->EstimatedParentDrawTime();
- return BeginFrameArgs::Create(
- frame_time, deadline, scheduler_->VSyncInterval());
- }
-
- Scheduler* scheduler_;
- scoped_refptr<TimeSource> time_source_;
-};
-
Scheduler::Scheduler(
SchedulerClient* client,
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
+ BeginFrameSource* external_frame_source,
const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner)
: settings_(scheduler_settings),
client_(client),
layer_tree_host_id_(layer_tree_host_id),
impl_task_runner_(impl_task_runner),
- vsync_interval_(BeginFrameArgs::DefaultInterval()),
- last_set_needs_begin_frame_(false),
- begin_unthrottled_frame_posted_(false),
begin_retro_frame_posted_(false),
state_machine_(scheduler_settings),
inside_process_scheduled_actions_(false),
@@ -98,8 +43,6 @@ Scheduler::Scheduler(
begin_retro_frame_closure_ =
base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
- begin_unthrottled_frame_closure_ =
- base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr());
begin_impl_frame_deadline_closure_ = base::Bind(
&Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
poll_for_draw_triggers_closure_ = base::Bind(
@@ -107,32 +50,37 @@ Scheduler::Scheduler(
advance_commit_state_closure_ = base::Bind(
&Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
- if (!settings_.begin_frame_scheduling_enabled) {
- SetupSyntheticBeginFrames();
- }
-}
+ scoped_ptr<BeginFrameSource> primary_frame_source;
-Scheduler::~Scheduler() {
- if (synthetic_begin_frame_source_) {
- synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
- &begin_retro_frame_args_);
+ if (!settings_.throttle_frame_production) {
+ TRACE_EVENT0("cc", "Scheduler::Scheduler() BackToBackBeginFrameSource");
+ primary_frame_source = scoped_ptr<BeginFrameSource>(
+ new BackToBackBeginFrameSource(this, impl_task_runner_));
+ } else if (settings_.begin_frame_scheduling_enabled) {
+ TRACE_EVENT0("cc", "Scheduler::Scheduler() ProxyBeginFrameSource");
+ primary_frame_source = scoped_ptr<BeginFrameSource>(
+ new ProxyBeginFrameSource(this, external_frame_source));
+ } else {
+ TRACE_EVENT0("cc", "Scheduler::Scheduler() SyntheticBeginFrameSource");
+ primary_frame_source =
+ scoped_ptr<BeginFrameSource>(new SyntheticBeginFrameSource(
+ this, impl_task_runner_, BeginFrameArgs::DefaultInterval()));
}
+ scoped_ptr<BeginFrameSource> background_frame_source(
+ new SyntheticBeginFrameSource(
+ this, impl_task_runner_, base::TimeDelta::FromSeconds(1)));
+
+ frame_source_ = scoped_ptr<DualBeginFrameSource>(new DualBeginFrameSource(
+ this, primary_frame_source.Pass(), background_frame_source.Pass()));
}
-void Scheduler::SetupSyntheticBeginFrames() {
- DCHECK(!synthetic_begin_frame_source_);
- synthetic_begin_frame_source_.reset(
- new SyntheticBeginFrameSource(this, impl_task_runner_.get()));
+Scheduler::~Scheduler() {
+ frame_source_->SetGenerateFrames(false);
}
void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) {
- // TODO(brianderson): We should not be receiving 0 intervals.
- if (interval == base::TimeDelta())
- interval = BeginFrameArgs::DefaultInterval();
- vsync_interval_ = interval;
- if (!settings_.begin_frame_scheduling_enabled)
- synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval);
+ frame_source_->SetTimeBaseAndInterval(timebase, interval);
}
void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
@@ -146,6 +94,11 @@ void Scheduler::SetCanStart() {
void Scheduler::SetVisible(bool visible) {
state_machine_.SetVisible(visible);
+ if (visible) {
+ frame_source_->SwitchSource(frame_source_->SourceForeground());
+ } else {
+ frame_source_->SwitchSource(frame_source_->SourceBackground());
+ }
ProcessScheduledActions();
}
@@ -228,14 +181,14 @@ void Scheduler::DidManageTiles() {
void Scheduler::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
state_machine_.DidLoseOutputSurface();
- last_set_needs_begin_frame_ = false;
+ frame_source_->SetGenerateFrames(false);
begin_retro_frame_args_.clear();
ProcessScheduledActions();
}
void Scheduler::DidCreateAndInitializeOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
- DCHECK(!last_set_needs_begin_frame_);
+ DCHECK(!frame_source_->IsGeneratingFrames());
DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
state_machine_.DidCreateAndInitializeOutputSurface();
ProcessScheduledActions();
@@ -247,7 +200,7 @@ void Scheduler::NotifyBeginMainFrameStarted() {
}
base::TimeTicks Scheduler::AnticipatedDrawTime() const {
- if (!last_set_needs_begin_frame_ ||
+ if (!frame_source_->IsGeneratingFrames() ||
begin_impl_frame_args_.interval <= base::TimeDelta())
return base::TimeTicks();
@@ -265,75 +218,28 @@ base::TimeTicks Scheduler::LastBeginImplFrameTime() {
void Scheduler::SetupNextBeginFrameIfNeeded() {
bool needs_begin_frame = state_machine_.BeginFrameNeeded();
- if (settings_.throttle_frame_production) {
- SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame);
- } else {
- SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame);
- }
- SetupPollingMechanisms(needs_begin_frame);
-}
-
-// When we are throttling frame production, we request BeginFrames
-// from the OutputSurface.
-void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
- bool needs_begin_frame) {
bool at_end_of_deadline =
- state_machine_.begin_impl_frame_state() ==
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
+ (state_machine_.begin_impl_frame_state() ==
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) ||
+ (state_machine_.begin_impl_frame_state() ==
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
bool should_call_set_needs_begin_frame =
// Always request the BeginFrame immediately if it wasn't needed before.
- (needs_begin_frame && !last_set_needs_begin_frame_) ||
+ needs_begin_frame ||
// Only stop requesting BeginFrames after a deadline.
- (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
+ (!needs_begin_frame && at_end_of_deadline);
if (should_call_set_needs_begin_frame) {
- if (settings_.begin_frame_scheduling_enabled) {
- client_->SetNeedsBeginFrame(needs_begin_frame);
- } else {
- synthetic_begin_frame_source_->SetNeedsBeginFrame(
- needs_begin_frame, &begin_retro_frame_args_);
- }
- last_set_needs_begin_frame_ = needs_begin_frame;
+ frame_source_->SetGenerateFrames(needs_begin_frame);
}
- PostBeginRetroFrameIfNeeded();
-}
-
-// When we aren't throttling frame production, we initiate a BeginFrame
-// as soon as one is needed.
-void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
- bool needs_begin_frame) {
- last_set_needs_begin_frame_ = needs_begin_frame;
-
- if (!needs_begin_frame || begin_unthrottled_frame_posted_)
- return;
+ // TODO(mithro): Use pending frames properly.
+ if (at_end_of_deadline)
+ frame_source_->PendingFrames(0);
- if (state_machine_.begin_impl_frame_state() !=
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
- state_machine_.begin_impl_frame_state() !=
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
- return;
- }
-
- begin_unthrottled_frame_posted_ = true;
- impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
-}
-
-// BeginUnthrottledFrame is used when we aren't throttling frame production.
-// This will usually be because VSync is disabled.
-void Scheduler::BeginUnthrottledFrame() {
- DCHECK(!settings_.throttle_frame_production);
- DCHECK(begin_retro_frame_args_.empty());
-
- base::TimeTicks now = gfx::FrameTime::Now();
- base::TimeTicks deadline = now + vsync_interval_;
-
- BeginFrameArgs begin_frame_args =
- BeginFrameArgs::Create(now, deadline, vsync_interval_);
- BeginImplFrame(begin_frame_args);
-
- begin_unthrottled_frame_posted_ = false;
+ PostBeginRetroFrameIfNeeded();
+ SetupPollingMechanisms(needs_begin_frame);
}
// We may need to poll when we can't rely on BeginFrame to advance certain
@@ -391,7 +297,9 @@ void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
// a BeginRetroFrame.
void Scheduler::BeginFrame(const BeginFrameArgs& args) {
TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", ToTrace(args));
- DCHECK(settings_.throttle_frame_production);
+
+ BeginFrameArgs adjusted_args(args);
+ adjusted_args.deadline -= EstimatedParentDrawTime();
bool should_defer_begin_frame;
if (settings_.using_synchronous_renderer_compositor) {
@@ -399,19 +307,22 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) {
} else {
should_defer_begin_frame =
!begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
- !last_set_needs_begin_frame_ ||
+ !frame_source_->IsGeneratingFrames() ||
(state_machine_.begin_impl_frame_state() !=
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
}
if (should_defer_begin_frame) {
- begin_retro_frame_args_.push_back(args);
- TRACE_EVENT_INSTANT0(
- "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
+ begin_retro_frame_args_.push_back(adjusted_args);
+ TRACE_EVENT_INSTANT1("cc",
+ "Scheduler::BeginFrame deferred",
+ TRACE_EVENT_SCOPE_THREAD,
+ "args",
+ ToTrace(adjusted_args));
return;
}
- BeginImplFrame(args);
+ BeginImplFrame(adjusted_args);
}
// BeginRetroFrame is called for BeginFrames that we've deferred because
@@ -442,12 +353,11 @@ void Scheduler::BeginRetroFrame() {
TRACE_EVENT1("cc",
"Scheduler::BeginRetroFrame discarding",
"frame_time",
- begin_retro_frame_args_.front().frame_time);
+ ToTrace(begin_retro_frame_args_.front()));
begin_retro_frame_args_.pop_front();
}
if (begin_retro_frame_args_.empty()) {
- DCHECK(settings_.throttle_frame_production);
TRACE_EVENT_INSTANT0("cc",
"Scheduler::BeginRetroFrames all expired",
TRACE_EVENT_SCOPE_THREAD);
@@ -462,7 +372,7 @@ void Scheduler::BeginRetroFrame() {
// will check if there is a pending BeginRetroFrame to ensure we handle
// BeginFrames in FIFO order.
void Scheduler::PostBeginRetroFrameIfNeeded() {
- if (!last_set_needs_begin_frame_)
+ if (!frame_source_->IsGeneratingFrames())
return;
if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
@@ -671,19 +581,17 @@ bool Scheduler::WillDrawIfNeeded() const {
scoped_ptr<base::Value> Scheduler::AsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
state->Set("state_machine", state_machine_.AsValue().release());
+ state->Set("frame_source",
+ frame_source_->BeginFrameSourceAsValue().release());
scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue);
scheduler_state->SetDouble(
"time_until_anticipated_draw_time_ms",
(AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
- scheduler_state->SetDouble("vsync_interval_ms",
- vsync_interval_.InMillisecondsF());
scheduler_state->SetDouble("estimated_parent_draw_time_ms",
estimated_parent_draw_time_.InMillisecondsF());
scheduler_state->SetBoolean("last_set_needs_begin_frame_",
- last_set_needs_begin_frame_);
- scheduler_state->SetBoolean("begin_unthrottled_frame_posted_",
- begin_unthrottled_frame_posted_);
+ frame_source_->IsGeneratingFrames());
scheduler_state->SetBoolean("begin_retro_frame_posted_",
begin_retro_frame_posted_);
scheduler_state->SetInteger("begin_retro_frame_args_",
« no previous file with comments | « cc/scheduler/scheduler.h ('k') | cc/scheduler/scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698