Chromium Code Reviews| Index: cc/trees/thread_proxy.cc |
| diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc |
| index d112a7065855806883a118980d54c9ee84d5e723..cc009d59a8613045c4d53d7874e09b9457ea17d5 100644 |
| --- a/cc/trees/thread_proxy.cc |
| +++ b/cc/trees/thread_proxy.cc |
| @@ -77,6 +77,7 @@ ThreadProxy::ThreadProxy( |
| manage_tiles_pending_(false), |
| weak_factory_on_impl_thread_(this), |
| weak_factory_(this), |
| + frame_did_draw_(false), |
| begin_frame_sent_to_main_thread_completion_event_on_impl_thread_(NULL), |
| readback_request_on_impl_thread_(NULL), |
| commit_completion_event_on_impl_thread_(NULL), |
| @@ -117,63 +118,58 @@ bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { |
| return false; |
| } |
| - // Perform a synchronous commit. |
| + // Perform a synchronous commit with an associated readback. |
| + ReadbackRequest request; |
| + request.rect = rect; |
| + request.pixels = pixels; |
| { |
| DebugScopedSetMainThreadBlocked main_thread_blocked(this); |
| CompletionEvent begin_frame_sent_to_main_thread_completion; |
| Proxy::ImplThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| - base::Bind(&ThreadProxy::ForceCommitOnImplThread, |
| + base::Bind(&ThreadProxy::ForceCommitForReadbackOnImplThread, |
| impl_thread_weak_ptr_, |
| - &begin_frame_sent_to_main_thread_completion)); |
| + &begin_frame_sent_to_main_thread_completion, |
| + &request)); |
| begin_frame_sent_to_main_thread_completion.Wait(); |
| } |
| in_composite_and_readback_ = true; |
| + // This is the forced commit. |
| + // Note: The Impl thread also queues a separate BeginFrameOnMainThread on the |
| + // main thread, which will be called after this CompositeAndReadback |
| + // completes, to replace the forced commit. |
| BeginFrameOnMainThread(scoped_ptr<BeginFrameAndCommitState>()); |
| in_composite_and_readback_ = false; |
| - // Perform a synchronous readback. |
| - ReadbackRequest request; |
| - request.rect = rect; |
| - request.pixels = pixels; |
| - { |
| - DebugScopedSetMainThreadBlocked main_thread_blocked(this); |
| - Proxy::ImplThreadTaskRunner()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&ThreadProxy::RequestReadbackOnImplThread, |
|
brianderson
2013/07/18 02:02:49
This method has been made part of ForceCommitForRe
|
| - impl_thread_weak_ptr_, |
| - &request)); |
| - request.completion.Wait(); |
| - } |
| + request.completion.Wait(); |
| return request.success; |
| } |
| -void ThreadProxy::ForceCommitOnImplThread(CompletionEvent* completion) { |
| - TRACE_EVENT0("cc", "ThreadProxy::ForceCommitOnImplThread"); |
| +void ThreadProxy::ForceCommitForReadbackOnImplThread( |
| + CompletionEvent* begin_frame_sent_completion, |
| + ReadbackRequest* request) { |
| + TRACE_EVENT0("cc", "ThreadProxy::ForceCommitForReadbackOnImplThread"); |
| DCHECK(IsImplThread()); |
| DCHECK(!begin_frame_sent_to_main_thread_completion_event_on_impl_thread_); |
| - |
| - scheduler_on_impl_thread_->SetNeedsForcedCommit(); |
| - if (scheduler_on_impl_thread_->CommitPending()) { |
| - completion->Signal(); |
| - return; |
| - } |
| - |
| - begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ = completion; |
| -} |
| - |
| -void ThreadProxy::RequestReadbackOnImplThread(ReadbackRequest* request) { |
| - DCHECK(Proxy::IsImplThread()); |
| DCHECK(!readback_request_on_impl_thread_); |
| + |
| if (!layer_tree_host_impl_) { |
| + begin_frame_sent_completion->Signal(); |
| request->success = false; |
| request->completion.Signal(); |
| return; |
| } |
| readback_request_on_impl_thread_ = request; |
| - scheduler_on_impl_thread_->SetNeedsRedraw(); |
| - scheduler_on_impl_thread_->SetNeedsForcedRedraw(); |
| + |
| + scheduler_on_impl_thread_->SetNeedsForcedCommitForReadback(); |
| + if (scheduler_on_impl_thread_->CommitPending()) { |
| + begin_frame_sent_completion->Signal(); |
| + return; |
| + } |
| + |
| + begin_frame_sent_to_main_thread_completion_event_on_impl_thread_ = |
| + begin_frame_sent_completion; |
| } |
| void ThreadProxy::FinishAllRendering() { |
| @@ -373,14 +369,32 @@ void ThreadProxy::SetNeedsBeginFrameOnImplThread(bool enable) { |
| TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginFrameOnImplThread", |
| "enable", enable); |
| layer_tree_host_impl_->SetNeedsBeginFrame(enable); |
| + layer_tree_host_impl_->UpdateBackgroundAnimateTicking(!enable); |
| } |
| void ThreadProxy::BeginFrameOnImplThread(const BeginFrameArgs& args) { |
| DCHECK(IsImplThread()); |
| TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnImplThread"); |
| + |
| + base::TimeTicks monotonic_time = |
| + layer_tree_host_impl_->CurrentFrameTimeTicks(); |
| + base::Time wall_clock_time = layer_tree_host_impl_->CurrentFrameTime(); |
| + layer_tree_host_impl_->Animate(monotonic_time, wall_clock_time); |
| + |
| + // Reinitialize for the current frame. |
| + frame_did_draw_ = false; |
| + |
| scheduler_on_impl_thread_->BeginFrame(args); |
| } |
| +void ThreadProxy::DidBeginFrameDeadlineOnImplThread() { |
| + // Do not start animations if we skip drawing the frame to avoid |
| + // checkerboarding. |
| + layer_tree_host_impl_->UpdateAnimationState( |
| + frame_did_draw_ || !layer_tree_host_impl_->CanDraw()); |
| + layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); |
| +} |
| + |
| void ThreadProxy::OnCanDrawStateChanged(bool can_draw) { |
| DCHECK(IsImplThread()); |
| TRACE_EVENT1( |
| @@ -394,7 +408,17 @@ void ThreadProxy::OnHasPendingTreeStateChanged(bool has_pending_tree) { |
| DCHECK(IsImplThread()); |
| TRACE_EVENT1("cc", "ThreadProxy::OnHasPendingTreeStateChanged", |
| "has_pending_tree", has_pending_tree); |
| - scheduler_on_impl_thread_->SetHasPendingTree(has_pending_tree); |
| + scheduler_on_impl_thread_->SetHasTrees( |
| + has_pending_tree, |
| + layer_tree_host_impl_->active_tree() ? |
| + !layer_tree_host_impl_->active_tree()->root_layer() : true); |
| + |
| + if (!has_pending_tree && !deferred_start_commit_on_impl_thread_.is_null()) { |
| + Proxy::ImplThreadTaskRunner()->PostTask( |
| + FROM_HERE, |
| + deferred_start_commit_on_impl_thread_); |
| + deferred_start_commit_on_impl_thread_.Reset(); |
| + } |
| } |
| void ThreadProxy::SetNeedsCommitOnImplThread() { |
| @@ -630,6 +654,7 @@ void ThreadProxy::ScheduledActionSendBeginFrameToMainThread() { |
| TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionSendBeginFrameToMainThread"); |
| scoped_ptr<BeginFrameAndCommitState> begin_frame_state( |
| new BeginFrameAndCommitState); |
| + |
| begin_frame_state->monotonic_frame_begin_time = |
| layer_tree_host_impl_->CurrentPhysicalTimeTicks(); |
| begin_frame_state->scroll_info = |
| @@ -638,6 +663,8 @@ void ThreadProxy::ScheduledActionSendBeginFrameToMainThread() { |
| if (!layer_tree_host_impl_->settings().impl_side_painting) { |
| DCHECK_GT(layer_tree_host_impl_->memory_allocation_limit_bytes(), 0u); |
| } |
| + |
| + |
| begin_frame_state->memory_allocation_limit_bytes = |
| layer_tree_host_impl_->memory_allocation_limit_bytes(); |
| Proxy::MainThreadTaskRunner()->PostTask( |
| @@ -786,8 +813,6 @@ void ThreadProxy::StartCommitOnImplThread( |
| CompletionEvent* completion, |
| ResourceUpdateQueue* raw_queue, |
| scoped_refptr<cc::ContextProvider> offscreen_context_provider) { |
| - scoped_ptr<ResourceUpdateQueue> queue(raw_queue); |
| - |
| TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread"); |
| DCHECK(!commit_completion_event_on_impl_thread_); |
| DCHECK(IsImplThread() && IsMainThreadBlocked()); |
| @@ -797,9 +822,26 @@ void ThreadProxy::StartCommitOnImplThread( |
| if (!layer_tree_host_impl_) { |
| TRACE_EVENT0("cc", "EarlyOut_NoLayerTree"); |
| completion->Signal(); |
| + |
| + return; |
| + } |
| + |
| + // We defer forced commits while there is a pending tree here. |
|
brianderson
2013/07/18 02:02:49
This code is no longer needed to make composite an
|
| + if (layer_tree_host_impl_->pending_tree()) { |
| + NOTREACHED(); |
| + TRACE_EVENT0("cc", "EarlyOut_DeferringDueToPendingTree"); |
| + DCHECK(deferred_start_commit_on_impl_thread_.is_null()); |
| + deferred_start_commit_on_impl_thread_ = |
| + base::Bind(&ThreadProxy::StartCommitOnImplThread, |
| + impl_thread_weak_ptr_, |
| + completion, |
| + raw_queue, |
| + offscreen_context_provider); |
| return; |
| } |
| + scoped_ptr<ResourceUpdateQueue> queue(raw_queue); |
| + |
| if (offscreen_context_provider.get()) |
| offscreen_context_provider->BindToCurrentThread(); |
| layer_tree_host_impl_->resource_provider()-> |
| @@ -855,9 +897,6 @@ void ThreadProxy::ScheduledActionCommit() { |
| layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get()); |
| layer_tree_host_impl_->CommitComplete(); |
| - layer_tree_host_impl_->UpdateBackgroundAnimateTicking( |
| - !scheduler_on_impl_thread_->WillDrawIfNeeded()); |
| - |
| next_frame_is_newly_committed_frame_on_impl_thread_ = true; |
| if (layer_tree_host_->settings().impl_side_painting && |
| @@ -879,6 +918,10 @@ void ThreadProxy::ScheduledActionCommit() { |
| begin_frame_to_commit_duration_history_.InsertSample( |
| commit_complete_time_ - begin_frame_sent_to_main_thread_time_); |
| + // The commit may have added animations, requiring us to start |
| + // background ticking. |
| + layer_tree_host_impl_->UpdateBackgroundAnimateTicking( |
| + !scheduler_on_impl_thread_->WillDrawIfNeeded()); |
| // SetVisible kicks off the next scheduler action, so this must be last. |
| scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); |
| } |
| @@ -904,11 +947,12 @@ void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { |
| main_thread_weak_ptr_)); |
| } |
| -ScheduledActionDrawAndSwapResult |
| -ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { |
| +DrawSwapReadbackResult |
| +ThreadProxy::ScheduledActionDrawSwapReadbackInternal( |
| + bool forced_draw, bool swap_requested, bool readback_requested) { |
| TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap"); |
| - ScheduledActionDrawAndSwapResult result; |
| + DrawSwapReadbackResult result; |
| result.did_draw = false; |
| result.did_swap = false; |
| DCHECK(IsImplThread()); |
| @@ -920,19 +964,6 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { |
| if (!layer_tree_host_impl_->renderer()) |
| return result; |
| - base::TimeTicks monotonic_time = |
| - layer_tree_host_impl_->CurrentFrameTimeTicks(); |
| - base::Time wall_clock_time = layer_tree_host_impl_->CurrentFrameTime(); |
| - |
| - // TODO(enne): This should probably happen post-animate. |
| - if (layer_tree_host_impl_->pending_tree()) { |
| - layer_tree_host_impl_->ActivatePendingTreeIfNeeded(); |
| - if (layer_tree_host_impl_->pending_tree()) |
| - layer_tree_host_impl_->pending_tree()->UpdateDrawProperties(); |
| - } |
| - layer_tree_host_impl_->Animate(monotonic_time, wall_clock_time); |
| - layer_tree_host_impl_->UpdateBackgroundAnimateTicking(false); |
| - |
| base::TimeTicks start_time = base::TimeTicks::HighResNow(); |
| base::TimeDelta draw_duration_estimate = DrawDurationEstimate(); |
| base::AutoReset<bool> mark_inside(&inside_draw_, true); |
| @@ -948,12 +979,12 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { |
| // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on |
| // CanDraw() as well. |
| - bool drawing_for_readback = !!readback_request_on_impl_thread_; |
| + bool drawing_for_readback = |
| + readback_requested && !!readback_request_on_impl_thread_; |
| bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels(); |
| LayerTreeHostImpl::FrameData frame; |
| bool draw_frame = false; |
| - bool start_ready_animations = true; |
| if (layer_tree_host_impl_->CanDraw() && |
| (!drawing_for_readback || can_do_readback)) { |
| @@ -962,15 +993,13 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { |
| if (drawing_for_readback) |
| readback_rect = readback_request_on_impl_thread_->rect; |
| - // Do not start animations if we skip drawing the frame to avoid |
| - // checkerboarding. |
| if (layer_tree_host_impl_->PrepareToDraw(&frame, readback_rect) || |
| forced_draw) |
| draw_frame = true; |
| - else |
| - start_ready_animations = false; |
| } |
| + frame_did_draw_ = draw_frame; |
| + |
| if (draw_frame) { |
| layer_tree_host_impl_->DrawLayers( |
| &frame, |
| @@ -979,20 +1008,19 @@ ThreadProxy::ScheduledActionDrawAndSwapInternal(bool forced_draw) { |
| } |
| layer_tree_host_impl_->DidDrawAllLayers(frame); |
| - layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); |
| - |
| // Check for a pending CompositeAndReadback. |
| - if (readback_request_on_impl_thread_) { |
| - readback_request_on_impl_thread_->success = false; |
| + if (drawing_for_readback) { |
| + result.did_readback = false; |
| if (draw_frame) { |
| layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels, |
| readback_request_on_impl_thread_->rect); |
| - readback_request_on_impl_thread_->success = |
| + result.did_readback = |
| !layer_tree_host_impl_->IsContextLost(); |
| } |
| + readback_request_on_impl_thread_->success = result.did_readback; |
| readback_request_on_impl_thread_->completion.Signal(); |
| readback_request_on_impl_thread_ = NULL; |
| - } else if (draw_frame) { |
| + } else if (draw_frame && swap_requested) { |
| result.did_swap = layer_tree_host_impl_->SwapBuffers(frame); |
| if (frame.contains_incomplete_tile) |
| @@ -1084,21 +1112,38 @@ void ThreadProxy::ScheduledActionAcquireLayerTexturesForMainThread() { |
| texture_acquisition_completion_event_on_impl_thread_ = NULL; |
| } |
| -ScheduledActionDrawAndSwapResult |
| +DrawSwapReadbackResult |
| ThreadProxy::ScheduledActionDrawAndSwapIfPossible() { |
| - return ScheduledActionDrawAndSwapInternal(false); |
| + bool forced_draw = false; |
| + bool swap_requested = true; |
| + bool readback_requested = false; |
| + return ScheduledActionDrawSwapReadbackInternal( |
| + forced_draw, swap_requested, readback_requested); |
| } |
| -ScheduledActionDrawAndSwapResult |
| +DrawSwapReadbackResult |
| ThreadProxy::ScheduledActionDrawAndSwapForced() { |
| - return ScheduledActionDrawAndSwapInternal(true); |
| + bool forced_draw = true; |
| + bool swap_requested = true; |
| + bool readback_requested = false; |
| + return ScheduledActionDrawSwapReadbackInternal( |
| + forced_draw, swap_requested, readback_requested); |
| +} |
| + |
| +DrawSwapReadbackResult |
| +ThreadProxy::ScheduledActionDrawAndReadback() { |
| + bool forced_draw = true; |
| + bool swap_requested = false; |
| + bool readback_requested = true; |
| + return ScheduledActionDrawSwapReadbackInternal( |
| + forced_draw, swap_requested, readback_requested); |
| } |
| + |
| void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { |
| if (current_resource_update_controller_on_impl_thread_) |
| current_resource_update_controller_on_impl_thread_ |
| ->PerformMoreUpdates(time); |
| - layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); |
| } |
| base::TimeDelta ThreadProxy::DrawDurationEstimate() { |
| @@ -1119,6 +1164,14 @@ base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() { |
| kCommitAndActivationDurationEstimationPercentile); |
| } |
| +void ThreadProxy::PostBeginFrameDeadline(const base::Closure &closure, |
| + base::TimeTicks deadline) { |
| + base::TimeDelta delta = deadline - base::TimeTicks::Now(); |
| + if (delta <= base::TimeDelta()) |
| + delta = base::TimeDelta(); |
| + Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, closure, delta); |
| +} |
| + |
| void ThreadProxy::ReadyToFinalizeTextureUpdates() { |
| DCHECK(IsImplThread()); |
| scheduler_on_impl_thread_->FinishCommit(); |
| @@ -1196,6 +1249,7 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { |
| settings.using_synchronous_renderer_compositor; |
| scheduler_settings.throttle_frame_production = |
| settings.throttle_frame_production; |
| + scheduler_settings.use_begin_frame_workaround_for_crbug_249806 = true; |
| scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings); |
| scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); |