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

Unified Diff: cc/scheduler/scheduler.cc

Issue 221833009: cc: Move scheduling logic out of OutputSurface (Closed) Base URL: http://git.chromium.org/chromium/src.git@swapAck2Sched11
Patch Set: rebase; fix tests Created 6 years, 8 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
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());

Powered by Google App Engine
This is Rietveld 408576698