| Index: cc/trees/proxy_main.cc
|
| diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dd5ac1afe5e6784188386ddec36905c46af43d1d
|
| --- /dev/null
|
| +++ b/cc/trees/proxy_main.cc
|
| @@ -0,0 +1,465 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "cc/trees/proxy_main.h"
|
| +
|
| +#include <algorithm>
|
| +#include <string>
|
| +
|
| +#include "base/trace_event/trace_event.h"
|
| +#include "base/trace_event/trace_event_argument.h"
|
| +#include "base/trace_event/trace_event_synthetic_delay.h"
|
| +#include "cc/debug/benchmark_instrumentation.h"
|
| +#include "cc/debug/devtools_instrumentation.h"
|
| +#include "cc/output/output_surface.h"
|
| +#include "cc/output/swap_promise.h"
|
| +#include "cc/trees/blocking_task_runner.h"
|
| +#include "cc/trees/layer_tree_host.h"
|
| +#include "cc/trees/scoped_abort_remaining_swap_promises.h"
|
| +#include "cc/trees/threaded_channel.h"
|
| +
|
| +namespace cc {
|
| +
|
| +scoped_ptr<ProxyMain> ProxyMain::CreateThreaded(
|
| + LayerTreeHost* layer_tree_host,
|
| + TaskRunnerProvider* task_runner_provider,
|
| + scoped_ptr<BeginFrameSource> external_begin_frame_source) {
|
| + scoped_ptr<ProxyMain> proxy_main(
|
| + new ProxyMain(layer_tree_host, task_runner_provider,
|
| + std::move(external_begin_frame_source)));
|
| + proxy_main->SetChannel(
|
| + ThreadedChannel::Create(proxy_main.get(), task_runner_provider));
|
| + return proxy_main;
|
| +}
|
| +
|
| +ProxyMain::ProxyMain(LayerTreeHost* layer_tree_host,
|
| + TaskRunnerProvider* task_runner_provider,
|
| + scoped_ptr<BeginFrameSource> external_begin_frame_source)
|
| + : layer_tree_host_(layer_tree_host),
|
| + task_runner_provider_(task_runner_provider),
|
| + layer_tree_host_id_(layer_tree_host->id()),
|
| + max_requested_pipeline_stage_(NO_PIPELINE_STAGE),
|
| + current_pipeline_stage_(NO_PIPELINE_STAGE),
|
| + final_pipeline_stage_(NO_PIPELINE_STAGE),
|
| + commit_waits_for_activation_(false),
|
| + started_(false),
|
| + defer_commits_(false),
|
| + external_begin_frame_source_(std::move(external_begin_frame_source)) {
|
| + TRACE_EVENT0("cc", "ProxyMain::ProxyMain");
|
| + DCHECK(task_runner_provider_);
|
| + DCHECK(IsMainThread());
|
| + DCHECK(!layer_tree_host_->settings().use_external_begin_frame_source ||
|
| + external_begin_frame_source_);
|
| +}
|
| +
|
| +ProxyMain::~ProxyMain() {
|
| + TRACE_EVENT0("cc", "ProxyMain::~ProxyMain");
|
| + DCHECK(IsMainThread());
|
| + DCHECK(!started_);
|
| +}
|
| +
|
| +void ProxyMain::SetChannel(scoped_ptr<ChannelMain> channel_main) {
|
| + DCHECK(!channel_main_);
|
| + channel_main_ = std::move(channel_main);
|
| +}
|
| +
|
| +void ProxyMain::DidCompleteSwapBuffers() {
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->DidCompleteSwapBuffers();
|
| +}
|
| +
|
| +void ProxyMain::SetRendererCapabilities(
|
| + const RendererCapabilities& capabilities) {
|
| + DCHECK(IsMainThread());
|
| + renderer_capabilities_ = capabilities;
|
| +}
|
| +
|
| +void ProxyMain::BeginMainFrameNotExpectedSoon() {
|
| + TRACE_EVENT0("cc", "ProxyMain::BeginMainFrameNotExpectedSoon");
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->BeginMainFrameNotExpectedSoon();
|
| +}
|
| +
|
| +void ProxyMain::DidCommitAndDrawFrame() {
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->DidCommitAndDrawFrame();
|
| +}
|
| +
|
| +void ProxyMain::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) {
|
| + TRACE_EVENT0("cc", "ProxyMain::SetAnimationEvents");
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->SetAnimationEvents(std::move(events));
|
| +}
|
| +
|
| +void ProxyMain::DidLoseOutputSurface() {
|
| + TRACE_EVENT0("cc", "ProxyMain::DidLoseOutputSurface");
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->DidLoseOutputSurface();
|
| +}
|
| +
|
| +void ProxyMain::RequestNewOutputSurface() {
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->RequestNewOutputSurface();
|
| +}
|
| +
|
| +void ProxyMain::DidInitializeOutputSurface(
|
| + bool success,
|
| + const RendererCapabilities& capabilities) {
|
| + TRACE_EVENT0("cc", "ProxyMain::DidInitializeOutputSurface");
|
| + DCHECK(IsMainThread());
|
| +
|
| + if (!success) {
|
| + layer_tree_host_->DidFailToInitializeOutputSurface();
|
| + return;
|
| + }
|
| + renderer_capabilities_ = capabilities;
|
| + layer_tree_host_->DidInitializeOutputSurface();
|
| +}
|
| +
|
| +void ProxyMain::DidCompletePageScaleAnimation() {
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->DidCompletePageScaleAnimation();
|
| +}
|
| +
|
| +void ProxyMain::PostFrameTimingEventsOnMain(
|
| + scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
|
| + scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
|
| + DCHECK(IsMainThread());
|
| + layer_tree_host_->RecordFrameTimingEvents(std::move(composite_events),
|
| + std::move(main_frame_events));
|
| +}
|
| +
|
| +void ProxyMain::BeginMainFrame(
|
| + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
|
| + benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
|
| + benchmark_instrumentation::kDoBeginFrame,
|
| + begin_main_frame_state->begin_frame_id);
|
| +
|
| + base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now();
|
| +
|
| + TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame");
|
| + DCHECK(IsMainThread());
|
| + DCHECK_EQ(NO_PIPELINE_STAGE, current_pipeline_stage_);
|
| +
|
| + if (defer_commits_) {
|
| + TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + channel_main_->BeginMainFrameAbortedOnImpl(
|
| + CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT,
|
| + begin_main_frame_start_time);
|
| + return;
|
| + }
|
| +
|
| + // If the commit finishes, LayerTreeHost will transfer its swap promises to
|
| + // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the
|
| + // remaining swap promises.
|
| + ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_);
|
| +
|
| + final_pipeline_stage_ = max_requested_pipeline_stage_;
|
| + max_requested_pipeline_stage_ = NO_PIPELINE_STAGE;
|
| +
|
| + if (!layer_tree_host_->visible()) {
|
| + TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
|
| + channel_main_->BeginMainFrameAbortedOnImpl(
|
| + CommitEarlyOutReason::ABORTED_NOT_VISIBLE, begin_main_frame_start_time);
|
| + return;
|
| + }
|
| +
|
| + if (layer_tree_host_->output_surface_lost()) {
|
| + TRACE_EVENT_INSTANT0("cc", "EarlyOut_OutputSurfaceLost",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + channel_main_->BeginMainFrameAbortedOnImpl(
|
| + CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST,
|
| + begin_main_frame_start_time);
|
| + return;
|
| + }
|
| +
|
| + current_pipeline_stage_ = ANIMATE_PIPELINE_STAGE;
|
| +
|
| + layer_tree_host_->ApplyScrollAndScale(
|
| + begin_main_frame_state->scroll_info.get());
|
| +
|
| + layer_tree_host_->WillBeginMainFrame();
|
| +
|
| + layer_tree_host_->BeginMainFrame(begin_main_frame_state->begin_frame_args);
|
| + layer_tree_host_->AnimateLayers(
|
| + begin_main_frame_state->begin_frame_args.frame_time);
|
| +
|
| + // Recreate all UI resources if there were evicted UI resources when the impl
|
| + // thread initiated the commit.
|
| + if (begin_main_frame_state->evicted_ui_resources)
|
| + layer_tree_host_->RecreateUIResources();
|
| +
|
| + layer_tree_host_->RequestMainFrameUpdate();
|
| + TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame");
|
| +
|
| + bool can_cancel_this_commit = final_pipeline_stage_ < COMMIT_PIPELINE_STAGE &&
|
| + !begin_main_frame_state->evicted_ui_resources;
|
| +
|
| + current_pipeline_stage_ = UPDATE_LAYERS_PIPELINE_STAGE;
|
| + bool should_update_layers =
|
| + final_pipeline_stage_ >= UPDATE_LAYERS_PIPELINE_STAGE;
|
| + bool updated = should_update_layers && layer_tree_host_->UpdateLayers();
|
| +
|
| + layer_tree_host_->WillCommit();
|
| + devtools_instrumentation::ScopedCommitTrace commit_task(
|
| + layer_tree_host_->id());
|
| +
|
| + current_pipeline_stage_ = COMMIT_PIPELINE_STAGE;
|
| + if (!updated && can_cancel_this_commit) {
|
| + TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD);
|
| + channel_main_->BeginMainFrameAbortedOnImpl(
|
| + CommitEarlyOutReason::FINISHED_NO_UPDATES, begin_main_frame_start_time);
|
| +
|
| + // Although the commit is internally aborted, this is because it has been
|
| + // detected to be a no-op. From the perspective of an embedder, this commit
|
| + // went through, and input should no longer be throttled, etc.
|
| + current_pipeline_stage_ = NO_PIPELINE_STAGE;
|
| + layer_tree_host_->CommitComplete();
|
| + layer_tree_host_->DidBeginMainFrame();
|
| + layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE);
|
| + return;
|
| + }
|
| +
|
| + // Notify the impl thread that the main thread is ready to commit. This will
|
| + // begin the commit process, which is blocking from the main thread's
|
| + // point of view, but asynchronously performed on the impl thread,
|
| + // coordinated by the Scheduler.
|
| + {
|
| + TRACE_EVENT0("cc", "ProxyMain::BeginMainFrame::commit");
|
| +
|
| + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
|
| +
|
| + // This CapturePostTasks should be destroyed before CommitComplete() is
|
| + // called since that goes out to the embedder, and we want the embedder
|
| + // to receive its callbacks before that.
|
| + BlockingTaskRunner::CapturePostTasks blocked(
|
| + task_runner_provider_->blocking_main_thread_task_runner());
|
| +
|
| + bool hold_commit_for_activation = commit_waits_for_activation_;
|
| + commit_waits_for_activation_ = false;
|
| + CompletionEvent completion;
|
| + channel_main_->StartCommitOnImpl(&completion, layer_tree_host_,
|
| + begin_main_frame_start_time,
|
| + hold_commit_for_activation);
|
| + completion.Wait();
|
| + }
|
| +
|
| + current_pipeline_stage_ = NO_PIPELINE_STAGE;
|
| + layer_tree_host_->CommitComplete();
|
| + layer_tree_host_->DidBeginMainFrame();
|
| +}
|
| +
|
| +void ProxyMain::FinishAllRendering() {
|
| + DCHECK(IsMainThread());
|
| + DCHECK(!defer_commits_);
|
| +
|
| + // Make sure all GL drawing is finished on the impl thread.
|
| + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
|
| + CompletionEvent completion;
|
| + channel_main_->FinishAllRenderingOnImpl(&completion);
|
| + completion.Wait();
|
| +}
|
| +
|
| +bool ProxyMain::IsStarted() const {
|
| + DCHECK(IsMainThread());
|
| + return started_;
|
| +}
|
| +
|
| +bool ProxyMain::CommitToActiveTree() const {
|
| + // With ProxyMain, we use a pending tree and activate it once it's ready to
|
| + // draw to allow input to modify the active tree and draw during raster.
|
| + return false;
|
| +}
|
| +
|
| +void ProxyMain::SetOutputSurface(OutputSurface* output_surface) {
|
| + channel_main_->InitializeOutputSurfaceOnImpl(output_surface);
|
| +}
|
| +
|
| +void ProxyMain::SetVisible(bool visible) {
|
| + TRACE_EVENT1("cc", "ProxyMain::SetVisible", "visible", visible);
|
| + channel_main_->SetVisibleOnImpl(visible);
|
| +}
|
| +
|
| +void ProxyMain::SetThrottleFrameProduction(bool throttle) {
|
| + TRACE_EVENT1("cc", "ProxyMain::SetThrottleFrameProduction", "throttle",
|
| + throttle);
|
| + channel_main_->SetThrottleFrameProductionOnImpl(throttle);
|
| +}
|
| +
|
| +const RendererCapabilities& ProxyMain::GetRendererCapabilities() const {
|
| + DCHECK(IsMainThread());
|
| + DCHECK(!layer_tree_host_->output_surface_lost());
|
| + return renderer_capabilities_;
|
| +}
|
| +
|
| +void ProxyMain::SetNeedsAnimate() {
|
| + DCHECK(IsMainThread());
|
| + if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE)) {
|
| + TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsAnimate",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + }
|
| +}
|
| +
|
| +void ProxyMain::SetNeedsUpdateLayers() {
|
| + DCHECK(IsMainThread());
|
| + // If we are currently animating, make sure we also update the layers.
|
| + if (current_pipeline_stage_ == ANIMATE_PIPELINE_STAGE) {
|
| + final_pipeline_stage_ =
|
| + std::max(final_pipeline_stage_, UPDATE_LAYERS_PIPELINE_STAGE);
|
| + return;
|
| + }
|
| + if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE)) {
|
| + TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsUpdateLayers",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + }
|
| +}
|
| +
|
| +void ProxyMain::SetNeedsCommit() {
|
| + DCHECK(IsMainThread());
|
| + // If we are currently animating, make sure we don't skip the commit. Note
|
| + // that requesting a commit during the layer update stage means we need to
|
| + // schedule another full commit.
|
| + if (current_pipeline_stage_ == ANIMATE_PIPELINE_STAGE) {
|
| + final_pipeline_stage_ =
|
| + std::max(final_pipeline_stage_, COMMIT_PIPELINE_STAGE);
|
| + return;
|
| + }
|
| + if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE)) {
|
| + TRACE_EVENT_INSTANT0("cc", "ProxyMain::SetNeedsCommit",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + }
|
| +}
|
| +
|
| +void ProxyMain::SetNeedsRedraw(const gfx::Rect& damage_rect) {
|
| + TRACE_EVENT0("cc", "ProxyMain::SetNeedsRedraw");
|
| + DCHECK(IsMainThread());
|
| + channel_main_->SetNeedsRedrawOnImpl(damage_rect);
|
| +}
|
| +
|
| +void ProxyMain::SetNextCommitWaitsForActivation() {
|
| + DCHECK(IsMainThread());
|
| + commit_waits_for_activation_ = true;
|
| +}
|
| +
|
| +void ProxyMain::NotifyInputThrottledUntilCommit() {
|
| + DCHECK(IsMainThread());
|
| + channel_main_->SetInputThrottledUntilCommitOnImpl(true);
|
| +}
|
| +
|
| +void ProxyMain::SetDeferCommits(bool defer_commits) {
|
| + DCHECK(IsMainThread());
|
| + if (defer_commits_ == defer_commits)
|
| + return;
|
| +
|
| + defer_commits_ = defer_commits;
|
| + if (defer_commits_)
|
| + TRACE_EVENT_ASYNC_BEGIN0("cc", "ProxyMain::SetDeferCommits", this);
|
| + else
|
| + TRACE_EVENT_ASYNC_END0("cc", "ProxyMain::SetDeferCommits", this);
|
| +
|
| + channel_main_->SetDeferCommitsOnImpl(defer_commits);
|
| +}
|
| +
|
| +bool ProxyMain::CommitRequested() const {
|
| + DCHECK(IsMainThread());
|
| + // TODO(skyostil): Split this into something like CommitRequested() and
|
| + // CommitInProgress().
|
| + return current_pipeline_stage_ != NO_PIPELINE_STAGE ||
|
| + max_requested_pipeline_stage_ >= COMMIT_PIPELINE_STAGE;
|
| +}
|
| +
|
| +bool ProxyMain::BeginMainFrameRequested() const {
|
| + DCHECK(IsMainThread());
|
| + return max_requested_pipeline_stage_ != NO_PIPELINE_STAGE;
|
| +}
|
| +
|
| +void ProxyMain::MainThreadHasStoppedFlinging() {
|
| + DCHECK(IsMainThread());
|
| + channel_main_->MainThreadHasStoppedFlingingOnImpl();
|
| +}
|
| +
|
| +void ProxyMain::Start() {
|
| + DCHECK(IsMainThread());
|
| + DCHECK(task_runner_provider_->HasImplThread());
|
| + DCHECK(channel_main_);
|
| +
|
| + // Create LayerTreeHostImpl.
|
| + channel_main_->SynchronouslyInitializeImpl(
|
| + layer_tree_host_, std::move(external_begin_frame_source_));
|
| +
|
| + started_ = true;
|
| +}
|
| +
|
| +void ProxyMain::Stop() {
|
| + TRACE_EVENT0("cc", "ProxyMain::Stop");
|
| + DCHECK(IsMainThread());
|
| + DCHECK(started_);
|
| +
|
| + channel_main_->SynchronouslyCloseImpl();
|
| +
|
| + layer_tree_host_ = nullptr;
|
| + started_ = false;
|
| +}
|
| +
|
| +bool ProxyMain::SupportsImplScrolling() const {
|
| + return true;
|
| +}
|
| +
|
| +bool ProxyMain::MainFrameWillHappenForTesting() {
|
| + DCHECK(IsMainThread());
|
| + bool main_frame_will_happen = false;
|
| + {
|
| + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
|
| + CompletionEvent completion;
|
| + channel_main_->MainFrameWillHappenOnImplForTesting(&completion,
|
| + &main_frame_will_happen);
|
| + completion.Wait();
|
| + }
|
| + return main_frame_will_happen;
|
| +}
|
| +
|
| +void ProxyMain::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
|
| + NOTREACHED() << "Only used by SingleThreadProxy";
|
| +}
|
| +
|
| +void ProxyMain::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) {
|
| + NOTREACHED() << "Only used by SingleProxyMain";
|
| +}
|
| +
|
| +void ProxyMain::ReleaseOutputSurface() {
|
| + DCHECK(IsMainThread());
|
| + DCHECK(layer_tree_host_->output_surface_lost());
|
| +
|
| + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
|
| + CompletionEvent completion;
|
| + channel_main_->ReleaseOutputSurfaceOnImpl(&completion);
|
| + completion.Wait();
|
| +}
|
| +
|
| +void ProxyMain::UpdateTopControlsState(TopControlsState constraints,
|
| + TopControlsState current,
|
| + bool animate) {
|
| + DCHECK(IsMainThread());
|
| + channel_main_->UpdateTopControlsStateOnImpl(constraints, current, animate);
|
| +}
|
| +
|
| +bool ProxyMain::SendCommitRequestToImplThreadIfNeeded(
|
| + CommitPipelineStage required_stage) {
|
| + DCHECK(IsMainThread());
|
| + DCHECK_NE(NO_PIPELINE_STAGE, required_stage);
|
| + bool already_posted = max_requested_pipeline_stage_ != NO_PIPELINE_STAGE;
|
| + max_requested_pipeline_stage_ =
|
| + std::max(max_requested_pipeline_stage_, required_stage);
|
| + if (already_posted)
|
| + return false;
|
| + channel_main_->SetNeedsCommitOnImpl();
|
| + return true;
|
| +}
|
| +
|
| +bool ProxyMain::IsMainThread() const {
|
| + return task_runner_provider_->IsMainThread();
|
| +}
|
| +
|
| +} // namespace cc
|
|
|