diff options
author | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-06 10:16:40 +0000 |
---|---|---|
committer | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-06 10:16:40 +0000 |
commit | f418ec05d5e2187ce266b2b407755bc01db3acb9 (patch) | |
tree | 409da27072bd85fb7569a35361c6fe9e6871187d /cc/trees/single_thread_proxy.cc | |
parent | bb056f59f212a77760a7d508b6417c62d869d201 (diff) | |
download | chromium_src-f418ec05d5e2187ce266b2b407755bc01db3acb9.zip chromium_src-f418ec05d5e2187ce266b2b407755bc01db3acb9.tar.gz chromium_src-f418ec05d5e2187ce266b2b407755bc01db3acb9.tar.bz2 |
Make SingleThreadProxy a SchedulerClient
This makes ui::Compositor no longer in charge of
scheduling commits and draws, deferring it to cc::Scheduler.
Other compositors that use SingleThreadProxy are left calling composite
synchronously and now pass a flag to indicate that this is their
intention. This patch doesn't remove synchronous composite, but now
makes it mutually exclusive with scheduling.
BUG=329552, 287250
Review URL: https://codereview.chromium.org/134623005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287747 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/trees/single_thread_proxy.cc')
-rw-r--r-- | cc/trees/single_thread_proxy.cc | 341 |
1 files changed, 273 insertions, 68 deletions
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 2f67740..fe9c34f8 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc @@ -36,8 +36,13 @@ SingleThreadProxy::SingleThreadProxy( : Proxy(main_task_runner, NULL), layer_tree_host_(layer_tree_host), client_(client), + timing_history_(layer_tree_host->rendering_stats_instrumentation()), next_frame_is_newly_committed_frame_(false), - inside_draw_(false) { + inside_draw_(false), + defer_commits_(false), + commit_was_deferred_(false), + commit_requested_(false), + weak_factory_(this) { TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy"); DCHECK(Proxy::IsMainThread()); DCHECK(layer_tree_host); @@ -77,13 +82,26 @@ void SingleThreadProxy::SetLayerTreeHostClientReady() { TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady"); // Scheduling is controlled by the embedder in the single thread case, so // nothing to do. + DCHECK(Proxy::IsMainThread()); + DebugScopedSetImplThread impl(this); + if (layer_tree_host_->settings().single_thread_proxy_scheduler && + !scheduler_on_impl_thread_) { + SchedulerSettings scheduler_settings(layer_tree_host_->settings()); + scheduler_on_impl_thread_ = Scheduler::Create(this, + scheduler_settings, + layer_tree_host_->id(), + MainThreadTaskRunner()); + scheduler_on_impl_thread_->SetCanStart(); + scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); + } } void SingleThreadProxy::SetVisible(bool visible) { TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible"); DebugScopedSetImplThread impl(this); layer_tree_host_impl_->SetVisible(visible); - + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); // Changing visibility could change ShouldComposite(). UpdateBackgroundAnimateTicking(); } @@ -110,9 +128,14 @@ void SingleThreadProxy::CreateAndInitializeOutputSurface() { layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success); - if (!success) { - // Force another recreation attempt to happen by requesting another commit. - SetNeedsCommit(); + if (success) { + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface(); + } else if (Proxy::MainThreadTaskRunner()) { + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&SingleThreadProxy::CreateAndInitializeOutputSurface, + weak_factory_.GetWeakPtr())); } } @@ -126,17 +149,40 @@ void SingleThreadProxy::SetNeedsAnimate() { TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate"); DCHECK(Proxy::IsMainThread()); client_->ScheduleAnimation(); + SetNeedsCommit(); } void SingleThreadProxy::SetNeedsUpdateLayers() { TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers"); DCHECK(Proxy::IsMainThread()); - client_->ScheduleComposite(); + SetNeedsCommit(); } -void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { +void SingleThreadProxy::DoCommit(base::TimeTicks frame_begin_time) { TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit"); DCHECK(Proxy::IsMainThread()); + layer_tree_host_->WillBeginMainFrame(); + layer_tree_host_->UpdateClientAnimations(frame_begin_time); + layer_tree_host_->AnimateLayers(frame_begin_time); + layer_tree_host_->Layout(); + commit_requested_ = false; + + if (PrioritizedResourceManager* contents_texture_manager = + layer_tree_host_->contents_texture_manager()) { + contents_texture_manager->UnlinkAndClearEvictedBackings(); + contents_texture_manager->SetMaxMemoryLimitBytes( + layer_tree_host_impl_->memory_allocation_limit_bytes()); + contents_texture_manager->SetExternalPriorityCutoff( + layer_tree_host_impl_->memory_allocation_priority_cutoff()); + } + + scoped_ptr<ResourceUpdateQueue> queue = + make_scoped_ptr(new ResourceUpdateQueue); + + layer_tree_host_->UpdateLayers(queue.get()); + + layer_tree_host_->WillCommit(); + // Commit immediately. { DebugScopedSetMainThreadBlocked main_thread_blocked(this); @@ -158,7 +204,7 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { scoped_ptr<ResourceUpdateController> update_controller = ResourceUpdateController::Create( NULL, - Proxy::MainThreadTaskRunner(), + MainThreadTaskRunner(), queue.Pass(), layer_tree_host_impl_->resource_provider()); update_controller->Finalize(); @@ -170,6 +216,8 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { layer_tree_host_impl_->CommitComplete(); + UpdateBackgroundAnimateTicking(); + #if DCHECK_IS_ON // In the single-threaded case, the scale and scroll deltas should never be // touched on the impl layer tree. @@ -186,30 +234,64 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { stats_instrumentation->AccumulateAndClearMainThreadStats(); } layer_tree_host_->CommitComplete(); + layer_tree_host_->DidBeginMainFrame(); + timing_history_.DidCommit(); + next_frame_is_newly_committed_frame_ = true; } void SingleThreadProxy::SetNeedsCommit() { DCHECK(Proxy::IsMainThread()); + DebugScopedSetImplThread impl(this); client_->ScheduleComposite(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetNeedsCommit(); + commit_requested_ = true; } void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw"); - SetNeedsRedrawRectOnImplThread(damage_rect); + DCHECK(Proxy::IsMainThread()); + DebugScopedSetImplThread impl(this); client_->ScheduleComposite(); + SetNeedsRedrawRectOnImplThread(damage_rect); } void SingleThreadProxy::SetNextCommitWaitsForActivation() { // There is no activation here other than commit. So do nothing. + DCHECK(Proxy::IsMainThread()); } void SingleThreadProxy::SetDeferCommits(bool defer_commits) { + DCHECK(Proxy::IsMainThread()); + // Deferring commits only makes sense if there's a scheduler. + if (!scheduler_on_impl_thread_) + return; + if (defer_commits_ == defer_commits) + return; + + if (defer_commits) + TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this); + else + TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this); + + defer_commits_ = defer_commits; + if (!defer_commits_ && commit_was_deferred_) { + scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(); + scheduler_on_impl_thread_->NotifyReadyToCommit(); + commit_was_deferred_ = false; + } } -bool SingleThreadProxy::CommitRequested() const { return false; } +bool SingleThreadProxy::CommitRequested() const { + DCHECK(Proxy::IsMainThread()); + return commit_requested_; +} -bool SingleThreadProxy::BeginMainFrameRequested() const { return false; } +bool SingleThreadProxy::BeginMainFrameRequested() const { + DCHECK(Proxy::IsMainThread()); + return commit_requested_; +} size_t SingleThreadProxy::MaxPartialTextureUpdates() const { return std::numeric_limits<size_t>::max(); @@ -225,6 +307,7 @@ void SingleThreadProxy::Stop() { BlockingTaskRunner::CapturePostTasks blocked; layer_tree_host_->DeleteContentsTexturesOnImplThread( layer_tree_host_impl_->resource_provider()); + scheduler_on_impl_thread_.reset(); layer_tree_host_impl_.reset(); } layer_tree_host_ = NULL; @@ -235,15 +318,19 @@ void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) { "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); DCHECK(Proxy::IsImplThread()); UpdateBackgroundAnimateTicking(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetCanDraw(can_draw); } void SingleThreadProxy::NotifyReadyToActivate() { - // Thread-only feature. + // Impl-side painting only. NOTREACHED(); } void SingleThreadProxy::SetNeedsRedrawOnImplThread() { client_->ScheduleComposite(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetNeedsRedraw(); } void SingleThreadProxy::SetNeedsAnimateOnImplThread() { @@ -251,17 +338,14 @@ void SingleThreadProxy::SetNeedsAnimateOnImplThread() { } void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { - // Thread-only/Impl-side-painting-only feature. + // Impl-side painting only. NOTREACHED(); } void SingleThreadProxy::SetNeedsRedrawRectOnImplThread( const gfx::Rect& damage_rect) { - // TODO(brianderson): Once we move render_widget scheduling into this class, - // we can treat redraw requests more efficiently than CommitAndRedraw - // requests. layer_tree_host_impl_->SetViewportDamage(damage_rect); - SetNeedsCommit(); + SetNeedsRedrawOnImplThread(); } void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { @@ -271,6 +355,8 @@ void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { void SingleThreadProxy::SetNeedsCommitOnImplThread() { client_->ScheduleComposite(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetNeedsCommit(); } void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread( @@ -307,66 +393,53 @@ void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() { layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities(); } +void SingleThreadProxy::DidManageTiles() { + // Impl-side painting only. + NOTREACHED(); +} + void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() { TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread"); - // Cause a commit so we can notice the lost context. - SetNeedsCommitOnImplThread(); + { + DebugScopedSetMainThread main(this); + // This must happen before we notify the scheduler as it may try to recreate + // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE. + layer_tree_host_->DidLoseOutputSurface(); + } client_->DidAbortSwapBuffers(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidLoseOutputSurface(); } void SingleThreadProxy::DidSwapBuffersOnImplThread() { + TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread"); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidSwapBuffers(); client_->DidPostSwapBuffers(); } void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() { TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread"); - client_->DidCompleteSwapBuffers(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidSwapBuffersComplete(); + layer_tree_host_->DidCompleteSwapBuffers(); +} + +void SingleThreadProxy::BeginFrame(const BeginFrameArgs& args) { + TRACE_EVENT0("cc", "SingleThreadProxy::BeginFrame"); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->BeginImplFrame(args); } -// Called by the legacy scheduling path (e.g. where render_widget does the -// scheduling) void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately"); DCHECK(Proxy::IsMainThread()); DCHECK(!layer_tree_host_->output_surface_lost()); - layer_tree_host_->AnimateLayers(frame_begin_time); - - if (PrioritizedResourceManager* contents_texture_manager = - layer_tree_host_->contents_texture_manager()) { - contents_texture_manager->UnlinkAndClearEvictedBackings(); - contents_texture_manager->SetMaxMemoryLimitBytes( - layer_tree_host_impl_->memory_allocation_limit_bytes()); - contents_texture_manager->SetExternalPriorityCutoff( - layer_tree_host_impl_->memory_allocation_priority_cutoff()); - } - - scoped_ptr<ResourceUpdateQueue> queue = - make_scoped_ptr(new ResourceUpdateQueue); - layer_tree_host_->UpdateLayers(queue.get()); - layer_tree_host_->WillCommit(); - DoCommit(queue.Pass()); - layer_tree_host_->DidBeginMainFrame(); + DoCommit(frame_begin_time); LayerTreeHostImpl::FrameData frame; - if (DoComposite(frame_begin_time, &frame)) { - { - DebugScopedSetMainThreadBlocked main_thread_blocked(this); - DebugScopedSetImplThread impl(this); - - // This CapturePostTasks should be destroyed before - // DidCommitAndDrawFrame() is called since that goes out to the embedder, - // and we want the embedder to receive its callbacks before that. - // NOTE: This maintains consistent ordering with the ThreadProxy since - // the DidCommitAndDrawFrame() must be post-tasked from the impl thread - // there as the main thread is not blocked, so any posted tasks inside - // the swap buffers will execute first. - BlockingTaskRunner::CapturePostTasks blocked; - - layer_tree_host_impl_->SwapBuffers(frame); - } - DidSwapFrame(); - } + DoComposite(frame_begin_time, &frame); } void SingleThreadProxy::AsValueInto(base::debug::TracedValue* state) const { @@ -406,13 +479,11 @@ void SingleThreadProxy::UpdateBackgroundAnimateTicking() { !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer()); } -bool SingleThreadProxy::DoComposite( - base::TimeTicks frame_begin_time, - LayerTreeHostImpl::FrameData* frame) { +DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time, + LayerTreeHostImpl::FrameData* frame) { TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite"); DCHECK(!layer_tree_host_->output_surface_lost()); - bool lost_output_surface = false; { DebugScopedSetImplThread impl(this); base::AutoReset<bool> mark_inside(&inside_draw_, true); @@ -423,9 +494,11 @@ bool SingleThreadProxy::DoComposite( // CanDraw() as well. if (!ShouldComposite()) { UpdateBackgroundAnimateTicking(); - return false; + return DRAW_ABORTED_CANT_DRAW; } + timing_history_.DidStartDrawing(); + layer_tree_host_impl_->Animate( layer_tree_host_impl_->CurrentFrameTimeTicks()); UpdateBackgroundAnimateTicking(); @@ -435,24 +508,43 @@ bool SingleThreadProxy::DoComposite( layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); layer_tree_host_impl_->DidDrawAllLayers(*frame); } - lost_output_surface = layer_tree_host_impl_->IsContextLost(); bool start_ready_animations = true; layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); + + timing_history_.DidFinishDrawing(); } - if (lost_output_surface) { - layer_tree_host_->DidLoseOutputSurface(); - return false; + { + DebugScopedSetImplThread impl(this); + + if (layer_tree_host_impl_->IsContextLost()) { + DidLoseOutputSurfaceOnImplThread(); + } else { + // This CapturePostTasks should be destroyed before + // DidCommitAndDrawFrame() is called since that goes out to the + // embedder, + // and we want the embedder to receive its callbacks before that. + // NOTE: This maintains consistent ordering with the ThreadProxy since + // the DidCommitAndDrawFrame() must be post-tasked from the impl thread + // there as the main thread is not blocked, so any posted tasks inside + // the swap buffers will execute first. + DebugScopedSetMainThreadBlocked main_thread_blocked(this); + + BlockingTaskRunner::CapturePostTasks blocked; + layer_tree_host_impl_->SwapBuffers(*frame); + } } + DidCommitAndDrawFrame(); - return true; + return DRAW_SUCCESS; } -void SingleThreadProxy::DidSwapFrame() { +void SingleThreadProxy::DidCommitAndDrawFrame() { if (next_frame_is_newly_committed_frame_) { + DebugScopedSetMainThread main(this); next_frame_is_newly_committed_frame_ = false; layer_tree_host_->DidCommitAndDrawFrame(); } @@ -460,4 +552,117 @@ void SingleThreadProxy::DidSwapFrame() { bool SingleThreadProxy::CommitPendingForTesting() { return false; } +void SingleThreadProxy::SetNeedsBeginFrame(bool enable) { + layer_tree_host_impl_->SetNeedsBeginFrame(enable); +} + +void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { + layer_tree_host_impl_->WillBeginImplFrame(args); +} + +void SingleThreadProxy::ScheduledActionSendBeginMainFrame() { + TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame"); + // Although this proxy is single-threaded, it's problematic to synchronously + // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame. This + // could cause a commit to occur in between a series of SetNeedsCommit calls + // (i.e. property modifications) causing some to fall on one frame and some to + // fall on the next. Doing it asynchronously instead matches the semantics of + // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a + // synchronous commit. + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&SingleThreadProxy::BeginMainFrame, + weak_factory_.GetWeakPtr())); +} + +void SingleThreadProxy::BeginMainFrame() { + if (defer_commits_) { + DCHECK(!commit_was_deferred_); + commit_was_deferred_ = true; + layer_tree_host_->DidDeferCommit(); + return; + } + timing_history_.DidBeginMainFrame(); + + DCHECK(scheduler_on_impl_thread_); + scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(); + scheduler_on_impl_thread_->NotifyReadyToCommit(); +} + +DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() { + DebugScopedSetImplThread impl(this); + if (layer_tree_host_impl_->IsContextLost()) { + DidCommitAndDrawFrame(); + return DRAW_SUCCESS; + } + + LayerTreeHostImpl::FrameData frame; + return DoComposite(layer_tree_host_impl_->CurrentFrameTimeTicks(), &frame); +} + +DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapForced() { + NOTREACHED(); + return INVALID_RESULT; +} + +void SingleThreadProxy::ScheduledActionCommit() { + DebugScopedSetMainThread main(this); + DoCommit(layer_tree_host_impl_->CurrentFrameTimeTicks()); +} + +void SingleThreadProxy::ScheduledActionAnimate() { + TRACE_EVENT0("cc", "ScheduledActionAnimate"); + layer_tree_host_impl_->Animate( + layer_tree_host_impl_->CurrentFrameTimeTicks()); +} + +void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() { + // Impl-side painting only. + NOTREACHED(); +} + +void SingleThreadProxy::ScheduledActionActivateSyncTree() { +} + +void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { + DebugScopedSetMainThread main(this); + DCHECK(scheduler_on_impl_thread_); + // If possible, create the output surface in a post task. Synchronously + // creating the output surface makes tests more awkward since this differs + // from the ThreadProxy behavior. However, sometimes there is no + // task runner. + if (Proxy::MainThreadTaskRunner()) { + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&SingleThreadProxy::CreateAndInitializeOutputSurface, + weak_factory_.GetWeakPtr())); + } else { + CreateAndInitializeOutputSurface(); + } +} + +void SingleThreadProxy::ScheduledActionManageTiles() { + // Impl-side painting only. + NOTREACHED(); +} + +void SingleThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { +} + +base::TimeDelta SingleThreadProxy::DrawDurationEstimate() { + return timing_history_.DrawDurationEstimate(); +} + +base::TimeDelta SingleThreadProxy::BeginMainFrameToCommitDurationEstimate() { + return timing_history_.BeginMainFrameToCommitDurationEstimate(); +} + +base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() { + return timing_history_.CommitToActivateDurationEstimate(); +} + +void SingleThreadProxy::DidBeginImplFrameDeadline() { + layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); +} + } // namespace cc |