Index: cc/surfaces/display_scheduler.cc |
diff --git a/cc/surfaces/display_scheduler.cc b/cc/surfaces/display_scheduler.cc |
index 229bc6306ccb1ecf4af4056e074b35a56ac9f429..8ec6d51241f6f8ba9cd6a99f2ef9c82ebcc2d5e5 100644 |
--- a/cc/surfaces/display_scheduler.cc |
+++ b/cc/surfaces/display_scheduler.cc |
@@ -9,14 +9,15 @@ |
#include "base/auto_reset.h" |
#include "base/stl_util.h" |
#include "base/trace_event/trace_event.h" |
+#include "cc/output/begin_frame_args.h" |
#include "cc/output/output_surface.h" |
namespace cc { |
-DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source, |
- base::SingleThreadTaskRunner* task_runner, |
+DisplayScheduler::DisplayScheduler(base::SingleThreadTaskRunner* task_runner, |
int max_pending_swaps) |
- : begin_frame_source_(begin_frame_source), |
+ : client_(nullptr), |
+ begin_frame_source_(nullptr), |
task_runner_(task_runner), |
inside_surface_damaged_(false), |
visible_(false), |
@@ -25,12 +26,9 @@ DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source, |
inside_begin_frame_deadline_interval_(false), |
needs_draw_(false), |
expecting_root_surface_damage_because_of_resize_(false), |
- all_active_child_surfaces_ready_to_draw_(false), |
pending_swaps_(0), |
max_pending_swaps_(max_pending_swaps), |
- observing_begin_frame_source_(false), |
- root_surface_damaged_(false), |
- expect_damage_from_root_surface_(false), |
+ observing_begin_frames_(false), |
weak_ptr_factory_(this) { |
begin_frame_deadline_closure_ = base::Bind( |
&DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr()); |
@@ -44,6 +42,12 @@ void DisplayScheduler::SetClient(DisplaySchedulerClient* client) { |
client_ = client; |
} |
+void DisplayScheduler::SetBeginFrameSource( |
+ DisplayBeginFrameSource* begin_frame_source) { |
+ begin_frame_source_ = begin_frame_source; |
+ begin_frame_source_->SetClient(this); |
+} |
+ |
void DisplayScheduler::SetVisible(bool visible) { |
if (visible_ == visible) |
return; |
@@ -68,14 +72,13 @@ void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) { |
void DisplayScheduler::ForceImmediateSwapIfPossible() { |
TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible"); |
bool in_begin = inside_begin_frame_deadline_interval_; |
- AttemptDrawAndSwap(); |
+ bool did_draw = AttemptDrawAndSwap(); |
if (in_begin) |
- begin_frame_source_->DidFinishFrame(this, 0); |
+ begin_frame_source_->FinishClientFrame(did_draw, needs_draw_); |
} |
void DisplayScheduler::DisplayResized() { |
expecting_root_surface_damage_because_of_resize_ = true; |
- expect_damage_from_root_surface_ = true; |
needs_draw_ = true; |
ScheduleBeginFrameDeadline(); |
} |
@@ -102,16 +105,8 @@ void DisplayScheduler::SurfaceDamaged(const SurfaceId& surface_id) { |
needs_draw_ = true; |
- if (surface_id == root_surface_id_) { |
- root_surface_damaged_ = true; |
+ if (surface_id == root_surface_id_) |
expecting_root_surface_damage_because_of_resize_ = false; |
- } else { |
- child_surface_ids_damaged_.insert(surface_id); |
- |
- // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. |
- all_active_child_surfaces_ready_to_draw_ = base::STLIncludes( |
- child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_); |
- } |
StartObservingBeginFrames(); |
ScheduleBeginFrameDeadline(); |
@@ -123,35 +118,27 @@ void DisplayScheduler::OutputSurfaceLost() { |
ScheduleBeginFrameDeadline(); |
} |
-void DisplayScheduler::DrawAndSwap() { |
+bool DisplayScheduler::DrawAndSwap() { |
TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap"); |
DCHECK_LT(pending_swaps_, max_pending_swaps_); |
DCHECK(!output_surface_lost_); |
bool success = client_->DrawAndSwap(); |
if (!success) |
- return; |
- |
- child_surface_ids_to_expect_damage_from_ = |
- base::STLSetIntersection<std::vector<SurfaceId>>( |
- child_surface_ids_damaged_, child_surface_ids_damaged_prev_); |
- |
- child_surface_ids_damaged_prev_.swap(child_surface_ids_damaged_); |
- child_surface_ids_damaged_.clear(); |
+ return false; |
needs_draw_ = false; |
- all_active_child_surfaces_ready_to_draw_ = |
- child_surface_ids_to_expect_damage_from_.empty(); |
- |
- expect_damage_from_root_surface_ = root_surface_damaged_; |
- root_surface_damaged_ = false; |
+ return true; |
} |
-bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { |
+void DisplayScheduler::OnBeginFrame(const BeginFrameArgs& args) { |
base::TimeTicks now = base::TimeTicks::Now(); |
TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(), |
"now", now); |
+ // We always use the args, even if we post a missing_begin_frame_task. |
+ last_used_begin_frame_args_ = args; |
+ |
if (inside_surface_damaged_) { |
// Repost this so that we don't run a missed BeginFrame on the same |
// callstack. Otherwise we end up running unexpected scheduler actions |
@@ -160,12 +147,12 @@ bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { |
DCHECK_EQ(args.type, BeginFrameArgs::MISSED); |
DCHECK(missed_begin_frame_task_.IsCancelled()); |
missed_begin_frame_task_.Reset(base::Bind( |
- base::IgnoreResult(&DisplayScheduler::OnBeginFrameDerivedImpl), |
+ base::IgnoreResult(&DisplayScheduler::OnBeginFrame), |
// The CancelableCallback will not run after it is destroyed, which |
// happens when |this| is destroyed. |
base::Unretained(this), args)); |
task_runner_->PostTask(FROM_HERE, missed_begin_frame_task_.callback()); |
- return true; |
+ return; |
} |
// Save the |BeginFrameArgs| as the callback (missed_begin_frame_task_) can be |
@@ -189,21 +176,24 @@ bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { |
BeginFrameArgs::DefaultEstimatedParentDrawTime(); |
inside_begin_frame_deadline_interval_ = true; |
ScheduleBeginFrameDeadline(); |
+} |
- return true; |
+const BeginFrameArgs& DisplayScheduler::LastUsedBeginFrameArgs() const { |
+ return last_used_begin_frame_args_; |
} |
void DisplayScheduler::StartObservingBeginFrames() { |
- if (!observing_begin_frame_source_ && ShouldDraw()) { |
- begin_frame_source_->AddObserver(this); |
- observing_begin_frame_source_ = true; |
+ if (!observing_begin_frames_ && |
+ (ShouldDraw() || begin_frame_source_->HasObservers())) { |
+ begin_frame_source_->SetClientNeedsBeginFrames(true); |
+ observing_begin_frames_ = true; |
} |
} |
void DisplayScheduler::StopObservingBeginFrames() { |
- if (observing_begin_frame_source_) { |
- begin_frame_source_->RemoveObserver(this); |
- observing_begin_frame_source_ = false; |
+ if (observing_begin_frames_) { |
+ begin_frame_source_->SetClientNeedsBeginFrames(false); |
+ observing_begin_frames_ = false; |
// A missed BeginFrame may be queued, so drop that too if we're going to |
// stop listening. |
@@ -217,11 +207,12 @@ bool DisplayScheduler::ShouldDraw() { |
return needs_draw_ && !output_surface_lost_ && visible_; |
} |
-void DisplayScheduler::OnBeginFrameSourcePausedChanged(bool paused) { |
- // BeginFrameSources used with DisplayScheduler do not make use of this |
- // feature. |
- if (paused) |
- NOTIMPLEMENTED(); |
+void DisplayScheduler::BeginFrameObserverStatusChanged() { |
+ // We proactively start observing if any observer requests BeginFrames to |
+ // ensure that we call FinishClientFrame() for all of the source's frames. |
+ StartObservingBeginFrames(); |
+ // Schedules an immediate deadline if all observers have responded. |
+ ScheduleBeginFrameDeadline(); |
} |
base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { |
@@ -236,7 +227,10 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { |
current_begin_frame_args_.interval; |
} |
- if (!needs_draw_) { |
+ bool observers_finished_frame = |
+ begin_frame_source_->AllObserversFinishedFrame(); |
+ |
+ if (!needs_draw_ && !observers_finished_frame) { |
TRACE_EVENT_INSTANT0("cc", "No damage yet", TRACE_EVENT_SCOPE_THREAD); |
return current_begin_frame_args_.frame_time + |
current_begin_frame_args_.interval; |
@@ -249,10 +243,8 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { |
current_begin_frame_args_.interval; |
} |
- bool root_ready_to_draw = |
- !expect_damage_from_root_surface_ || root_surface_damaged_; |
- |
- if (all_active_child_surfaces_ready_to_draw_ && root_ready_to_draw) { |
+ if (observers_finished_frame && |
+ !expecting_root_surface_damage_because_of_resize_) { |
TRACE_EVENT_INSTANT0("cc", "All active surfaces ready", |
TRACE_EVENT_SCOPE_THREAD); |
return base::TimeTicks(); |
@@ -266,27 +258,6 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { |
current_begin_frame_args_.interval; |
} |
- // Use an earlier deadline if we are only waiting for the root surface |
- // in case our expect_damage_from_root_surface heuristic is incorrect. |
- // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort |
- // logic. |
- if (all_active_child_surfaces_ready_to_draw_ && |
- expect_damage_from_root_surface_) { |
- TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface", |
- TRACE_EVENT_SCOPE_THREAD); |
- // This adjusts the deadline by DefaultEstimatedParentDrawTime for |
- // a second time. The first one represented the Surfaces draw to display |
- // latency. This one represents root surface commit+raster+draw latency. |
- // We treat the root surface differently since it lives on the same thread |
- // as Surfaces and waiting for it too long may push out the Surfaces draw. |
- // If we also assume the root surface is fast to start a commit after the |
- // beginning of a frame, it'll have a chance to lock its resources, which |
- // will cause us to wait for it to unlock its resources above. |
- // TODO(mithro): Replace hard coded estimates. |
- return current_begin_frame_args_.deadline - |
- BeginFrameArgs::DefaultEstimatedParentDrawTime(); |
- } |
- |
TRACE_EVENT_INSTANT0("cc", "More damage expected soon", |
TRACE_EVENT_SCOPE_THREAD); |
return current_begin_frame_args_.deadline; |
@@ -327,31 +298,31 @@ void DisplayScheduler::ScheduleBeginFrameDeadline() { |
"desired_deadline", desired_deadline); |
} |
-void DisplayScheduler::AttemptDrawAndSwap() { |
+bool DisplayScheduler::AttemptDrawAndSwap() { |
inside_begin_frame_deadline_interval_ = false; |
begin_frame_deadline_task_.Cancel(); |
begin_frame_deadline_task_time_ = base::TimeTicks(); |
if (ShouldDraw()) { |
if (pending_swaps_ < max_pending_swaps_ && !root_surface_resources_locked_) |
- DrawAndSwap(); |
- } else { |
+ return DrawAndSwap(); |
+ } else if (!begin_frame_source_->HasObservers()) { |
// We are going idle, so reset expectations. |
- child_surface_ids_to_expect_damage_from_.clear(); |
- child_surface_ids_damaged_prev_.clear(); |
- child_surface_ids_damaged_.clear(); |
- all_active_child_surfaces_ready_to_draw_ = true; |
- expect_damage_from_root_surface_ = false; |
+ // TODO(eseckler): Should we avoid going idle if |
+ // expecting_root_surface_damage_because_of_resize_ is true? |
+ expecting_root_surface_damage_because_of_resize_ = false; |
StopObservingBeginFrames(); |
} |
+ |
+ return false; |
} |
void DisplayScheduler::OnBeginFrameDeadline() { |
TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); |
- AttemptDrawAndSwap(); |
- begin_frame_source_->DidFinishFrame(this, 0); |
+ bool did_draw = AttemptDrawAndSwap(); |
+ begin_frame_source_->FinishClientFrame(did_draw, needs_draw_); |
} |
void DisplayScheduler::DidSwapBuffers() { |