Index: cc/scheduler/scheduler.cc |
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc |
index 78d1973e9c035a07275e9cb921debbf34ba37966..7a05a283b93a9c55ecc0c8676bc15c92d416ceb5 100644 |
--- a/cc/scheduler/scheduler.cc |
+++ b/cc/scheduler/scheduler.cc |
@@ -10,6 +10,7 @@ |
#include "base/logging.h" |
#include "cc/debug/devtools_instrumentation.h" |
#include "cc/debug/traced_value.h" |
+#include "cc/scheduler/delay_based_time_source.h" |
#include "ui/gfx/frame_time.h" |
namespace cc { |
@@ -18,11 +19,12 @@ Scheduler::Scheduler( |
SchedulerClient* client, |
const SchedulerSettings& scheduler_settings, |
int layer_tree_host_id, |
- const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner) |
+ 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_retro_frame_posted_(false), |
state_machine_(scheduler_settings), |
@@ -43,10 +45,53 @@ Scheduler::Scheduler( |
&Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); |
advance_commit_state_closure_ = base::Bind( |
&Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); |
+ |
+ if (!settings_.begin_frame_scheduling_enabled) { |
+ SetupSyntheticBeginFrames(); |
+ } |
} |
Scheduler::~Scheduler() {} |
Sami
2014/04/08 13:46:01
Should probably stop the time source here.
brianderson
2014/04/09 02:52:05
The timesource cleans itself up, but it wouldn't h
brianderson
2014/04/10 23:45:58
Done.
|
+void Scheduler::SetupSyntheticBeginFrames() { |
+ if (gfx::FrameTime::TimestampsAreHighRes()) { |
+ time_source_for_synthetic_begin_frames_ = |
+ DelayBasedTimeSourceHighRes::Create(vsync_interval_, |
+ impl_task_runner_.get()); |
+ } else { |
+ time_source_for_synthetic_begin_frames_ = |
+ DelayBasedTimeSource::Create(vsync_interval_, impl_task_runner_.get()); |
+ } |
+ time_source_for_synthetic_begin_frames_->SetClient(this); |
+} |
+ |
+void Scheduler::OnTimerTick() { |
+ DCHECK(!settings_.begin_frame_scheduling_enabled); |
+ BeginFrameArgs synthentic_begin_frame_args(CreateSyntheticBeginFrameArgs( |
+ time_source_for_synthetic_begin_frames_->LastTickTime())); |
+ BeginFrame(synthentic_begin_frame_args); |
+} |
+ |
+BeginFrameArgs Scheduler::CreateSyntheticBeginFrameArgs( |
+ base::TimeTicks frame_time) { |
+ base::TimeTicks deadline = |
+ time_source_for_synthetic_begin_frames_->NextTickTime() - |
+ estimated_parent_draw_time_; |
+ return BeginFrameArgs::Create(frame_time, deadline, vsync_interval_); |
+} |
+ |
+void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
+ base::TimeDelta interval) { |
+ vsync_interval_ = interval; |
+ if (!settings_.begin_frame_scheduling_enabled) |
+ time_source_for_synthetic_begin_frames_->SetTimebaseAndInterval(timebase, |
+ interval); |
+} |
+ |
+void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { |
+ estimated_parent_draw_time_ = draw_time; |
+} |
+ |
void Scheduler::SetCanStart() { |
state_machine_.SetCanStart(); |
ProcessScheduledActions(); |
@@ -96,7 +141,10 @@ void Scheduler::SetMaxSwapsPending(int max) { |
state_machine_.SetMaxSwapsPending(max); |
} |
-void Scheduler::DidSwapBuffers() { state_machine_.DidSwapBuffers(); } |
+void Scheduler::DidSwapBuffers() { |
+ DCHECK(state_machine_.HasInitializedOutputSurface()); |
+ state_machine_.DidSwapBuffers(); |
+} |
void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) { |
state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile); |
@@ -174,6 +222,17 @@ base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
void Scheduler::SetupNextBeginFrameIfNeeded() { |
bool needs_begin_frame = state_machine_.BeginFrameNeeded(); |
+ if (settings_.throttle_frame_production) { |
+ SetupNextBeginFrameWhenVSyncEnabled(needs_begin_frame); |
Sami
2014/04/08 13:46:01
bikeshed: s/VSync/Throttling/ to keep the terms a
brianderson
2014/04/09 02:52:05
I was afraid of confusing vsync throttling with sw
brianderson
2014/04/10 23:45:58
Done.
|
+ } else { |
+ SetupNextBeginFrameWhenVSyncDisabled(needs_begin_frame); |
+ } |
+ SetupPollingMechanisms(needs_begin_frame); |
+} |
+ |
+// When we are throttling frame production, we request BeginFrames |
+// from the OutputSurface. |
+void Scheduler::SetupNextBeginFrameWhenVSyncEnabled(bool needs_begin_frame) { |
bool at_end_of_deadline = |
state_machine_.begin_impl_frame_state() == |
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; |
@@ -181,18 +240,54 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { |
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_) || |
- // We always need to explicitly request our next BeginFrame. |
- at_end_of_deadline; |
+ // Only stop requesting BeginFrames after a deadline. |
+ (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline); |
if (should_call_set_needs_begin_frame) { |
- client_->SetNeedsBeginFrame(needs_begin_frame); |
+ if (settings_.begin_frame_scheduling_enabled) { |
+ client_->SetNeedsBeginFrame(needs_begin_frame); |
+ } else { |
+ base::TimeTicks missed_tick_time = |
+ time_source_for_synthetic_begin_frames_->SetActive(needs_begin_frame); |
+ if (!missed_tick_time.is_null()) { |
+ begin_retro_frame_args_.push_back( |
+ CreateSyntheticBeginFrameArgs(missed_tick_time)); |
+ } |
+ } |
last_set_needs_begin_frame_ = needs_begin_frame; |
} |
- // Handle retroactive BeginFrames. |
if (needs_begin_frame) |
PostBeginRetroFrameIfNeeded(); |
+} |
+ |
+// When we aren't throttling frame production, we create our own |
+// BeginImplFrames as soon as we go idle, using the BeginRetroFrame logic. |
+void Scheduler::SetupNextBeginFrameWhenVSyncDisabled(bool needs_begin_frame) { |
+ last_set_needs_begin_frame_ = needs_begin_frame; |
+ |
+ if (!needs_begin_frame || begin_retro_frame_posted_) |
+ return; |
+ |
+ 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; |
+ } |
+ |
+ base::TimeTicks now = gfx::FrameTime::Now(); |
+ base::TimeDelta interval = vsync_interval_ > base::TimeDelta() |
+ ? vsync_interval_ |
+ : BeginFrameArgs::DefaultInterval(); |
+ DCHECK(begin_retro_frame_args_.empty()); |
+ begin_retro_frame_args_.push_back( |
+ BeginFrameArgs::Create(now, now + interval, interval)); |
+ PostBeginRetroFrame(); |
+} |
+ |
+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 |
@@ -256,6 +351,7 @@ void Scheduler::PostBeginRetroFrameIfNeeded() { |
} |
void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
+ DCHECK(settings_.throttle_frame_production); |
if (settings_.using_synchronous_renderer_compositor || |
(last_set_needs_begin_frame_ && begin_retro_frame_args_.empty() && |
state_machine_.begin_impl_frame_state() == |
@@ -268,21 +364,31 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
} |
} |
+void Scheduler::PostBeginRetroFrame() { |
+ begin_retro_frame_posted_ = true; |
+ impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); |
+} |
+ |
void Scheduler::BeginRetroFrame() { |
TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); |
DCHECK(begin_retro_frame_posted_); |
DCHECK(!begin_retro_frame_args_.empty()); |
// Discard expired BeginRetroFrames |
- base::TimeTicks now = gfx::FrameTime::Now(); |
- base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
- while (!begin_retro_frame_args_.empty() && |
- now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), |
- draw_duration_estimate)) { |
- begin_retro_frame_args_.pop_front(); |
+ // Not if frame production isn't throttled though, since all frames will be |
Sami
2014/04/08 13:46:01
This is getting a little confusing. Should we perh
brianderson
2014/04/09 02:52:05
This is for the unthrottled (vsync disabled) frame
brianderson
2014/04/10 23:45:58
Added a BeginUnthrottledFrame with a separate clos
|
+ // BeginRetroFrames. |
+ if (settings_.throttle_frame_production) { |
+ base::TimeTicks now = gfx::FrameTime::Now(); |
+ base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
+ while (!begin_retro_frame_args_.empty() && |
+ now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), |
+ draw_duration_estimate)) { |
+ begin_retro_frame_args_.pop_front(); |
+ } |
} |
if (begin_retro_frame_args_.empty()) { |
+ DCHECK(settings_.throttle_frame_production); |
TRACE_EVENT_INSTANT0( |
"cc", "Scheduler::BeginRetroFrames expired", TRACE_EVENT_SCOPE_THREAD); |
} else { |
@@ -294,7 +400,6 @@ void Scheduler::BeginRetroFrame() { |
} |
void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { |
- TRACE_EVENT0("cc", "Scheduler::BeginImplFrame"); |
DCHECK(state_machine_.begin_impl_frame_state() == |
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
DCHECK(state_machine_.HasInitializedOutputSurface()); |