diff options
28 files changed, 2575 insertions, 2233 deletions
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index df0083a..3be4ebb 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn @@ -502,7 +502,9 @@ component("cc") { "trees/proxy.h", "trees/proxy_common.cc", "trees/proxy_common.h", + "trees/proxy_impl.cc", "trees/proxy_impl.h", + "trees/proxy_main.cc", "trees/proxy_main.h", "trees/remote_proto_channel.h", "trees/scoped_abort_remaining_swap_promises.h", @@ -512,8 +514,6 @@ component("cc") { "trees/swap_promise_monitor.h", "trees/task_runner_provider.cc", "trees/task_runner_provider.h", - "trees/thread_proxy.cc", - "trees/thread_proxy.h", "trees/threaded_channel.cc", "trees/threaded_channel.h", "trees/tree_synchronizer.cc", @@ -655,6 +655,10 @@ source_set("test_support") { "test/pixel_test_software_output_device.h", "test/pixel_test_utils.cc", "test/pixel_test_utils.h", + "test/proxy_impl_for_test.cc", + "test/proxy_impl_for_test.h", + "test/proxy_main_for_test.cc", + "test/proxy_main_for_test.h", "test/render_pass_test_utils.cc", "test/render_pass_test_utils.h", "test/scheduler_test_common.cc", @@ -677,6 +681,8 @@ source_set("test_support") { "test/test_gles2_interface.h", "test/test_gpu_memory_buffer_manager.cc", "test/test_gpu_memory_buffer_manager.h", + "test/test_hooks.cc", + "test/test_hooks.h", "test/test_image_factory.cc", "test/test_image_factory.h", "test/test_in_process_context_provider.cc", @@ -692,6 +698,8 @@ source_set("test_support") { "test/test_tile_priorities.h", "test/test_web_graphics_context_3d.cc", "test/test_web_graphics_context_3d.h", + "test/threaded_channel_for_test.cc", + "test/threaded_channel_for_test.h", ] configs += [ "//build/config:precompiled_headers" ] @@ -564,7 +564,9 @@ 'trees/proxy.h', 'trees/proxy_common.cc', 'trees/proxy_common.h', + 'trees/proxy_impl.cc', 'trees/proxy_impl.h', + 'trees/proxy_main.cc', 'trees/proxy_main.h', 'trees/remote_proto_channel.h', 'trees/scoped_abort_remaining_swap_promises.h', @@ -572,8 +574,6 @@ 'trees/single_thread_proxy.h', 'trees/swap_promise_monitor.cc', 'trees/swap_promise_monitor.h', - 'trees/thread_proxy.cc', - 'trees/thread_proxy.h', 'trees/task_runner_provider.cc', 'trees/task_runner_provider.h', 'trees/threaded_channel.cc', diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 5332133..8ce17e2 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -258,6 +258,10 @@ 'test/pixel_test_software_output_device.h', 'test/pixel_test_utils.cc', 'test/pixel_test_utils.h', + 'test/proxy_impl_for_test.cc', + 'test/proxy_impl_for_test.h', + 'test/proxy_main_for_test.cc', + 'test/proxy_main_for_test.h', 'test/render_pass_test_utils.cc', 'test/render_pass_test_utils.h', 'test/scheduler_test_common.cc', @@ -280,6 +284,8 @@ 'test/test_gles2_interface.h', 'test/test_gpu_memory_buffer_manager.cc', 'test/test_gpu_memory_buffer_manager.h', + 'test/test_hooks.cc', + 'test/test_hooks.h', 'test/test_image_factory.cc', 'test/test_image_factory.h', 'test/test_in_process_context_provider.cc', @@ -295,6 +301,8 @@ 'test/test_tile_priorities.h', 'test/test_web_graphics_context_3d.cc', 'test/test_web_graphics_context_3d.h', + 'test/threaded_channel_for_test.cc', + 'test/threaded_channel_for_test.h', ], }, 'targets': [ diff --git a/cc/debug/benchmark_instrumentation.h b/cc/debug/benchmark_instrumentation.h index 944ac66..99cfa21 100644 --- a/cc/debug/benchmark_instrumentation.h +++ b/cc/debug/benchmark_instrumentation.h @@ -20,6 +20,8 @@ const char kCategory[] = "cc,benchmark"; const char kBeginFrameId[] = "begin_frame_id"; } // namespace internal +// TODO(khushalsagar): Fix these names for the telemetry benchmarks. +// See crbug/567993. const char kSendBeginFrame[] = "ThreadProxy::ScheduledActionSendBeginMainFrame"; const char kDoBeginFrame[] = "ThreadProxy::BeginMainFrame"; diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index 8999b2f..44d16c1 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc @@ -1228,7 +1228,7 @@ TEST(SchedulerStateMachineTest, TestNoRequestOutputSurfaceWhenInvisible) { SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); } -// See ThreadProxy::BeginMainFrame "EarlyOut_NotVisible" / +// See ProxyMain::BeginMainFrame "EarlyOut_NotVisible" / // "EarlyOut_OutputSurfaceLost" cases. TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { SchedulerSettings default_scheduler_settings; @@ -1282,7 +1282,7 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } -// See ThreadProxy::BeginMainFrame "EarlyOut_NoUpdates" case. +// See ProxyMain::BeginMainFrame "EarlyOut_NoUpdates" case. TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index a99e2f2..d68ec67 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc @@ -30,8 +30,10 @@ #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/layer_tree_host_single_thread_client.h" #include "cc/trees/layer_tree_impl.h" +#include "cc/trees/proxy_impl.h" +#include "cc/trees/proxy_main.h" #include "cc/trees/single_thread_proxy.h" -#include "cc/trees/thread_proxy.h" +#include "cc/trees/threaded_channel.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/gfx/geometry/size_conversions.h" @@ -93,254 +95,8 @@ void CreateVirtualViewportLayers(Layer* root_layer, layer_settings); } -TestHooks::TestHooks() {} - -TestHooks::~TestHooks() {} - -DrawResult TestHooks::PrepareToDrawOnThread( - LayerTreeHostImpl* host_impl, - LayerTreeHostImpl::FrameData* frame_data, - DrawResult draw_result) { - return draw_result; -} - -void TestHooks::CreateResourceAndTileTaskWorkerPool( - LayerTreeHostImpl* host_impl, - scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool, - scoped_ptr<ResourcePool>* resource_pool) { - host_impl->LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool( - tile_task_worker_pool, resource_pool); -} - -// Adapts ThreadProxy for test. Injects test hooks for testing. -class ThreadProxyForTest : public ThreadProxy { - public: - static scoped_ptr<Proxy> Create( - TestHooks* test_hooks, - LayerTreeHost* host, - TaskRunnerProvider* task_runner_provider, - scoped_ptr<BeginFrameSource> external_begin_frame_source) { - return make_scoped_ptr( - new ThreadProxyForTest(test_hooks, host, task_runner_provider, - std::move(external_begin_frame_source))); - } - - ~ThreadProxyForTest() override {} - - private: - TestHooks* test_hooks_; - - void SetNeedsUpdateLayers() override { - ThreadProxy::SetNeedsUpdateLayers(); - test_hooks_->DidSetNeedsUpdateLayers(); - } - - void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override { - test_hooks_->ScheduledActionWillSendBeginMainFrame(); - ThreadProxy::ScheduledActionSendBeginMainFrame(args); - test_hooks_->ScheduledActionSendBeginMainFrame(); - } - - DrawResult ScheduledActionDrawAndSwapIfPossible() override { - DrawResult result = ThreadProxy::ScheduledActionDrawAndSwapIfPossible(); - test_hooks_->ScheduledActionDrawAndSwapIfPossible(); - return result; - } - - void ScheduledActionCommit() override { - ThreadProxy::ScheduledActionCommit(); - test_hooks_->ScheduledActionCommit(); - } - - void ScheduledActionBeginOutputSurfaceCreation() override { - ThreadProxy::ScheduledActionBeginOutputSurfaceCreation(); - test_hooks_->ScheduledActionBeginOutputSurfaceCreation(); - } - - void ScheduledActionPrepareTiles() override { - ThreadProxy::ScheduledActionPrepareTiles(); - test_hooks_->ScheduledActionPrepareTiles(); - } - - void ScheduledActionInvalidateOutputSurface() override { - ThreadProxy::ScheduledActionInvalidateOutputSurface(); - test_hooks_->ScheduledActionInvalidateOutputSurface(); - } - - void SendBeginMainFrameNotExpectedSoon() override { - ThreadProxy::SendBeginMainFrameNotExpectedSoon(); - test_hooks_->SendBeginMainFrameNotExpectedSoon(); - } - - void DidActivateSyncTree() override { - ThreadProxy::DidActivateSyncTree(); - test_hooks_->DidActivateSyncTree(); - } - - void SetThrottleFrameProductionOnImpl(bool throttle) override { - test_hooks_->SetThrottleFrameProductionOnImpl(throttle); - ThreadProxy::SetThrottleFrameProductionOnImpl(throttle); - } - - void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) override { - test_hooks_->InitializeOutputSurfaceOnImpl(output_surface); - ThreadProxy::InitializeOutputSurfaceOnImpl(output_surface); - } - - void MainThreadHasStoppedFlingingOnImpl() override { - test_hooks_->MainThreadHasStoppedFlingingOnImpl(); - ThreadProxy::MainThreadHasStoppedFlingingOnImpl(); - } - - void SetInputThrottledUntilCommitOnImpl(bool is_throttled) override { - test_hooks_->SetInputThrottledUntilCommitOnImpl(is_throttled); - ThreadProxy::SetInputThrottledUntilCommitOnImpl(is_throttled); - } - - void UpdateTopControlsStateOnImpl(TopControlsState constraints, - TopControlsState current, - bool animate) override { - test_hooks_->UpdateTopControlsStateOnImpl(constraints, current, animate); - ThreadProxy::UpdateTopControlsStateOnImpl(constraints, current, animate); - } - - void SetDeferCommitsOnImpl(bool defer_commits) const override { - test_hooks_->SetDeferCommitsOnImpl(defer_commits); - ThreadProxy::SetDeferCommitsOnImpl(defer_commits); - } - - void BeginMainFrameAbortedOnImpl( - CommitEarlyOutReason reason, - base::TimeTicks main_thread_start_time) override { - test_hooks_->BeginMainFrameAbortedOnImpl(reason); - ThreadProxy::BeginMainFrameAbortedOnImpl(reason, main_thread_start_time); - } - - void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override { - test_hooks_->SetNeedsRedrawOnImpl(damage_rect); - ThreadProxy::SetNeedsRedrawOnImpl(damage_rect); - }; - - void SetNeedsCommitOnImpl() override { - test_hooks_->SetNeedsCommitOnImpl(); - ThreadProxy::SetNeedsCommitOnImpl(); - } - - void FinishAllRenderingOnImpl(CompletionEvent* completion) override { - test_hooks_->FinishAllRenderingOnImpl(); - ThreadProxy::FinishAllRenderingOnImpl(completion); - }; - - void SetVisibleOnImpl(bool visible) override { - test_hooks_->SetVisibleOnImpl(visible); - ThreadProxy::SetVisibleOnImpl(visible); - } - - void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override { - test_hooks_->ReleaseOutputSurfaceOnImpl(); - ThreadProxy::ReleaseOutputSurfaceOnImpl(completion); - } - - void FinishGLOnImpl(CompletionEvent* completion) override { - test_hooks_->FinishGLOnImpl(); - ThreadProxy::FinishGLOnImpl(completion); - } - - void StartCommitOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host, - base::TimeTicks main_thread_start_time, - bool hold_commit_for_activation) override { - test_hooks_->StartCommitOnImpl(); - ThreadProxy::StartCommitOnImpl(completion, layer_tree_host, - main_thread_start_time, - hold_commit_for_activation); - } - - void InitializeImplOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host) override { - ThreadProxy::InitializeImplOnImpl(completion, layer_tree_host); - test_hooks_->InitializeImplOnImpl(); - } - - void LayerTreeHostClosedOnImpl(CompletionEvent* completion) override { - test_hooks_->WillCloseLayerTreeHostOnImpl(); - ThreadProxy::LayerTreeHostClosedOnImpl(completion); - } - - void DidCompleteSwapBuffers() override { - test_hooks_->ReceivedDidCompleteSwapBuffers(); - ThreadProxy::DidCompleteSwapBuffers(); - } - - void SetRendererCapabilitiesMainCopy( - const RendererCapabilities& capabilities) override { - test_hooks_->ReceivedSetRendererCapabilitiesMainCopy(capabilities); - ThreadProxy::SetRendererCapabilitiesMainCopy(capabilities); - } - - void BeginMainFrameNotExpectedSoon() override { - test_hooks_->ReceivedBeginMainFrameNotExpectedSoon(); - ThreadProxy::BeginMainFrameNotExpectedSoon(); - } - - void DidCommitAndDrawFrame() override { - test_hooks_->ReceivedDidCommitAndDrawFrame(); - ThreadProxy::DidCommitAndDrawFrame(); - } - - void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) override { - test_hooks_->ReceivedSetAnimationEvents(); - ThreadProxy::SetAnimationEvents(std::move(events)); - } - - void DidLoseOutputSurface() override { - test_hooks_->ReceivedDidLoseOutputSurface(); - ThreadProxy::DidLoseOutputSurface(); - } - - void RequestNewOutputSurface() override { - test_hooks_->ReceivedRequestNewOutputSurface(); - ThreadProxy::RequestNewOutputSurface(); - } - - void DidInitializeOutputSurface( - bool success, - const RendererCapabilities& capabilities) override { - test_hooks_->ReceivedDidInitializeOutputSurface(success, capabilities); - ThreadProxy::DidInitializeOutputSurface(success, capabilities); - } - - void DidCompletePageScaleAnimation() override { - test_hooks_->ReceivedDidCompletePageScaleAnimation(); - ThreadProxy::DidCompletePageScaleAnimation(); - } - - void PostFrameTimingEventsOnMain( - scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, - scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) - override { - test_hooks_->ReceivedPostFrameTimingEventsOnMain(); - ThreadProxy::PostFrameTimingEventsOnMain(std::move(composite_events), - std::move(main_frame_events)); - } - - void BeginMainFrame(scoped_ptr<BeginMainFrameAndCommitState> - begin_main_frame_state) override { - test_hooks_->ReceivedBeginMainFrame(); - ThreadProxy::BeginMainFrame(std::move(begin_main_frame_state)); - }; - - ThreadProxyForTest(TestHooks* test_hooks, - LayerTreeHost* host, - TaskRunnerProvider* task_runner_provider, - scoped_ptr<BeginFrameSource> external_begin_frame_source) - : ThreadProxy(host, - task_runner_provider, - std::move(external_begin_frame_source)), - test_hooks_(test_hooks) {} -}; - -// Adapts SingleThreadProxy for test. Injects test hooks for testing. +// Creates a SingleThreadProxy that notifies the supplied |test_hooks| of +// various actions. class SingleThreadProxyForTest : public SingleThreadProxy { public: static scoped_ptr<Proxy> Create( @@ -357,7 +113,17 @@ class SingleThreadProxyForTest : public SingleThreadProxy { ~SingleThreadProxyForTest() override {} private: - TestHooks* test_hooks_; + SingleThreadProxyForTest( + TestHooks* test_hooks, + LayerTreeHost* host, + LayerTreeHostSingleThreadClient* client, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) + : SingleThreadProxy(host, + client, + task_runner_provider, + std::move(external_begin_frame_source)), + test_hooks_(test_hooks) {} void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override { test_hooks_->ScheduledActionWillSendBeginMainFrame(); @@ -397,17 +163,7 @@ class SingleThreadProxyForTest : public SingleThreadProxy { test_hooks_->SendBeginMainFrameNotExpectedSoon(); } - SingleThreadProxyForTest( - TestHooks* test_hooks, - LayerTreeHost* host, - LayerTreeHostSingleThreadClient* client, - TaskRunnerProvider* task_runner_provider, - scoped_ptr<BeginFrameSource> external_begin_frame_source) - : SingleThreadProxy(host, - client, - task_runner_provider, - std::move(external_begin_frame_source)), - test_hooks_(test_hooks) {} + TestHooks* test_hooks_; }; // Adapts LayerTreeHostImpl for test. Runs real code, then invokes test hooks. @@ -700,9 +456,10 @@ class LayerTreeHostForTesting : public LayerTreeHost { scoped_ptr<Proxy> proxy; if (mode == CompositorMode::Threaded) { DCHECK(impl_task_runner.get()); - proxy = ThreadProxyForTest::Create( + scoped_ptr<ProxyMain> proxy_main = ProxyMainForTest::CreateThreaded( test_hooks, layer_tree_host.get(), task_runner_provider.get(), std::move(external_begin_frame_source)); + proxy = std::move(proxy_main); } else { proxy = SingleThreadProxyForTest::Create( test_hooks, layer_tree_host.get(), client, task_runner_provider.get(), @@ -1161,4 +918,21 @@ LayerTreeHost* LayerTreeTest::layer_tree_host() { return layer_tree_host_.get(); } +ProxyMainForTest* LayerTreeTest::GetProxyMainForTest() const { + DCHECK(HasImplThread()); + return static_cast<ProxyMainForTest*>(proxy()); +} + +ProxyImplForTest* LayerTreeTest::GetProxyImplForTest() const { + DCHECK(HasImplThread()); + ThreadedChannel* threaded_channel = + static_cast<ThreadedChannel*>(GetProxyMainForTest()->channel_main()); + ProxyImpl* proxy_impl = threaded_channel->GetProxyImplForTesting(); + + // We check for null ProxyImpl since ProxyImpl exists in the ThreadedChannel + // only after it is initialized. + DCHECK(proxy_impl); + return static_cast<ProxyImplForTest*>(proxy_impl); +} + } // namespace cc diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index d727ae6..ea509d5 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h @@ -9,6 +9,9 @@ #include "base/threading/thread.h" #include "cc/animation/animation_delegate.h" #include "cc/layers/layer_settings.h" +#include "cc/test/proxy_impl_for_test.h" +#include "cc/test/proxy_main_for_test.h" +#include "cc/test/test_hooks.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_impl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -46,130 +49,6 @@ void CreateVirtualViewportLayers(Layer* root_layer, LayerTreeHost* host, const LayerSettings& layer_settings); -// Used by test stubs to notify the test when something interesting happens. -class TestHooks : public AnimationDelegate { - public: - TestHooks(); - ~TestHooks() override; - - void ReadSettings(const LayerTreeSettings& settings); - - virtual void CreateResourceAndTileTaskWorkerPool( - LayerTreeHostImpl* host_impl, - scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool, - scoped_ptr<ResourcePool>* resource_pool); - virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, - const BeginFrameArgs& args) {} - virtual void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) {} - virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, - CommitEarlyOutReason reason) {} - virtual void WillPrepareTiles(LayerTreeHostImpl* host_impl) {} - virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) {} - virtual void WillCommitCompleteOnThread(LayerTreeHostImpl* host_impl) {} - virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) {} - virtual void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) {} - virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) {} - virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, - bool success) {} - virtual DrawResult PrepareToDrawOnThread( - LayerTreeHostImpl* host_impl, - LayerTreeHostImpl::FrameData* frame_data, - DrawResult draw_result); - virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {} - virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) {} - virtual void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) {} - virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {} - virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {} - virtual void NotifyAllTileTasksCompleted(LayerTreeHostImpl* host_impl) {} - virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl, - const Tile* tile) {} - virtual void AnimateLayers(LayerTreeHostImpl* host_impl, - base::TimeTicks monotonic_time) {} - virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl, - bool has_unfinished_animation) {} - virtual void WillAnimateLayers(LayerTreeHostImpl* host_impl, - base::TimeTicks monotonic_time) {} - virtual void ApplyViewportDeltas( - const gfx::Vector2dF& inner_delta, - const gfx::Vector2dF& outer_delta, - const gfx::Vector2dF& elastic_overscroll_delta, - float scale, - float top_controls_delta) {} - virtual void BeginMainFrame(const BeginFrameArgs& args) {} - virtual void WillBeginMainFrame() {} - virtual void DidBeginMainFrame() {} - virtual void UpdateLayerTreeHost() {} - virtual void DidInitializeOutputSurface() {} - virtual void DidFailToInitializeOutputSurface() {} - virtual void DidAddAnimation() {} - virtual void WillCommit() {} - virtual void DidCommit() {} - virtual void DidCommitAndDrawFrame() {} - virtual void DidCompleteSwapBuffers() {} - virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl, - bool visible) {} - virtual void ScheduleComposite() {} - virtual void DidSetNeedsUpdateLayers() {} - virtual void DidActivateSyncTree() {} - - // Hooks for SchedulerClient. - virtual void ScheduledActionWillSendBeginMainFrame() {} - virtual void ScheduledActionSendBeginMainFrame() {} - virtual void ScheduledActionDrawAndSwapIfPossible() {} - virtual void ScheduledActionCommit() {} - virtual void ScheduledActionBeginOutputSurfaceCreation() {} - virtual void ScheduledActionPrepareTiles() {} - virtual void ScheduledActionInvalidateOutputSurface() {} - virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) {} - virtual void SendBeginMainFrameNotExpectedSoon() {} - - // Hooks for ProxyImpl - virtual void SetThrottleFrameProductionOnImpl(bool throttle) {} - virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints, - TopControlsState current, - bool animate) {} - virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) {} - virtual void MainThreadHasStoppedFlingingOnImpl() {} - virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled) {} - virtual void SetDeferCommitsOnImpl(bool defer_commits) {} - virtual void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) {} - virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {} - virtual void SetNeedsCommitOnImpl() {} - virtual void FinishAllRenderingOnImpl() {} - virtual void SetVisibleOnImpl(bool visible) {} - virtual void ReleaseOutputSurfaceOnImpl() {} - virtual void FinishGLOnImpl() {} - virtual void StartCommitOnImpl() {} - virtual void InitializeImplOnImpl() {} - virtual void WillCloseLayerTreeHostOnImpl() {} - - // Hooks for ProxyMain - virtual void ReceivedDidCompleteSwapBuffers() {} - virtual void ReceivedSetRendererCapabilitiesMainCopy( - const RendererCapabilities& capabilities) {} - virtual void ReceivedBeginMainFrameNotExpectedSoon() {} - virtual void ReceivedDidCommitAndDrawFrame() {} - virtual void ReceivedSetAnimationEvents() {} - virtual void ReceivedDidLoseOutputSurface() {} - virtual void ReceivedRequestNewOutputSurface() {} - virtual void ReceivedDidInitializeOutputSurface( - bool success, - const RendererCapabilities& capabilities) {} - virtual void ReceivedDidCompletePageScaleAnimation() {} - virtual void ReceivedPostFrameTimingEventsOnMain() {} - virtual void ReceivedBeginMainFrame() {} - - // Implementation of AnimationDelegate: - void NotifyAnimationStarted(base::TimeTicks monotonic_time, - Animation::TargetProperty target_property, - int group) override {} - void NotifyAnimationFinished(base::TimeTicks monotonic_time, - Animation::TargetProperty target_property, - int group) override {} - - virtual void RequestNewOutputSurface() = 0; -}; - class BeginTask; class LayerTreeHostClientForTesting; class TimeoutTask; @@ -250,9 +129,10 @@ class LayerTreeTest : public testing::Test, public TestHooks { virtual void BeginTest() = 0; virtual void SetupTree(); + // TODO(khushalsagar): Add mode for running remote channel tests. virtual void RunTest(CompositorMode mode, bool delegating_renderer); - bool HasImplThread() { return !!impl_thread_; } + bool HasImplThread() const { return !!impl_thread_; } base::SingleThreadTaskRunner* ImplThreadTaskRunner() { DCHECK(task_runner_provider()); base::SingleThreadTaskRunner* impl_thread_task_runner = @@ -278,6 +158,12 @@ class LayerTreeTest : public testing::Test, public TestHooks { FakeOutputSurface* output_surface() { return output_surface_; } int LastCommittedSourceFrameNumber(LayerTreeHostImpl* impl) const; + // Use these only for ProxyMain tests in threaded mode. + // TODO(khushalsagar): Update these when adding support for remote channel + // tests. + ProxyMainForTest* GetProxyMainForTest() const; + ProxyImplForTest* GetProxyImplForTest() const; + void DestroyLayerTreeHost(); // By default, output surface recreation is synchronous. diff --git a/cc/test/proxy_impl_for_test.cc b/cc/test/proxy_impl_for_test.cc new file mode 100644 index 0000000..3cd542b --- /dev/null +++ b/cc/test/proxy_impl_for_test.cc @@ -0,0 +1,163 @@ +// 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/test/proxy_impl_for_test.h" + +namespace cc { +scoped_ptr<ProxyImpl> ProxyImplForTest::Create( + TestHooks* test_hooks, + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) { + return make_scoped_ptr(new ProxyImplForTest( + test_hooks, channel_impl, layer_tree_host, task_runner_provider, + std::move(external_begin_frame_source))); +} + +bool ProxyImplForTest::HasCommitCompletionEvent() const { + return commit_completion_event_ != nullptr; +} + +bool ProxyImplForTest::GetNextCommitWaitsForActivation() const { + return next_commit_waits_for_activation_; +} + +ProxyImplForTest::ProxyImplForTest( + TestHooks* test_hooks, + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) + : ProxyImpl(channel_impl, + layer_tree_host, + task_runner_provider, + std::move(external_begin_frame_source)), + test_hooks_(test_hooks) {} + +void ProxyImplForTest::ScheduledActionSendBeginMainFrame( + const BeginFrameArgs& args) { + test_hooks_->ScheduledActionWillSendBeginMainFrame(); + ProxyImpl::ScheduledActionSendBeginMainFrame(args); + test_hooks_->ScheduledActionSendBeginMainFrame(); +} + +DrawResult ProxyImplForTest::ScheduledActionDrawAndSwapIfPossible() { + DrawResult result = ProxyImpl::ScheduledActionDrawAndSwapIfPossible(); + test_hooks_->ScheduledActionDrawAndSwapIfPossible(); + return result; +} + +void ProxyImplForTest::ScheduledActionCommit() { + ProxyImpl::ScheduledActionCommit(); + test_hooks_->ScheduledActionCommit(); +} + +void ProxyImplForTest::ScheduledActionBeginOutputSurfaceCreation() { + ProxyImpl::ScheduledActionBeginOutputSurfaceCreation(); + test_hooks_->ScheduledActionBeginOutputSurfaceCreation(); +} + +void ProxyImplForTest::ScheduledActionPrepareTiles() { + ProxyImpl::ScheduledActionPrepareTiles(); + test_hooks_->ScheduledActionPrepareTiles(); +} + +void ProxyImplForTest::ScheduledActionInvalidateOutputSurface() { + ProxyImpl::ScheduledActionInvalidateOutputSurface(); + test_hooks_->ScheduledActionInvalidateOutputSurface(); +} + +void ProxyImplForTest::SendBeginMainFrameNotExpectedSoon() { + ProxyImpl::SendBeginMainFrameNotExpectedSoon(); + test_hooks_->SendBeginMainFrameNotExpectedSoon(); +} + +void ProxyImplForTest::DidActivateSyncTree() { + ProxyImpl::DidActivateSyncTree(); + test_hooks_->DidActivateSyncTree(); +} + +void ProxyImplForTest::SetThrottleFrameProductionOnImpl(bool throttle) { + test_hooks_->SetThrottleFrameProductionOnImpl(throttle); + ProxyImpl::SetThrottleFrameProductionOnImpl(throttle); +} + +void ProxyImplForTest::InitializeOutputSurfaceOnImpl( + OutputSurface* output_surface) { + test_hooks_->InitializeOutputSurfaceOnImpl(output_surface); + ProxyImpl::InitializeOutputSurfaceOnImpl(output_surface); +} + +void ProxyImplForTest::MainThreadHasStoppedFlingingOnImpl() { + test_hooks_->MainThreadHasStoppedFlingingOnImpl(); + ProxyImpl::MainThreadHasStoppedFlingingOnImpl(); +} + +void ProxyImplForTest::SetInputThrottledUntilCommitOnImpl(bool is_throttled) { + test_hooks_->SetInputThrottledUntilCommitOnImpl(is_throttled); + ProxyImpl::SetInputThrottledUntilCommitOnImpl(is_throttled); +} + +void ProxyImplForTest::UpdateTopControlsStateOnImpl( + TopControlsState constraints, + TopControlsState current, + bool animate) { + test_hooks_->UpdateTopControlsStateOnImpl(constraints, current, animate); + ProxyImpl::UpdateTopControlsStateOnImpl(constraints, current, animate); +} + +void ProxyImplForTest::SetDeferCommitsOnImpl(bool defer_commits) const { + test_hooks_->SetDeferCommitsOnImpl(defer_commits); + ProxyImpl::SetDeferCommitsOnImpl(defer_commits); +} + +void ProxyImplForTest::BeginMainFrameAbortedOnImpl( + CommitEarlyOutReason reason, + base::TimeTicks main_thread_start_time) { + test_hooks_->BeginMainFrameAbortedOnImpl(reason); + ProxyImpl::BeginMainFrameAbortedOnImpl(reason, main_thread_start_time); +} + +void ProxyImplForTest::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) { + test_hooks_->SetNeedsRedrawOnImpl(damage_rect); + ProxyImpl::SetNeedsRedrawOnImpl(damage_rect); +} + +void ProxyImplForTest::SetNeedsCommitOnImpl() { + test_hooks_->SetNeedsCommitOnImpl(); + ProxyImpl::SetNeedsCommitOnImpl(); +} + +void ProxyImplForTest::FinishAllRenderingOnImpl(CompletionEvent* completion) { + test_hooks_->FinishAllRenderingOnImpl(); + ProxyImpl::FinishAllRenderingOnImpl(completion); +} + +void ProxyImplForTest::SetVisibleOnImpl(bool visible) { + test_hooks_->SetVisibleOnImpl(visible); + ProxyImpl::SetVisibleOnImpl(visible); +} + +void ProxyImplForTest::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) { + test_hooks_->ReleaseOutputSurfaceOnImpl(); + ProxyImpl::ReleaseOutputSurfaceOnImpl(completion); +} + +void ProxyImplForTest::FinishGLOnImpl(CompletionEvent* completion) { + test_hooks_->FinishGLOnImpl(); + ProxyImpl::FinishGLOnImpl(completion); +} + +void ProxyImplForTest::StartCommitOnImpl(CompletionEvent* completion, + LayerTreeHost* layer_tree_host, + base::TimeTicks main_thread_start_time, + bool hold_commit_for_activation) { + test_hooks_->StartCommitOnImpl(); + ProxyImpl::StartCommitOnImpl(completion, layer_tree_host, + main_thread_start_time, + hold_commit_for_activation); +} + +} // namespace cc diff --git a/cc/test/proxy_impl_for_test.h b/cc/test/proxy_impl_for_test.h new file mode 100644 index 0000000..b81ece5 --- /dev/null +++ b/cc/test/proxy_impl_for_test.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef CC_TEST_PROXY_IMPL_FOR_TEST_H_ +#define CC_TEST_PROXY_IMPL_FOR_TEST_H_ + +#include "base/macros.h" +#include "cc/test/test_hooks.h" +#include "cc/trees/proxy_impl.h" + +namespace cc { +// Creates a ProxyImpl that notifies the supplied |test_hooks| of various +// actions. +class ProxyImplForTest : public ProxyImpl { + public: + static scoped_ptr<ProxyImpl> Create( + TestHooks* test_hooks, + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + + using ProxyImpl::PostAnimationEventsToMainThreadOnImplThread; + using ProxyImpl::DidLoseOutputSurfaceOnImplThread; + using ProxyImpl::DidCompletePageScaleAnimationOnImplThread; + using ProxyImpl::SendBeginMainFrameNotExpectedSoon; + + bool HasCommitCompletionEvent() const; + bool GetNextCommitWaitsForActivation() const; + + ProxyImplForTest(TestHooks* test_hooks, + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + + void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override; + DrawResult ScheduledActionDrawAndSwapIfPossible() override; + void ScheduledActionCommit() override; + void ScheduledActionBeginOutputSurfaceCreation() override; + void ScheduledActionPrepareTiles() override; + void ScheduledActionInvalidateOutputSurface() override; + void SendBeginMainFrameNotExpectedSoon() override; + void DidActivateSyncTree() override; + void SetThrottleFrameProductionOnImpl(bool throttle) override; + void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) override; + void MainThreadHasStoppedFlingingOnImpl() override; + void SetInputThrottledUntilCommitOnImpl(bool is_throttled) override; + void UpdateTopControlsStateOnImpl(TopControlsState constraints, + TopControlsState current, + bool animate) override; + void SetDeferCommitsOnImpl(bool defer_commits) const override; + void BeginMainFrameAbortedOnImpl( + CommitEarlyOutReason reason, + base::TimeTicks main_thread_start_time) override; + void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override; + void SetNeedsCommitOnImpl() override; + void FinishAllRenderingOnImpl(CompletionEvent* completion) override; + void SetVisibleOnImpl(bool visible) override; + void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override; + void FinishGLOnImpl(CompletionEvent* completion) override; + void StartCommitOnImpl(CompletionEvent* completion, + LayerTreeHost* layer_tree_host, + base::TimeTicks main_thread_start_time, + bool hold_commit_for_activation) override; + + TestHooks* test_hooks_; +}; + +} // namespace cc + +#endif // CC_TEST_PROXY_IMPL_FOR_TEST_H_ diff --git a/cc/test/proxy_main_for_test.cc b/cc/test/proxy_main_for_test.cc new file mode 100644 index 0000000..4588422 --- /dev/null +++ b/cc/test/proxy_main_for_test.cc @@ -0,0 +1,104 @@ +// 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/test/proxy_main_for_test.h" + +#include "cc/test/threaded_channel_for_test.h" + +namespace cc { + +scoped_ptr<ProxyMain> ProxyMainForTest::CreateThreaded( + TestHooks* test_hooks, + LayerTreeHost* host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) { + scoped_ptr<ProxyMain> proxy_main( + new ProxyMainForTest(test_hooks, host, task_runner_provider, + std::move(external_begin_frame_source))); + proxy_main->SetChannel(ThreadedChannelForTest::Create( + test_hooks, proxy_main.get(), task_runner_provider)); + return proxy_main; +} + +ProxyMainForTest::~ProxyMainForTest() {} + +ProxyMainForTest::ProxyMainForTest( + TestHooks* test_hooks, + LayerTreeHost* host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) + : ProxyMain(host, + task_runner_provider, + std::move(external_begin_frame_source)), + test_hooks_(test_hooks) {} + +void ProxyMainForTest::SetNeedsUpdateLayers() { + ProxyMain::SetNeedsUpdateLayers(); + test_hooks_->DidSetNeedsUpdateLayers(); +} + +void ProxyMainForTest::DidCompleteSwapBuffers() { + test_hooks_->ReceivedDidCompleteSwapBuffers(); + ProxyMain::DidCompleteSwapBuffers(); +} + +void ProxyMainForTest::SetRendererCapabilities( + const RendererCapabilities& capabilities) { + test_hooks_->ReceivedSetRendererCapabilitiesMainCopy(capabilities); + ProxyMain::SetRendererCapabilities(capabilities); +} + +void ProxyMainForTest::BeginMainFrameNotExpectedSoon() { + test_hooks_->ReceivedBeginMainFrameNotExpectedSoon(); + ProxyMain::BeginMainFrameNotExpectedSoon(); +} + +void ProxyMainForTest::DidCommitAndDrawFrame() { + test_hooks_->ReceivedDidCommitAndDrawFrame(); + ProxyMain::DidCommitAndDrawFrame(); +} + +void ProxyMainForTest::SetAnimationEvents( + scoped_ptr<AnimationEventsVector> events) { + test_hooks_->ReceivedSetAnimationEvents(); + ProxyMain::SetAnimationEvents(std::move(events)); +} + +void ProxyMainForTest::DidLoseOutputSurface() { + test_hooks_->ReceivedDidLoseOutputSurface(); + ProxyMain::DidLoseOutputSurface(); +} + +void ProxyMainForTest::RequestNewOutputSurface() { + test_hooks_->ReceivedRequestNewOutputSurface(); + ProxyMain::RequestNewOutputSurface(); +} + +void ProxyMainForTest::DidInitializeOutputSurface( + bool success, + const RendererCapabilities& capabilities) { + test_hooks_->ReceivedDidInitializeOutputSurface(success, capabilities); + ProxyMain::DidInitializeOutputSurface(success, capabilities); +} + +void ProxyMainForTest::DidCompletePageScaleAnimation() { + test_hooks_->ReceivedDidCompletePageScaleAnimation(); + ProxyMain::DidCompletePageScaleAnimation(); +} + +void ProxyMainForTest::PostFrameTimingEventsOnMain( + scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, + scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { + test_hooks_->ReceivedPostFrameTimingEventsOnMain(); + ProxyMain::PostFrameTimingEventsOnMain(std::move(composite_events), + std::move(main_frame_events)); +} + +void ProxyMainForTest::BeginMainFrame( + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) { + test_hooks_->ReceivedBeginMainFrame(); + ProxyMain::BeginMainFrame(std::move(begin_main_frame_state)); +} + +} // namespace cc diff --git a/cc/test/proxy_main_for_test.h b/cc/test/proxy_main_for_test.h new file mode 100644 index 0000000..1669cc5 --- /dev/null +++ b/cc/test/proxy_main_for_test.h @@ -0,0 +1,56 @@ +// 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. + +#ifndef CC_TEST_PROXY_MAIN_FOR_TEST_H_ +#define CC_TEST_PROXY_MAIN_FOR_TEST_H_ + +#include "base/macros.h" +#include "cc/test/test_hooks.h" +#include "cc/trees/proxy_main.h" + +namespace cc { + +// Creates a ProxyMain that notifies the supplied |test_hooks| of various +// actions. +class ProxyMainForTest : public ProxyMain { + public: + static scoped_ptr<ProxyMain> CreateThreaded( + TestHooks* test_hooks, + LayerTreeHost* host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + + ~ProxyMainForTest() override; + + ProxyMainForTest(TestHooks* test_hooks, + LayerTreeHost* host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + + void SetNeedsUpdateLayers() override; + void DidCompleteSwapBuffers() override; + void SetRendererCapabilities( + const RendererCapabilities& capabilities) override; + void BeginMainFrameNotExpectedSoon() override; + void DidCommitAndDrawFrame() override; + void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) override; + void DidLoseOutputSurface() override; + void RequestNewOutputSurface() override; + void DidInitializeOutputSurface( + bool success, + const RendererCapabilities& capabilities) override; + void DidCompletePageScaleAnimation() override; + void PostFrameTimingEventsOnMain( + scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, + scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) + override; + void BeginMainFrame( + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) override; + + TestHooks* test_hooks_; +}; + +} // namespace cc + +#endif // CC_TEST_PROXY_MAIN_FOR_TEST_H_ diff --git a/cc/test/test_hooks.cc b/cc/test/test_hooks.cc new file mode 100644 index 0000000..5c913ac --- /dev/null +++ b/cc/test/test_hooks.cc @@ -0,0 +1,28 @@ +// 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/test/test_hooks.h" + +namespace cc { + +TestHooks::TestHooks() {} + +TestHooks::~TestHooks() {} + +DrawResult TestHooks::PrepareToDrawOnThread( + LayerTreeHostImpl* host_impl, + LayerTreeHostImpl::FrameData* frame_data, + DrawResult draw_result) { + return draw_result; +} + +void TestHooks::CreateResourceAndTileTaskWorkerPool( + LayerTreeHostImpl* host_impl, + scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool, + scoped_ptr<ResourcePool>* resource_pool) { + host_impl->LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool( + tile_task_worker_pool, resource_pool); +} + +} // namespace cc diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h new file mode 100644 index 0000000..fd45cbc --- /dev/null +++ b/cc/test/test_hooks.h @@ -0,0 +1,139 @@ +// 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. + +#ifndef CC_TEST_TEST_HOOKS_H_ +#define CC_TEST_TEST_HOOKS_H_ + +#include "base/macros.h" +#include "cc/animation/animation_delegate.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_host_impl.h" + +namespace cc { + +// Used by test stubs to notify the test when something interesting happens. +class TestHooks : public AnimationDelegate { + public: + TestHooks(); + ~TestHooks() override; + + void ReadSettings(const LayerTreeSettings& settings); + + virtual void CreateResourceAndTileTaskWorkerPool( + LayerTreeHostImpl* host_impl, + scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool, + scoped_ptr<ResourcePool>* resource_pool); + virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, + const BeginFrameArgs& args) {} + virtual void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) {} + virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, + CommitEarlyOutReason reason) {} + virtual void WillPrepareTiles(LayerTreeHostImpl* host_impl) {} + virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) {} + virtual void WillCommitCompleteOnThread(LayerTreeHostImpl* host_impl) {} + virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) {} + virtual void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) {} + virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) {} + virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, + bool success) {} + virtual DrawResult PrepareToDrawOnThread( + LayerTreeHostImpl* host_impl, + LayerTreeHostImpl::FrameData* frame_data, + DrawResult draw_result); + virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {} + virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) {} + virtual void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) {} + virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {} + virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {} + virtual void NotifyAllTileTasksCompleted(LayerTreeHostImpl* host_impl) {} + virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl, + const Tile* tile) {} + virtual void AnimateLayers(LayerTreeHostImpl* host_impl, + base::TimeTicks monotonic_time) {} + virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl, + bool has_unfinished_animation) {} + virtual void WillAnimateLayers(LayerTreeHostImpl* host_impl, + base::TimeTicks monotonic_time) {} + virtual void ApplyViewportDeltas( + const gfx::Vector2dF& inner_delta, + const gfx::Vector2dF& outer_delta, + const gfx::Vector2dF& elastic_overscroll_delta, + float scale, + float top_controls_delta) {} + virtual void BeginMainFrame(const BeginFrameArgs& args) {} + virtual void WillBeginMainFrame() {} + virtual void DidBeginMainFrame() {} + virtual void UpdateLayerTreeHost() {} + virtual void DidInitializeOutputSurface() {} + virtual void DidFailToInitializeOutputSurface() {} + virtual void DidAddAnimation() {} + virtual void WillCommit() {} + virtual void DidCommit() {} + virtual void DidCommitAndDrawFrame() {} + virtual void DidCompleteSwapBuffers() {} + virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl, + bool visible) {} + virtual void ScheduleComposite() {} + virtual void DidSetNeedsUpdateLayers() {} + virtual void DidActivateSyncTree() {} + + // Hooks for SchedulerClient. + virtual void ScheduledActionWillSendBeginMainFrame() {} + virtual void ScheduledActionSendBeginMainFrame() {} + virtual void ScheduledActionDrawAndSwapIfPossible() {} + virtual void ScheduledActionCommit() {} + virtual void ScheduledActionBeginOutputSurfaceCreation() {} + virtual void ScheduledActionPrepareTiles() {} + virtual void ScheduledActionInvalidateOutputSurface() {} + virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) {} + virtual void SendBeginMainFrameNotExpectedSoon() {} + + // Hooks for ProxyImpl + virtual void SetThrottleFrameProductionOnImpl(bool throttle) {} + virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints, + TopControlsState current, + bool animate) {} + virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) {} + virtual void MainThreadHasStoppedFlingingOnImpl() {} + virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled) {} + virtual void SetDeferCommitsOnImpl(bool defer_commits) {} + virtual void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) {} + virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {} + virtual void SetNeedsCommitOnImpl() {} + virtual void FinishAllRenderingOnImpl() {} + virtual void SetVisibleOnImpl(bool visible) {} + virtual void ReleaseOutputSurfaceOnImpl() {} + virtual void FinishGLOnImpl() {} + virtual void StartCommitOnImpl() {} + + // Hooks for ProxyMain + virtual void ReceivedDidCompleteSwapBuffers() {} + virtual void ReceivedSetRendererCapabilitiesMainCopy( + const RendererCapabilities& capabilities) {} + virtual void ReceivedBeginMainFrameNotExpectedSoon() {} + virtual void ReceivedDidCommitAndDrawFrame() {} + virtual void ReceivedSetAnimationEvents() {} + virtual void ReceivedDidLoseOutputSurface() {} + virtual void ReceivedRequestNewOutputSurface() {} + virtual void ReceivedDidInitializeOutputSurface( + bool success, + const RendererCapabilities& capabilities) {} + virtual void ReceivedDidCompletePageScaleAnimation() {} + virtual void ReceivedPostFrameTimingEventsOnMain() {} + virtual void ReceivedBeginMainFrame() {} + + // Implementation of AnimationDelegate: + void NotifyAnimationStarted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override {} + void NotifyAnimationFinished(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override {} + + virtual void RequestNewOutputSurface() = 0; +}; + +} // namespace cc + +#endif // CC_TEST_TEST_HOOKS_H_ diff --git a/cc/test/threaded_channel_for_test.cc b/cc/test/threaded_channel_for_test.cc new file mode 100644 index 0000000..35489bd --- /dev/null +++ b/cc/test/threaded_channel_for_test.cc @@ -0,0 +1,36 @@ +// Copyright 2011 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/test/threaded_channel_for_test.h" + +#include "cc/test/proxy_impl_for_test.h" + +namespace cc { + +scoped_ptr<ThreadedChannel> ThreadedChannelForTest::Create( + TestHooks* test_hooks, + ProxyMain* proxy_main, + TaskRunnerProvider* task_runner_provider) { + return make_scoped_ptr( + new ThreadedChannelForTest(test_hooks, proxy_main, task_runner_provider)); +} + +ThreadedChannelForTest::ThreadedChannelForTest( + TestHooks* test_hooks, + ProxyMain* proxy_main, + TaskRunnerProvider* task_runner_provider) + : ThreadedChannel(proxy_main, task_runner_provider), + test_hooks_(test_hooks) {} + +scoped_ptr<ProxyImpl> ThreadedChannelForTest::CreateProxyImpl( + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) { + return ProxyImplForTest::Create(test_hooks_, channel_impl, layer_tree_host, + task_runner_provider, + std::move(external_begin_frame_source)); +} + +} // namespace cc diff --git a/cc/test/threaded_channel_for_test.h b/cc/test/threaded_channel_for_test.h new file mode 100644 index 0000000..bd74790 --- /dev/null +++ b/cc/test/threaded_channel_for_test.h @@ -0,0 +1,38 @@ +// Copyright 2011 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. + +#ifndef CC_TEST_THREADED_CHANNEL_FOR_TEST_H_ +#define CC_TEST_THREADED_CHANNEL_FOR_TEST_H_ + +#include "base/macros.h" +#include "cc/test/test_hooks.h" +#include "cc/trees/threaded_channel.h" + +namespace cc { + +// ThreadedChannel that notifies |test_hooks| of internal actions by ProxyImpl. +class ThreadedChannelForTest : public ThreadedChannel { + public: + static scoped_ptr<ThreadedChannel> Create( + TestHooks* test_hooks, + ProxyMain* proxy_main, + TaskRunnerProvider* task_runner_provider); + + private: + ThreadedChannelForTest(TestHooks* test_hooks, + ProxyMain* proxy_main, + TaskRunnerProvider* task_runner_provider); + + scoped_ptr<ProxyImpl> CreateProxyImpl( + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) override; + + TestHooks* test_hooks_; +}; + +} // namespace cc + +#endif // CC_TEST_THREADED_CHANNEL_FOR_TEST_H_ diff --git a/cc/trees/channel_main.h b/cc/trees/channel_main.h index 8f8c4ee..39861e0 100644 --- a/cc/trees/channel_main.h +++ b/cc/trees/channel_main.h @@ -9,10 +9,12 @@ #include "cc/base/completion_event.h" #include "cc/input/top_controls_state.h" #include "cc/output/output_surface.h" +#include "cc/scheduler/begin_frame_source.h" #include "cc/scheduler/commit_earlyout_reason.h" #include "cc/trees/proxy_common.h" namespace cc { + // ChannelMain and ChannelImpl provide an abstract communication layer for // the main and impl side of the compositor. // @@ -25,7 +27,9 @@ namespace cc { class CC_EXPORT ChannelMain { public: - // Interface for commands sent to the ProxyImpl + virtual ~ChannelMain() {} + + // Interface for commands sent to ProxyImpl virtual void SetThrottleFrameProductionOnImpl(bool throttle) = 0; virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints, TopControlsState current, @@ -37,7 +41,6 @@ class CC_EXPORT ChannelMain { virtual void FinishAllRenderingOnImpl(CompletionEvent* completion) = 0; virtual void SetVisibleOnImpl(bool visible) = 0; virtual void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) = 0; - virtual void FinishGLOnImpl(CompletionEvent* completion) = 0; virtual void MainFrameWillHappenOnImplForTesting( CompletionEvent* completion, bool* main_frame_will_happen) = 0; @@ -50,11 +53,14 @@ class CC_EXPORT ChannelMain { LayerTreeHost* layer_tree_host, base::TimeTicks main_thread_start_time, bool hold_commit_for_activation) = 0; - virtual void InitializeImplOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host) = 0; - virtual void LayerTreeHostClosedOnImpl(CompletionEvent* completion) = 0; - virtual ~ChannelMain() {} + // Must be called before using the channel. + virtual void SynchronouslyInitializeImpl( + LayerTreeHost* layer_tree_host, + scoped_ptr<BeginFrameSource> external_begin_frame_source) = 0; + + // Must be called before deleting the channel. + virtual void SynchronouslyCloseImpl() = 0; }; } // namespace cc diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index b5f0231..6eb60f6 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc @@ -42,8 +42,8 @@ #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/layer_tree_impl.h" +#include "cc/trees/proxy_main.h" #include "cc/trees/single_thread_proxy.h" -#include "cc/trees/thread_proxy.h" #include "cc/trees/tree_synchronizer.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/geometry/vector2d_conversions.h" @@ -143,8 +143,10 @@ void LayerTreeHost::InitializeThreaded( scoped_ptr<BeginFrameSource> external_begin_frame_source) { task_runner_provider_ = TaskRunnerProvider::Create(main_task_runner, impl_task_runner); - InitializeProxy(ThreadProxy::Create(this, task_runner_provider_.get(), - std::move(external_begin_frame_source))); + scoped_ptr<ProxyMain> proxy_main = + ProxyMain::CreateThreaded(this, task_runner_provider_.get(), + std::move(external_begin_frame_source)); + InitializeProxy(std::move(proxy_main)); } void LayerTreeHost::InitializeSingleThreaded( diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index f97d3d2..fdcc26d 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc @@ -49,7 +49,6 @@ #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/single_thread_proxy.h" -#include "cc/trees/thread_proxy.h" #include "gpu/GLES2/gl2extchromium.h" #include "skia/ext/refptr.h" #include "testing/gmock/include/gmock/gmock.h" diff --git a/cc/trees/layer_tree_host_unittest_proxy.cc b/cc/trees/layer_tree_host_unittest_proxy.cc index 293c864..e00b085 100644 --- a/cc/trees/layer_tree_host_unittest_proxy.cc +++ b/cc/trees/layer_tree_host_unittest_proxy.cc @@ -7,15 +7,16 @@ #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_picture_layer.h" #include "cc/test/layer_tree_test.h" -#include "cc/trees/thread_proxy.h" +#include "cc/trees/proxy_impl.h" +#include "cc/trees/proxy_main.h" -#define THREAD_PROXY_TEST_F(TEST_FIXTURE_NAME) \ +#define PROXY_MAIN_THREADED_TEST_F(TEST_FIXTURE_NAME) \ TEST_F(TEST_FIXTURE_NAME, MultiThread) { Run(true); } -// Do common tests for single thread proxy and thread proxy. +// Do common tests for single thread proxy and proxy main in threaded mode. // TODO(simonhong): Add SINGLE_THREAD_PROXY_TEST_F #define PROXY_TEST_SCHEDULED_ACTION(TEST_FIXTURE_NAME) \ - THREAD_PROXY_TEST_F(TEST_FIXTURE_NAME); + PROXY_MAIN_THREADED_TEST_F(TEST_FIXTURE_NAME); namespace cc { @@ -73,12 +74,12 @@ class ProxyTestScheduledActionsBasic : public ProxyTest { PROXY_TEST_SCHEDULED_ACTION(ProxyTestScheduledActionsBasic); -class ThreadProxyTest : public ProxyTest { +class ProxyMainThreaded : public ProxyTest { protected: - ThreadProxyTest() + ProxyMainThreaded() : update_check_layer_( FakePictureLayer::Create(layer_settings(), &client_)) {} - ~ThreadProxyTest() override {} + ~ProxyMainThreaded() override {} void SetupTree() override { layer_tree_host()->SetRootLayer(update_check_layer_); @@ -86,83 +87,69 @@ class ThreadProxyTest : public ProxyTest { client_.set_bounds(update_check_layer_->bounds()); } - const ThreadProxy::MainThreadOnly& ThreadProxyMainOnly() const { - DCHECK(task_runner_provider()); - DCHECK(task_runner_provider()->HasImplThread()); - DCHECK(proxy()); - return static_cast<const ThreadProxy*>(proxy())->main(); - } - - const ThreadProxy::CompositorThreadOnly& ThreadProxyImplOnly() const { - DCHECK(task_runner_provider()); - DCHECK(task_runner_provider()->HasImplThread()); - DCHECK(proxy()); - return static_cast<const ThreadProxy*>(proxy())->impl(); - } - protected: FakeContentLayerClient client_; scoped_refptr<FakePictureLayer> update_check_layer_; private: - DISALLOW_COPY_AND_ASSIGN(ThreadProxyTest); + DISALLOW_COPY_AND_ASSIGN(ProxyMainThreaded); }; -class ThreadProxyTestSetNeedsCommit : public ThreadProxyTest { +class ProxyMainThreadedSetNeedsCommit : public ProxyMainThreaded { protected: - ThreadProxyTestSetNeedsCommit() {} - ~ThreadProxyTestSetNeedsCommit() override {} + ProxyMainThreadedSetNeedsCommit() {} + ~ProxyMainThreadedSetNeedsCommit() override {} void BeginTest() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); proxy()->SetNeedsCommit(); - EXPECT_EQ(ThreadProxy::COMMIT_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ProxyMain::COMMIT_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); } void DidBeginMainFrame() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); } void DidCommit() override { EXPECT_EQ(1, update_check_layer_->update_count()); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); EndTest(); } private: - DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsCommit); + DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsCommit); }; -THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsCommit); +PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsCommit); -class ThreadProxyTestSetNeedsAnimate : public ThreadProxyTest { +class ProxyMainThreadedSetNeedsAnimate : public ProxyMainThreaded { protected: - ThreadProxyTestSetNeedsAnimate() {} - ~ThreadProxyTestSetNeedsAnimate() override {} + ProxyMainThreadedSetNeedsAnimate() {} + ~ProxyMainThreadedSetNeedsAnimate() override {} void BeginTest() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); proxy()->SetNeedsAnimate(); - EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); } void DidBeginMainFrame() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); } void DidCommit() override { @@ -171,31 +158,31 @@ class ThreadProxyTestSetNeedsAnimate : public ThreadProxyTest { } private: - DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsAnimate); + DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsAnimate); }; -THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsAnimate); +PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsAnimate); -class ThreadProxyTestSetNeedsUpdateLayers : public ThreadProxyTest { +class ProxyMainThreadedSetNeedsUpdateLayers : public ProxyMainThreaded { protected: - ThreadProxyTestSetNeedsUpdateLayers() {} - ~ThreadProxyTestSetNeedsUpdateLayers() override {} + ProxyMainThreadedSetNeedsUpdateLayers() {} + ~ProxyMainThreadedSetNeedsUpdateLayers() override {} void BeginTest() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); proxy()->SetNeedsUpdateLayers(); - EXPECT_EQ(ThreadProxy::UPDATE_LAYERS_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ProxyMain::UPDATE_LAYERS_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); } void DidBeginMainFrame() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); } void DidCommit() override { @@ -204,40 +191,40 @@ class ThreadProxyTestSetNeedsUpdateLayers : public ThreadProxyTest { } private: - DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsUpdateLayers); + DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsUpdateLayers); }; -THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsUpdateLayers); +PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsUpdateLayers); -class ThreadProxyTestSetNeedsUpdateLayersWhileAnimating - : public ThreadProxyTest { +class ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating + : public ProxyMainThreaded { protected: - ThreadProxyTestSetNeedsUpdateLayersWhileAnimating() {} - ~ThreadProxyTestSetNeedsUpdateLayersWhileAnimating() override {} + ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating() {} + ~ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating() override {} void BeginTest() override { proxy()->SetNeedsAnimate(); } void WillBeginMainFrame() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); - EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, - ThreadProxyMainOnly().final_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); + EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE, + GetProxyMainForTest()->final_pipeline_stage()); proxy()->SetNeedsUpdateLayers(); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::UPDATE_LAYERS_PIPELINE_STAGE, - ThreadProxyMainOnly().final_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::UPDATE_LAYERS_PIPELINE_STAGE, + GetProxyMainForTest()->final_pipeline_stage()); } void DidBeginMainFrame() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); } void DidCommit() override { @@ -246,39 +233,39 @@ class ThreadProxyTestSetNeedsUpdateLayersWhileAnimating } private: - DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsUpdateLayersWhileAnimating); + DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating); }; -THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsUpdateLayersWhileAnimating); +PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsUpdateLayersWhileAnimating); -class ThreadProxyTestSetNeedsCommitWhileAnimating : public ThreadProxyTest { +class ProxyMainThreadedSetNeedsCommitWhileAnimating : public ProxyMainThreaded { protected: - ThreadProxyTestSetNeedsCommitWhileAnimating() {} - ~ThreadProxyTestSetNeedsCommitWhileAnimating() override {} + ProxyMainThreadedSetNeedsCommitWhileAnimating() {} + ~ProxyMainThreadedSetNeedsCommitWhileAnimating() override {} void BeginTest() override { proxy()->SetNeedsAnimate(); } void WillBeginMainFrame() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); - EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, - ThreadProxyMainOnly().final_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); + EXPECT_EQ(ProxyMain::ANIMATE_PIPELINE_STAGE, + GetProxyMainForTest()->final_pipeline_stage()); proxy()->SetNeedsCommit(); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::COMMIT_PIPELINE_STAGE, - ThreadProxyMainOnly().final_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::COMMIT_PIPELINE_STAGE, + GetProxyMainForTest()->final_pipeline_stage()); } void DidBeginMainFrame() override { - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().max_requested_pipeline_stage); - EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, - ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->max_requested_pipeline_stage()); + EXPECT_EQ(ProxyMain::NO_PIPELINE_STAGE, + GetProxyMainForTest()->current_pipeline_stage()); } void DidCommit() override { @@ -287,15 +274,15 @@ class ThreadProxyTestSetNeedsCommitWhileAnimating : public ThreadProxyTest { } private: - DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsCommitWhileAnimating); + DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedSetNeedsCommitWhileAnimating); }; -THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsCommitWhileAnimating); +PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedSetNeedsCommitWhileAnimating); -class ThreadProxyTestCommitWaitsForActivation : public ThreadProxyTest { +class ProxyMainThreadedCommitWaitsForActivation : public ProxyMainThreaded { protected: - ThreadProxyTestCommitWaitsForActivation() : commits_completed_(0) {} - ~ThreadProxyTestCommitWaitsForActivation() override {} + ProxyMainThreadedCommitWaitsForActivation() : commits_completed_(0) {} + ~ProxyMainThreadedCommitWaitsForActivation() override {} void BeginTest() override { proxy()->SetNeedsCommit(); } @@ -304,25 +291,25 @@ class ThreadProxyTestCommitWaitsForActivation : public ThreadProxyTest { case 0: // The first commit does not wait for activation. Verify that the // completion event is cleared. - EXPECT_FALSE(ThreadProxyImplOnly().commit_completion_event); - EXPECT_FALSE(ThreadProxyImplOnly().next_commit_waits_for_activation); + EXPECT_FALSE(GetProxyImplForTest()->HasCommitCompletionEvent()); + EXPECT_FALSE(GetProxyImplForTest()->GetNextCommitWaitsForActivation()); break; case 1: // The second commit should be held until activation. - EXPECT_TRUE(ThreadProxyImplOnly().commit_completion_event); - EXPECT_TRUE(ThreadProxyImplOnly().next_commit_waits_for_activation); + EXPECT_TRUE(GetProxyImplForTest()->HasCommitCompletionEvent()); + EXPECT_TRUE(GetProxyImplForTest()->GetNextCommitWaitsForActivation()); break; case 2: // The third commit should not wait for activation. - EXPECT_FALSE(ThreadProxyImplOnly().commit_completion_event); - EXPECT_FALSE(ThreadProxyImplOnly().next_commit_waits_for_activation); + EXPECT_FALSE(GetProxyImplForTest()->HasCommitCompletionEvent()); + EXPECT_FALSE(GetProxyImplForTest()->GetNextCommitWaitsForActivation()); } } void DidActivateSyncTree() override { // The next_commit_waits_for_activation should have been cleared after the // sync tree is activated. - EXPECT_FALSE(ThreadProxyImplOnly().next_commit_waits_for_activation); + EXPECT_FALSE(GetProxyImplForTest()->GetNextCommitWaitsForActivation()); } void DidCommit() override { @@ -349,9 +336,9 @@ class ThreadProxyTestCommitWaitsForActivation : public ThreadProxyTest { private: int commits_completed_; - DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestCommitWaitsForActivation); + DISALLOW_COPY_AND_ASSIGN(ProxyMainThreadedCommitWaitsForActivation); }; -THREAD_PROXY_TEST_F(ThreadProxyTestCommitWaitsForActivation); +PROXY_MAIN_THREADED_TEST_F(ProxyMainThreadedCommitWaitsForActivation); } // namespace cc diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc new file mode 100644 index 0000000..810e73e --- /dev/null +++ b/cc/trees/proxy_impl.cc @@ -0,0 +1,684 @@ +// 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_impl.h" + +#include <algorithm> +#include <string> + +#include "base/auto_reset.h" +#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/input/top_controls_manager.h" +#include "cc/output/context_provider.h" +#include "cc/output/output_surface.h" +#include "cc/scheduler/compositor_timing_history.h" +#include "cc/trees/layer_tree_host.h" +#include "cc/trees/layer_tree_impl.h" +#include "cc/trees/task_runner_provider.h" +#include "gpu/command_buffer/client/gles2_interface.h" + +namespace cc { + +namespace { + +// Measured in seconds. +const double kSmoothnessTakesPriorityExpirationDelay = 0.25; + +unsigned int nextBeginFrameId = 0; + +} // namespace + +scoped_ptr<ProxyImpl> ProxyImpl::Create( + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) { + return make_scoped_ptr(new ProxyImpl(channel_impl, layer_tree_host, + task_runner_provider, + std::move(external_begin_frame_source))); +} + +ProxyImpl::ProxyImpl(ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) + : layer_tree_host_id_(layer_tree_host->id()), + next_commit_waits_for_activation_(false), + commit_completion_event_(nullptr), + next_frame_is_newly_committed_frame_(false), + inside_draw_(false), + input_throttled_until_commit_(false), + task_runner_provider_(task_runner_provider), + smoothness_priority_expiration_notifier_( + task_runner_provider->ImplThreadTaskRunner(), + base::Bind(&ProxyImpl::RenewTreePriority, base::Unretained(this)), + base::TimeDelta::FromSeconds( + kSmoothnessTakesPriorityExpirationDelay)), + external_begin_frame_source_(std::move(external_begin_frame_source)), + rendering_stats_instrumentation_( + layer_tree_host->rendering_stats_instrumentation()), + channel_impl_(channel_impl) { + TRACE_EVENT0("cc", "ProxyImpl::ProxyImpl"); + DCHECK(IsImplThread()); + DCHECK(IsMainThreadBlocked()); + + layer_tree_host_impl_ = layer_tree_host->CreateLayerTreeHostImpl(this); + + SchedulerSettings scheduler_settings( + layer_tree_host->settings().ToSchedulerSettings()); + + scoped_ptr<CompositorTimingHistory> compositor_timing_history( + new CompositorTimingHistory(CompositorTimingHistory::RENDERER_UMA, + rendering_stats_instrumentation_)); + + scheduler_ = Scheduler::Create(this, scheduler_settings, layer_tree_host_id_, + task_runner_provider_->ImplThreadTaskRunner(), + external_begin_frame_source_.get(), + std::move(compositor_timing_history)); + + DCHECK_EQ(scheduler_->visible(), layer_tree_host_impl_->visible()); +} + +ProxyImpl::BlockedMainCommitOnly::BlockedMainCommitOnly() + : layer_tree_host(nullptr) {} + +ProxyImpl::BlockedMainCommitOnly::~BlockedMainCommitOnly() {} + +ProxyImpl::~ProxyImpl() { + TRACE_EVENT0("cc", "ProxyImpl::~ProxyImpl"); + DCHECK(IsImplThread()); + DCHECK(IsMainThreadBlocked()); + + scheduler_ = nullptr; + external_begin_frame_source_ = nullptr; + layer_tree_host_impl_ = nullptr; + // We need to explicitly shutdown the notifier to destroy any weakptrs it is + // holding while still on the compositor thread. This also ensures any + // callbacks holding a ProxyImpl pointer are cancelled. + smoothness_priority_expiration_notifier_.Shutdown(); +} + +void ProxyImpl::SetThrottleFrameProductionOnImpl(bool throttle) { + TRACE_EVENT1("cc", "ProxyImpl::SetThrottleFrameProductionOnImplThread", + "throttle", throttle); + DCHECK(IsImplThread()); + scheduler_->SetThrottleFrameProduction(throttle); +} + +void ProxyImpl::UpdateTopControlsStateOnImpl(TopControlsState constraints, + TopControlsState current, + bool animate) { + DCHECK(IsImplThread()); + layer_tree_host_impl_->top_controls_manager()->UpdateTopControlsState( + constraints, current, animate); +} + +void ProxyImpl::InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) { + TRACE_EVENT0("cc", "ProxyImpl::InitializeOutputSurfaceOnImplThread"); + DCHECK(IsImplThread()); + + LayerTreeHostImpl* host_impl = layer_tree_host_impl_.get(); + bool success = host_impl->InitializeRenderer(output_surface); + RendererCapabilities capabilities; + if (success) { + capabilities = + host_impl->GetRendererCapabilities().MainThreadCapabilities(); + } + + channel_impl_->DidInitializeOutputSurface(success, capabilities); + + if (success) + scheduler_->DidCreateAndInitializeOutputSurface(); +} + +void ProxyImpl::MainThreadHasStoppedFlingingOnImpl() { + DCHECK(IsImplThread()); + layer_tree_host_impl_->MainThreadHasStoppedFlinging(); +} + +void ProxyImpl::SetInputThrottledUntilCommitOnImpl(bool is_throttled) { + DCHECK(IsImplThread()); + if (is_throttled == input_throttled_until_commit_) + return; + input_throttled_until_commit_ = is_throttled; + RenewTreePriority(); +} + +void ProxyImpl::SetDeferCommitsOnImpl(bool defer_commits) const { + DCHECK(IsImplThread()); + scheduler_->SetDeferCommits(defer_commits); +} + +void ProxyImpl::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) { + DCHECK(IsImplThread()); + SetNeedsRedrawRectOnImplThread(damage_rect); +} + +void ProxyImpl::SetNeedsCommitOnImpl() { + DCHECK(IsImplThread()); + SetNeedsCommitOnImplThread(); +} + +void ProxyImpl::BeginMainFrameAbortedOnImpl( + CommitEarlyOutReason reason, + base::TimeTicks main_thread_start_time) { + TRACE_EVENT1("cc", "ProxyImpl::BeginMainFrameAbortedOnImplThread", "reason", + CommitEarlyOutReasonToString(reason)); + DCHECK(IsImplThread()); + DCHECK(scheduler_->CommitPending()); + DCHECK(!layer_tree_host_impl_->pending_tree()); + + if (CommitEarlyOutHandledCommit(reason)) { + SetInputThrottledUntilCommitOnImpl(false); + last_processed_begin_main_frame_args_ = last_begin_main_frame_args_; + } + layer_tree_host_impl_->BeginMainFrameAborted(reason); + scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time); + scheduler_->BeginMainFrameAborted(reason); +} + +void ProxyImpl::FinishAllRenderingOnImpl(CompletionEvent* completion) { + TRACE_EVENT0("cc", "ProxyImpl::FinishAllRenderingOnImplThread"); + DCHECK(IsImplThread()); + layer_tree_host_impl_->FinishAllRendering(); + completion->Signal(); +} + +void ProxyImpl::SetVisibleOnImpl(bool visible) { + TRACE_EVENT1("cc", "ProxyImpl::SetVisibleOnImplThread", "visible", visible); + DCHECK(IsImplThread()); + layer_tree_host_impl_->SetVisible(visible); + scheduler_->SetVisible(visible); +} + +void ProxyImpl::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) { + DCHECK(IsImplThread()); + + // Unlike DidLoseOutputSurfaceOnImplThread, we don't need to call + // LayerTreeHost::DidLoseOutputSurface since it already knows. + scheduler_->DidLoseOutputSurface(); + layer_tree_host_impl_->ReleaseOutputSurface(); + completion->Signal(); +} + +void ProxyImpl::FinishGLOnImpl(CompletionEvent* completion) { + TRACE_EVENT0("cc", "ProxyImpl::FinishGLOnImplThread"); + DCHECK(IsImplThread()); + if (layer_tree_host_impl_->output_surface()) { + ContextProvider* context_provider = + layer_tree_host_impl_->output_surface()->context_provider(); + if (context_provider) + context_provider->ContextGL()->Finish(); + } + completion->Signal(); +} + +void ProxyImpl::MainFrameWillHappenOnImplForTesting( + CompletionEvent* completion, + bool* main_frame_will_happen) { + DCHECK(IsImplThread()); + if (layer_tree_host_impl_->output_surface()) { + *main_frame_will_happen = scheduler_->MainFrameForTestingWillHappen(); + } else { + *main_frame_will_happen = false; + } + completion->Signal(); +} + +void ProxyImpl::StartCommitOnImpl(CompletionEvent* completion, + LayerTreeHost* layer_tree_host, + base::TimeTicks main_thread_start_time, + bool hold_commit_for_activation) { + TRACE_EVENT0("cc", "ProxyImpl::StartCommitOnImplThread"); + DCHECK(!commit_completion_event_); + DCHECK(IsImplThread() && IsMainThreadBlocked()); + DCHECK(scheduler_); + DCHECK(scheduler_->CommitPending()); + + if (hold_commit_for_activation) { + // This commit may be aborted. Store the value for + // hold_commit_for_activation so that whenever the next commit is started, + // the main thread will be unblocked only after pending tree activation. + next_commit_waits_for_activation_ = hold_commit_for_activation; + } + + if (!layer_tree_host_impl_) { + TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoLayerTree", + TRACE_EVENT_SCOPE_THREAD); + completion->Signal(); + return; + } + + // Ideally, we should inform to impl thread when BeginMainFrame is started. + // But, we can avoid a PostTask in here. + scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time); + commit_completion_event_ = completion; + DCHECK(!blocked_main_commit().layer_tree_host); + blocked_main_commit().layer_tree_host = layer_tree_host; + scheduler_->NotifyReadyToCommit(); +} + +void ProxyImpl::UpdateRendererCapabilitiesOnImplThread() { + DCHECK(IsImplThread()); + channel_impl_->SetRendererCapabilitiesMainCopy( + layer_tree_host_impl_->GetRendererCapabilities() + .MainThreadCapabilities()); +} + +void ProxyImpl::DidLoseOutputSurfaceOnImplThread() { + TRACE_EVENT0("cc", "ProxyImpl::DidLoseOutputSurfaceOnImplThread"); + DCHECK(IsImplThread()); + channel_impl_->DidLoseOutputSurface(); + scheduler_->DidLoseOutputSurface(); +} + +void ProxyImpl::CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + DCHECK(IsImplThread()); + scheduler_->CommitVSyncParameters(timebase, interval); +} + +void ProxyImpl::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { + DCHECK(IsImplThread()); + scheduler_->SetEstimatedParentDrawTime(draw_time); +} + +void ProxyImpl::DidSwapBuffersOnImplThread() { + DCHECK(IsImplThread()); + scheduler_->DidSwapBuffers(); +} + +void ProxyImpl::DidSwapBuffersCompleteOnImplThread() { + TRACE_EVENT0("cc,benchmark", "ProxyImpl::DidSwapBuffersCompleteOnImplThread"); + DCHECK(IsImplThread()); + scheduler_->DidSwapBuffersComplete(); + channel_impl_->DidCompleteSwapBuffers(); +} + +void ProxyImpl::OnResourcelessSoftareDrawStateChanged(bool resourceless_draw) { + DCHECK(IsImplThread()); + scheduler_->SetResourcelessSoftareDraw(resourceless_draw); +} + +void ProxyImpl::OnCanDrawStateChanged(bool can_draw) { + TRACE_EVENT1("cc", "ProxyImpl::OnCanDrawStateChanged", "can_draw", can_draw); + DCHECK(IsImplThread()); + scheduler_->SetCanDraw(can_draw); +} + +void ProxyImpl::NotifyReadyToActivate() { + TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToActivate"); + DCHECK(IsImplThread()); + scheduler_->NotifyReadyToActivate(); +} + +void ProxyImpl::NotifyReadyToDraw() { + TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToDraw"); + DCHECK(IsImplThread()); + scheduler_->NotifyReadyToDraw(); +} + +void ProxyImpl::SetNeedsRedrawOnImplThread() { + TRACE_EVENT0("cc", "ProxyImpl::SetNeedsRedrawOnImplThread"); + DCHECK(IsImplThread()); + scheduler_->SetNeedsRedraw(); +} + +void ProxyImpl::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) { + DCHECK(IsImplThread()); + layer_tree_host_impl_->SetViewportDamage(damage_rect); + SetNeedsRedrawOnImplThread(); +} + +void ProxyImpl::SetNeedsOneBeginImplFrameOnImplThread() { + TRACE_EVENT0("cc", "ProxyImpl::SetNeedsOneBeginImplFrameOnImplThread"); + DCHECK(IsImplThread()); + scheduler_->SetNeedsOneBeginImplFrame(); +} + +void ProxyImpl::SetNeedsPrepareTilesOnImplThread() { + DCHECK(IsImplThread()); + scheduler_->SetNeedsPrepareTiles(); +} + +void ProxyImpl::SetNeedsCommitOnImplThread() { + TRACE_EVENT0("cc", "ProxyImpl::SetNeedsCommitOnImplThread"); + DCHECK(IsImplThread()); + scheduler_->SetNeedsBeginMainFrame(); +} + +void ProxyImpl::SetVideoNeedsBeginFrames(bool needs_begin_frames) { + TRACE_EVENT1("cc", "ProxyImpl::SetVideoNeedsBeginFrames", + "needs_begin_frames", needs_begin_frames); + DCHECK(IsImplThread()); + // In tests the layer tree is destroyed after the scheduler is. + if (scheduler_) + scheduler_->SetVideoNeedsBeginFrames(needs_begin_frames); +} + +void ProxyImpl::PostAnimationEventsToMainThreadOnImplThread( + scoped_ptr<AnimationEventsVector> events) { + TRACE_EVENT0("cc", "ProxyImpl::PostAnimationEventsToMainThreadOnImplThread"); + DCHECK(IsImplThread()); + channel_impl_->SetAnimationEvents(std::move(events)); +} + +bool ProxyImpl::IsInsideDraw() { + return inside_draw_; +} + +void ProxyImpl::RenewTreePriority() { + DCHECK(IsImplThread()); + bool smoothness_takes_priority = + layer_tree_host_impl_->pinch_gesture_active() || + layer_tree_host_impl_->page_scale_animation_active() || + layer_tree_host_impl_->IsActivelyScrolling(); + + // Schedule expiration if smoothness currently takes priority. + if (smoothness_takes_priority) + smoothness_priority_expiration_notifier_.Schedule(); + + // We use the same priority for both trees by default. + TreePriority tree_priority = SAME_PRIORITY_FOR_BOTH_TREES; + + // Smoothness takes priority if we have an expiration for it scheduled. + if (smoothness_priority_expiration_notifier_.HasPendingNotification()) + tree_priority = SMOOTHNESS_TAKES_PRIORITY; + + // New content always takes priority when there is an invalid viewport size or + // ui resources have been evicted. + if (layer_tree_host_impl_->active_tree()->ViewportSizeInvalid() || + layer_tree_host_impl_->EvictedUIResourcesExist() || + input_throttled_until_commit_) { + // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active + // tree might be freed. We need to set RequiresHighResToDraw to ensure that + // high res tiles will be required to activate pending tree. + layer_tree_host_impl_->SetRequiresHighResToDraw(); + tree_priority = NEW_CONTENT_TAKES_PRIORITY; + } + + layer_tree_host_impl_->SetTreePriority(tree_priority); + + // Only put the scheduler in impl latency prioritization mode if we don't + // have a scroll listener. This gives the scroll listener a better chance of + // handling scroll updates within the same frame. The tree itself is still + // kept in prefer smoothness mode to allow checkerboarding. + ScrollHandlerState scroll_handler_state = + layer_tree_host_impl_->scroll_affects_scroll_handler() + ? ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER + : ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER; + scheduler_->SetTreePrioritiesAndScrollState(tree_priority, + scroll_handler_state); + + // Notify the the client of this compositor via the output surface. + // TODO(epenner): Route this to compositor-thread instead of output-surface + // after GTFO refactor of compositor-thread (http://crbug/170828). + if (layer_tree_host_impl_->output_surface()) { + layer_tree_host_impl_->output_surface()->UpdateSmoothnessTakesPriority( + tree_priority == SMOOTHNESS_TAKES_PRIORITY); + } +} + +void ProxyImpl::PostDelayedAnimationTaskOnImplThread(const base::Closure& task, + base::TimeDelta delay) { + DCHECK(IsImplThread()); + task_runner_provider_->ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, + task, delay); +} + +void ProxyImpl::DidActivateSyncTree() { + TRACE_EVENT0("cc", "ProxyImpl::DidActivateSyncTreeOnImplThread"); + DCHECK(IsImplThread()); + + if (next_commit_waits_for_activation_) { + TRACE_EVENT_INSTANT0("cc", "ReleaseCommitbyActivation", + TRACE_EVENT_SCOPE_THREAD); + DCHECK(commit_completion_event_); + commit_completion_event_->Signal(); + commit_completion_event_ = nullptr; + next_commit_waits_for_activation_ = false; + } + + last_processed_begin_main_frame_args_ = last_begin_main_frame_args_; +} + +void ProxyImpl::WillPrepareTiles() { + DCHECK(IsImplThread()); + scheduler_->WillPrepareTiles(); +} + +void ProxyImpl::DidPrepareTiles() { + DCHECK(IsImplThread()); + scheduler_->DidPrepareTiles(); +} + +void ProxyImpl::DidCompletePageScaleAnimationOnImplThread() { + DCHECK(IsImplThread()); + channel_impl_->DidCompletePageScaleAnimation(); +} + +void ProxyImpl::OnDrawForOutputSurface() { + DCHECK(IsImplThread()); + scheduler_->OnDrawForOutputSurface(); +} + +void ProxyImpl::PostFrameTimingEventsOnImplThread( + scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, + scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { + DCHECK(IsImplThread()); + channel_impl_->PostFrameTimingEventsOnMain(std::move(composite_events), + std::move(main_frame_events)); +} + +void ProxyImpl::WillBeginImplFrame(const BeginFrameArgs& args) { + DCHECK(IsImplThread()); + layer_tree_host_impl_->WillBeginImplFrame(args); + if (last_processed_begin_main_frame_args_.IsValid()) { + // Last processed begin main frame args records the frame args that we sent + // to the main thread for the last frame that we've processed. If that is + // set, that means the current frame is one past the frame in which we've + // finished the processing. + layer_tree_host_impl_->RecordMainFrameTiming( + last_processed_begin_main_frame_args_, args); + last_processed_begin_main_frame_args_ = BeginFrameArgs(); + } +} + +void ProxyImpl::DidFinishImplFrame() { + DCHECK(IsImplThread()); + layer_tree_host_impl_->DidFinishImplFrame(); +} + +void ProxyImpl::ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) { + DCHECK(IsImplThread()); + unsigned int begin_frame_id = nextBeginFrameId++; + benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( + benchmark_instrumentation::kSendBeginFrame, begin_frame_id); + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state( + new BeginMainFrameAndCommitState); + begin_main_frame_state->begin_frame_id = begin_frame_id; + begin_main_frame_state->begin_frame_args = args; + begin_main_frame_state->scroll_info = + layer_tree_host_impl_->ProcessScrollDeltas(); + begin_main_frame_state->memory_allocation_limit_bytes = + layer_tree_host_impl_->memory_allocation_limit_bytes(); + begin_main_frame_state->evicted_ui_resources = + layer_tree_host_impl_->EvictedUIResourcesExist(); + // TODO(vmpstr): This needs to be fixed if + // main_frame_before_activation_enabled is set, since we might run this code + // twice before recording a duration. crbug.com/469824 + last_begin_main_frame_args_ = begin_main_frame_state->begin_frame_args; + channel_impl_->BeginMainFrame(std::move(begin_main_frame_state)); + devtools_instrumentation::DidRequestMainThreadFrame(layer_tree_host_id_); +} + +DrawResult ProxyImpl::ScheduledActionDrawAndSwapIfPossible() { + TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionDrawAndSwap"); + DCHECK(IsImplThread()); + + // SchedulerStateMachine::DidDrawIfPossibleCompleted isn't set up to + // handle DRAW_ABORTED_CANT_DRAW. Moreover, the scheduler should + // never generate this call when it can't draw. + DCHECK(layer_tree_host_impl_->CanDraw()); + + bool forced_draw = false; + return DrawAndSwapInternal(forced_draw); +} + +DrawResult ProxyImpl::ScheduledActionDrawAndSwapForced() { + TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionDrawAndSwapForced"); + DCHECK(IsImplThread()); + bool forced_draw = true; + return DrawAndSwapInternal(forced_draw); +} + +void ProxyImpl::ScheduledActionCommit() { + TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionCommit"); + DCHECK(IsImplThread()); + DCHECK(IsMainThreadBlocked()); + DCHECK(commit_completion_event_); + + layer_tree_host_impl_->BeginCommit(); + blocked_main_commit().layer_tree_host->FinishCommitOnImplThread( + layer_tree_host_impl_.get()); + + // Remove the LayerTreeHost reference before the completion event is signaled + // and cleared. This is necessary since blocked_main_commit() allows access + // only while we have the completion event to ensure the main thread is + // blocked for a commit. + blocked_main_commit().layer_tree_host = nullptr; + + if (next_commit_waits_for_activation_) { + // For some layer types in impl-side painting, the commit is held until + // the sync tree is activated. It's also possible that the + // sync tree has already activated if there was no work to be done. + TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD); + } else { + commit_completion_event_->Signal(); + commit_completion_event_ = nullptr; + } + + scheduler_->DidCommit(); + + // Delay this step until afer the main thread has been released as it's + // often a good bit of work to update the tree and prepare the new frame. + layer_tree_host_impl_->CommitComplete(); + + SetInputThrottledUntilCommitOnImpl(false); + + next_frame_is_newly_committed_frame_ = true; +} + +void ProxyImpl::ScheduledActionActivateSyncTree() { + TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionActivateSyncTree"); + DCHECK(IsImplThread()); + layer_tree_host_impl_->ActivateSyncTree(); +} + +void ProxyImpl::ScheduledActionBeginOutputSurfaceCreation() { + TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionBeginOutputSurfaceCreation"); + DCHECK(IsImplThread()); + channel_impl_->RequestNewOutputSurface(); +} + +void ProxyImpl::ScheduledActionPrepareTiles() { + TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionPrepareTiles"); + DCHECK(IsImplThread()); + layer_tree_host_impl_->PrepareTiles(); +} + +void ProxyImpl::ScheduledActionInvalidateOutputSurface() { + TRACE_EVENT0("cc", "ProxyImpl::ScheduledActionInvalidateOutputSurface"); + DCHECK(IsImplThread()); + DCHECK(layer_tree_host_impl_->output_surface()); + layer_tree_host_impl_->output_surface()->Invalidate(); +} + +void ProxyImpl::SendBeginFramesToChildren(const BeginFrameArgs& args) { + NOTREACHED() << "Only used by SingleThreadProxy"; +} + +void ProxyImpl::SendBeginMainFrameNotExpectedSoon() { + DCHECK(IsImplThread()); + channel_impl_->BeginMainFrameNotExpectedSoon(); +} + +DrawResult ProxyImpl::DrawAndSwapInternal(bool forced_draw) { + TRACE_EVENT_SYNTHETIC_DELAY("cc.DrawAndSwap"); + + DCHECK(IsImplThread()); + DCHECK(layer_tree_host_impl_.get()); + + base::AutoReset<bool> mark_inside(&inside_draw_, true); + + if (layer_tree_host_impl_->pending_tree()) { + bool update_lcd_text = false; + layer_tree_host_impl_->pending_tree()->UpdateDrawProperties( + update_lcd_text); + } + + // This method is called on a forced draw, regardless of whether we are able + // to produce a frame, as the calling site on main thread is blocked until its + // request completes, and we signal completion here. If CanDraw() is false, we + // will indicate success=false to the caller, but we must still signal + // completion to avoid deadlock. + + // We guard PrepareToDraw() with CanDraw() because it always returns a valid + // frame, so can only be used when such a frame is possible. Since + // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on + // CanDraw() as well. + + LayerTreeHostImpl::FrameData frame; + bool draw_frame = false; + + DrawResult result; + if (layer_tree_host_impl_->CanDraw()) { + result = layer_tree_host_impl_->PrepareToDraw(&frame); + draw_frame = forced_draw || result == DRAW_SUCCESS; + } else { + result = DRAW_ABORTED_CANT_DRAW; + } + + if (draw_frame) { + layer_tree_host_impl_->DrawLayers(&frame); + result = DRAW_SUCCESS; + } else { + DCHECK_NE(DRAW_SUCCESS, result); + } + layer_tree_host_impl_->DidDrawAllLayers(frame); + + bool start_ready_animations = draw_frame; + layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); + + if (draw_frame) + layer_tree_host_impl_->SwapBuffers(frame); + + // Tell the main thread that the the newly-commited frame was drawn. + if (next_frame_is_newly_committed_frame_) { + next_frame_is_newly_committed_frame_ = false; + channel_impl_->DidCommitAndDrawFrame(); + } + + DCHECK_NE(INVALID_RESULT, result); + return result; +} + +bool ProxyImpl::IsImplThread() const { + return task_runner_provider_->IsImplThread(); +} + +bool ProxyImpl::IsMainThreadBlocked() const { + return task_runner_provider_->IsMainThreadBlocked(); +} + +ProxyImpl::BlockedMainCommitOnly& ProxyImpl::blocked_main_commit() { + DCHECK(IsMainThreadBlocked() && commit_completion_event_); + return main_thread_blocked_commit_vars_unsafe_; +} + +} // namespace cc diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h index 4b0cdaa..092385b 100644 --- a/cc/trees/proxy_impl.h +++ b/cc/trees/proxy_impl.h @@ -5,59 +5,171 @@ #ifndef CC_TREES_PROXY_IMPL_H_ #define CC_TREES_PROXY_IMPL_H_ -#include "base/memory/weak_ptr.h" -#include "cc/base/cc_export.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "cc/base/completion_event.h" +#include "cc/base/delayed_unique_notifier.h" #include "cc/input/top_controls_state.h" -#include "cc/output/output_surface.h" -#include "cc/scheduler/commit_earlyout_reason.h" -#include "cc/trees/proxy_common.h" +#include "cc/scheduler/scheduler.h" +#include "cc/trees/channel_impl.h" +#include "cc/trees/layer_tree_host_impl.h" namespace cc { -// TODO(khushalsagar): The impl side of ThreadProxy. It is currently defined as -// an interface with the implementation provided by ThreadProxy and will be -// made an independent class. -// The methods added to this interface should only use the CompositorThreadOnly -// variables from ThreadProxy. -// See crbug/527200 -class CC_EXPORT ProxyImpl { - private: - friend class ThreadedChannel; - // Callback for impl side commands received from the channel. - virtual void SetThrottleFrameProductionOnImpl(bool throttle) = 0; +// This class aggregates all the interactions that the main side of the +// compositor needs to have with the impl side. It is created and owned by the +// ChannelImpl implementation. The class lives entirely on the impl thread. +class CC_EXPORT ProxyImpl : public NON_EXPORTED_BASE(LayerTreeHostImplClient), + public NON_EXPORTED_BASE(SchedulerClient) { + public: + static scoped_ptr<ProxyImpl> Create( + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + + ~ProxyImpl() override; + + // Virtual for testing. + virtual void SetThrottleFrameProductionOnImpl(bool throttle); virtual void UpdateTopControlsStateOnImpl(TopControlsState constraints, TopControlsState current, - bool animate) = 0; - virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) = 0; - virtual void MainThreadHasStoppedFlingingOnImpl() = 0; - virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled) = 0; - virtual void SetDeferCommitsOnImpl(bool defer_commits) const = 0; - virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) = 0; - virtual void SetNeedsCommitOnImpl() = 0; - virtual void FinishAllRenderingOnImpl(CompletionEvent* completion) = 0; - virtual void SetVisibleOnImpl(bool visible) = 0; - virtual void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) = 0; - virtual void FinishGLOnImpl(CompletionEvent* completion) = 0; - virtual void MainFrameWillHappenOnImplForTesting( - CompletionEvent* completion, - bool* main_frame_will_happen) = 0; + bool animate); + virtual void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface); + virtual void MainThreadHasStoppedFlingingOnImpl(); + virtual void SetInputThrottledUntilCommitOnImpl(bool is_throttled); + virtual void SetDeferCommitsOnImpl(bool defer_commits) const; + virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect); + virtual void SetNeedsCommitOnImpl(); virtual void BeginMainFrameAbortedOnImpl( CommitEarlyOutReason reason, - base::TimeTicks main_thread_start_time) = 0; + base::TimeTicks main_thread_start_time); + virtual void FinishAllRenderingOnImpl(CompletionEvent* completion); + virtual void SetVisibleOnImpl(bool visible); + virtual void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion); + virtual void FinishGLOnImpl(CompletionEvent* completion); + virtual void MainFrameWillHappenOnImplForTesting( + CompletionEvent* completion, + bool* main_frame_will_happen); virtual void StartCommitOnImpl(CompletionEvent* completion, LayerTreeHost* layer_tree_host, base::TimeTicks main_thread_start_time, - bool hold_commit_for_activation) = 0; - virtual void InitializeImplOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host) = 0; - virtual void LayerTreeHostClosedOnImpl(CompletionEvent* completion) = 0; - - // TODO(khushalsagar): Rename as GetWeakPtr() once ThreadProxy is split. - virtual base::WeakPtr<ProxyImpl> GetImplWeakPtr() = 0; + bool hold_commit_for_activation); protected: - virtual ~ProxyImpl() {} + // protected for testing. + ProxyImpl(ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + + private: + // The members of this struct should be accessed on the impl thread only when + // the main thread is blocked for a commit. + struct BlockedMainCommitOnly { + BlockedMainCommitOnly(); + ~BlockedMainCommitOnly(); + LayerTreeHost* layer_tree_host; + }; + + friend class ProxyImplForTest; + + // LayerTreeHostImplClient implementation + void UpdateRendererCapabilitiesOnImplThread() override; + void DidLoseOutputSurfaceOnImplThread() override; + void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) override; + void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override; + void DidSwapBuffersOnImplThread() override; + void DidSwapBuffersCompleteOnImplThread() override; + void OnResourcelessSoftareDrawStateChanged(bool resourceless_draw) override; + void OnCanDrawStateChanged(bool can_draw) override; + void NotifyReadyToActivate() override; + void NotifyReadyToDraw() override; + // Please call these 3 functions through + // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and + // SetNeedsOneBeginImplFrame(). + void SetNeedsRedrawOnImplThread() override; + void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override; + void SetNeedsOneBeginImplFrameOnImplThread() override; + void SetNeedsPrepareTilesOnImplThread() override; + void SetNeedsCommitOnImplThread() override; + void SetVideoNeedsBeginFrames(bool needs_begin_frames) override; + void PostAnimationEventsToMainThreadOnImplThread( + scoped_ptr<AnimationEventsVector> queue) override; + bool IsInsideDraw() override; + void RenewTreePriority() override; + void PostDelayedAnimationTaskOnImplThread(const base::Closure& task, + base::TimeDelta delay) override; + void DidActivateSyncTree() override; + void WillPrepareTiles() override; + void DidPrepareTiles() override; + void DidCompletePageScaleAnimationOnImplThread() override; + void OnDrawForOutputSurface() override; + // This should only be called by LayerTreeHostImpl::PostFrameTimingEvents. + void PostFrameTimingEventsOnImplThread( + scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, + scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) + override; + + // SchedulerClient implementation + void WillBeginImplFrame(const BeginFrameArgs& args) override; + void DidFinishImplFrame() override; + void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override; + DrawResult ScheduledActionDrawAndSwapIfPossible() override; + DrawResult ScheduledActionDrawAndSwapForced() override; + void ScheduledActionCommit() override; + void ScheduledActionActivateSyncTree() override; + void ScheduledActionBeginOutputSurfaceCreation() override; + void ScheduledActionPrepareTiles() override; + void ScheduledActionInvalidateOutputSurface() override; + void SendBeginFramesToChildren(const BeginFrameArgs& args) override; + void SendBeginMainFrameNotExpectedSoon() override; + + DrawResult DrawAndSwapInternal(bool forced_draw); + + bool IsImplThread() const; + bool IsMainThreadBlocked() const; + + const int layer_tree_host_id_; + + scoped_ptr<Scheduler> scheduler_; + + // Set when the main thread is waiting on a pending tree activation. + bool next_commit_waits_for_activation_; + + // Set when the main thread is waiting on a commit to complete or on a + // pending tree activation. + CompletionEvent* commit_completion_event_; + + // Set when the next draw should post DidCommitAndDrawFrame to the main + // thread. + bool next_frame_is_newly_committed_frame_; + + bool inside_draw_; + bool input_throttled_until_commit_; + + TaskRunnerProvider* task_runner_provider_; + + DelayedUniqueNotifier smoothness_priority_expiration_notifier_; + + scoped_ptr<BeginFrameSource> external_begin_frame_source_; + + RenderingStatsInstrumentation* rendering_stats_instrumentation_; + + // Values used to keep track of frame durations. Used only in frame timing. + BeginFrameArgs last_begin_main_frame_args_; + BeginFrameArgs last_processed_begin_main_frame_args_; + + scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl_; + + ChannelImpl* channel_impl_; + + // Use accessors instead of this variable directly. + BlockedMainCommitOnly main_thread_blocked_commit_vars_unsafe_; + BlockedMainCommitOnly& blocked_main_commit(); + + DISALLOW_COPY_AND_ASSIGN(ProxyImpl); }; } // namespace cc diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc new file mode 100644 index 0000000..dd5ac1a --- /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 diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h index fbe191d..edc2a22 100644 --- a/cc/trees/proxy_main.h +++ b/cc/trees/proxy_main.h @@ -5,56 +5,155 @@ #ifndef CC_TREES_PROXY_MAIN_H_ #define CC_TREES_PROXY_MAIN_H_ -#include "base/memory/weak_ptr.h" +#include "base/macros.h" #include "cc/animation/animation_events.h" #include "cc/base/cc_export.h" #include "cc/debug/frame_timing_tracker.h" +#include "cc/input/top_controls_state.h" +#include "cc/output/output_surface.h" #include "cc/output/renderer_capabilities.h" +#include "cc/trees/channel_main.h" +#include "cc/trees/proxy.h" #include "cc/trees/proxy_common.h" namespace cc { -class ThreadedChannel; - -// TODO(khushalsagar): The main side of ThreadProxy. It is currently defined as -// an interface with the implementation provided by ThreadProxy and will be -// made an independent class. -// The methods added to this interface should only use the MainThreadOnly or -// BlockedMainThread variables from ThreadProxy. -// See crbug/527200. -class CC_EXPORT ProxyMain { +class BeginFrameSource; +class ChannelMain; +class LayerTreeHost; + +// This class aggregates all interactions that the impl side of the compositor +// needs to have with the main side. +// The class is created and lives on the main thread. +class CC_EXPORT ProxyMain : public Proxy { public: - // TODO(khushalsagar): Make this ChannelMain*. When ProxyMain and - // ProxyImpl are split, ProxyImpl will be passed a reference to ChannelImpl - // at creation. Right now we just set it directly from ThreadedChannel - // when the impl side is initialized. - virtual void SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) = 0; + static scoped_ptr<ProxyMain> CreateThreaded( + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); - protected: - virtual ~ProxyMain() {} + ~ProxyMain() override; - private: - friend class ThreadedChannel; - // Callback for main side commands received from the Channel. - virtual void DidCompleteSwapBuffers() = 0; - virtual void SetRendererCapabilitiesMainCopy( - const RendererCapabilities& capabilities) = 0; - virtual void BeginMainFrameNotExpectedSoon() = 0; - virtual void DidCommitAndDrawFrame() = 0; - virtual void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue) = 0; - virtual void DidLoseOutputSurface() = 0; - virtual void RequestNewOutputSurface() = 0; + // Commits between the main and impl threads are processed through a pipeline + // with the following stages. For efficiency we can early out at any stage if + // we decide that no further processing is necessary. + enum CommitPipelineStage { + NO_PIPELINE_STAGE, + ANIMATE_PIPELINE_STAGE, + UPDATE_LAYERS_PIPELINE_STAGE, + COMMIT_PIPELINE_STAGE, + }; + + // Virtual for testing. + virtual void DidCompleteSwapBuffers(); + virtual void SetRendererCapabilities( + const RendererCapabilities& capabilities); + virtual void BeginMainFrameNotExpectedSoon(); + virtual void DidCommitAndDrawFrame(); + virtual void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue); + virtual void DidLoseOutputSurface(); + virtual void RequestNewOutputSurface(); virtual void DidInitializeOutputSurface( bool success, - const RendererCapabilities& capabilities) = 0; - virtual void DidCompletePageScaleAnimation() = 0; + const RendererCapabilities& capabilities); + virtual void DidCompletePageScaleAnimation(); virtual void PostFrameTimingEventsOnMain( scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, - scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) = 0; + scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events); virtual void BeginMainFrame( - scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) = 0; + scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state); + + ChannelMain* channel_main() const { return channel_main_.get(); } + CommitPipelineStage max_requested_pipeline_stage() const { + return max_requested_pipeline_stage_; + } + CommitPipelineStage current_pipeline_stage() const { + return current_pipeline_stage_; + } + CommitPipelineStage final_pipeline_stage() const { + return final_pipeline_stage_; + } + + protected: + ProxyMain(LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + + private: + friend class ProxyMainForTest; + + // Proxy implementation. + void FinishAllRendering() override; + bool IsStarted() const override; + bool CommitToActiveTree() const override; + void SetOutputSurface(OutputSurface* output_surface) override; + void SetVisible(bool visible) override; + void SetThrottleFrameProduction(bool throttle) override; + const RendererCapabilities& GetRendererCapabilities() const override; + void SetNeedsAnimate() override; + void SetNeedsUpdateLayers() override; + void SetNeedsCommit() override; + void SetNeedsRedraw(const gfx::Rect& damage_rect) override; + void SetNextCommitWaitsForActivation() override; + void NotifyInputThrottledUntilCommit() override; + void SetDeferCommits(bool defer_commits) override; + bool CommitRequested() const override; + bool BeginMainFrameRequested() const override; + void MainThreadHasStoppedFlinging() override; + void Start() override; + void Stop() override; + bool SupportsImplScrolling() const override; + bool MainFrameWillHappenForTesting() override; + void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override; + void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) override; + void ReleaseOutputSurface() override; + void UpdateTopControlsState(TopControlsState constraints, + TopControlsState current, + bool animate) override; + + // This sets the channel used by ProxyMain to communicate with ProxyImpl. + void SetChannel(scoped_ptr<ChannelMain> channel_main); + + // Returns |true| if the request was actually sent, |false| if one was + // already outstanding. + bool SendCommitRequestToImplThreadIfNeeded( + CommitPipelineStage required_stage); + bool IsMainThread() const; + + LayerTreeHost* layer_tree_host_; + + TaskRunnerProvider* task_runner_provider_; + + const int layer_tree_host_id_; + + // The furthest pipeline stage which has been requested for the next + // commit. + CommitPipelineStage max_requested_pipeline_stage_; + // The commit pipeline stage that is currently being processed. + CommitPipelineStage current_pipeline_stage_; + // The commit pipeline stage at which processing for the current commit + // will stop. Only valid while we are executing the pipeline (i.e., + // |current_pipeline_stage| is set to a pipeline stage). + CommitPipelineStage final_pipeline_stage_; + + bool commit_waits_for_activation_; + + // Set when the Proxy is started using Proxy::Start() and reset when it is + // stopped using Proxy::Stop(). + bool started_; + + bool defer_commits_; + + RendererCapabilities renderer_capabilities_; + + // This holds a valid value only until ProxyImpl is created on the impl thread + // with InitializeImplOnImpl(). + // TODO(khushalsagar): Remove the use of this temporary variable. + // See crbug/567930. + scoped_ptr<BeginFrameSource> external_begin_frame_source_; + + scoped_ptr<ChannelMain> channel_main_; - // TODO(khushalsagar): Rename as GetWeakPtr() once ThreadProxy is split. - virtual base::WeakPtr<ProxyMain> GetMainWeakPtr() = 0; + DISALLOW_COPY_AND_ASSIGN(ProxyMain); }; } // namespace cc diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc deleted file mode 100644 index 7e09d7a..0000000 --- a/cc/trees/thread_proxy.cc +++ /dev/null @@ -1,1190 +0,0 @@ -// Copyright 2011 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/thread_proxy.h" - -#include <algorithm> -#include <string> - -#include "base/auto_reset.h" -#include "base/bind.h" -#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/input/input_handler.h" -#include "cc/input/top_controls_manager.h" -#include "cc/output/context_provider.h" -#include "cc/output/output_surface.h" -#include "cc/output/swap_promise.h" -#include "cc/quads/draw_quad.h" -#include "cc/scheduler/commit_earlyout_reason.h" -#include "cc/scheduler/compositor_timing_history.h" -#include "cc/scheduler/scheduler.h" -#include "cc/trees/blocking_task_runner.h" -#include "cc/trees/layer_tree_host.h" -#include "cc/trees/layer_tree_impl.h" -#include "cc/trees/scoped_abort_remaining_swap_promises.h" -#include "gpu/command_buffer/client/gles2_interface.h" - -namespace cc { - -namespace { - -// Measured in seconds. -const double kSmoothnessTakesPriorityExpirationDelay = 0.25; - -unsigned int nextBeginFrameId = 0; - -} // namespace - -struct ThreadProxy::SchedulerStateRequest { - CompletionEvent completion; - scoped_ptr<base::Value> state; -}; - -scoped_ptr<Proxy> ThreadProxy::Create( - LayerTreeHost* layer_tree_host, - TaskRunnerProvider* task_runner_provider, - scoped_ptr<BeginFrameSource> external_begin_frame_source) { - return make_scoped_ptr( - new ThreadProxy(layer_tree_host, task_runner_provider, - std::move(external_begin_frame_source))); -} - -ThreadProxy::ThreadProxy( - LayerTreeHost* layer_tree_host, - TaskRunnerProvider* task_runner_provider, - scoped_ptr<BeginFrameSource> external_begin_frame_source) - : task_runner_provider_(task_runner_provider), - main_thread_only_vars_unsafe_(this, layer_tree_host), - compositor_thread_vars_unsafe_( - this, - layer_tree_host->id(), - layer_tree_host->rendering_stats_instrumentation(), - std::move(external_begin_frame_source)) { - TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy"); - DCHECK(task_runner_provider_); - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK(this->main().layer_tree_host); - // TODO(khushalsagar): Move this to LayerTreeHost#InitializeThreaded once - // ThreadProxy is split. LayerTreeHost creates the channel and passes it to - // ProxyMain#SetChannel. - SetChannel(ThreadedChannel::Create(this, task_runner_provider_)); -} - -ThreadProxy::MainThreadOnly::MainThreadOnly(ThreadProxy* proxy, - LayerTreeHost* layer_tree_host) - : layer_tree_host_id(layer_tree_host->id()), - layer_tree_host(layer_tree_host), - 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), - prepare_tiles_pending(false), - defer_commits(false), - weak_factory(proxy) {} - -ThreadProxy::MainThreadOnly::~MainThreadOnly() {} - -ThreadProxy::BlockedMainCommitOnly::BlockedMainCommitOnly() - : layer_tree_host(nullptr) {} - -ThreadProxy::BlockedMainCommitOnly::~BlockedMainCommitOnly() {} - -ThreadProxy::CompositorThreadOnly::CompositorThreadOnly( - ThreadProxy* proxy, - int layer_tree_host_id, - RenderingStatsInstrumentation* rendering_stats_instrumentation, - scoped_ptr<BeginFrameSource> external_begin_frame_source) - : layer_tree_host_id(layer_tree_host_id), - next_commit_waits_for_activation(false), - commit_completion_event(nullptr), - next_frame_is_newly_committed_frame(false), - inside_draw(false), - input_throttled_until_commit(false), - smoothness_priority_expiration_notifier( - proxy->task_runner_provider() - ->ImplThreadTaskRunner(), - base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)), - base::TimeDelta::FromMilliseconds( - kSmoothnessTakesPriorityExpirationDelay * 1000)), - external_begin_frame_source(std::move(external_begin_frame_source)), - rendering_stats_instrumentation(rendering_stats_instrumentation), - weak_factory(proxy) {} - -ThreadProxy::CompositorThreadOnly::~CompositorThreadOnly() {} - -ThreadProxy::~ThreadProxy() { - TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy"); - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK(!main().started); -} - -void ThreadProxy::SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) { - threaded_channel_ = std::move(threaded_channel); - main().channel_main = threaded_channel_.get(); -} - -void ThreadProxy::FinishAllRendering() { - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK(!main().defer_commits); - - // Make sure all GL drawing is finished on the impl thread. - DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); - CompletionEvent completion; - main().channel_main->FinishAllRenderingOnImpl(&completion); - completion.Wait(); -} - -bool ThreadProxy::IsStarted() const { - DCHECK(task_runner_provider_->IsMainThread()); - return main().started; -} - -bool ThreadProxy::CommitToActiveTree() const { - // With ThreadProxy, 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 ThreadProxy::SetVisible(bool visible) { - TRACE_EVENT1("cc", "ThreadProxy::SetVisible", "visible", visible); - main().channel_main->SetVisibleOnImpl(visible); -} - -void ThreadProxy::SetVisibleOnImpl(bool visible) { - TRACE_EVENT1("cc", "ThreadProxy::SetVisibleOnImplThread", "visible", visible); - impl().layer_tree_host_impl->SetVisible(visible); - impl().scheduler->SetVisible(visible); -} - -void ThreadProxy::SetThrottleFrameProduction(bool throttle) { - TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProduction", "throttle", - throttle); - main().channel_main->SetThrottleFrameProductionOnImpl(throttle); -} - -void ThreadProxy::SetThrottleFrameProductionOnImpl(bool throttle) { - TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread", - "throttle", throttle); - impl().scheduler->SetThrottleFrameProduction(throttle); -} - -void ThreadProxy::DidLoseOutputSurface() { - TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface"); - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->DidLoseOutputSurface(); -} - -void ThreadProxy::RequestNewOutputSurface() { - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->RequestNewOutputSurface(); -} - -void ThreadProxy::SetOutputSurface(OutputSurface* output_surface) { - main().channel_main->InitializeOutputSurfaceOnImpl(output_surface); -} - -void ThreadProxy::ReleaseOutputSurface() { - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK(main().layer_tree_host->output_surface_lost()); - - DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); - CompletionEvent completion; - main().channel_main->ReleaseOutputSurfaceOnImpl(&completion); - completion.Wait(); -} - -void ThreadProxy::DidInitializeOutputSurface( - bool success, - const RendererCapabilities& capabilities) { - TRACE_EVENT0("cc", "ThreadProxy::DidInitializeOutputSurface"); - DCHECK(task_runner_provider_->IsMainThread()); - - if (!success) { - main().layer_tree_host->DidFailToInitializeOutputSurface(); - return; - } - main().renderer_capabilities_main_thread_copy = capabilities; - main().layer_tree_host->DidInitializeOutputSurface(); -} - -void ThreadProxy::SetRendererCapabilitiesMainCopy( - const RendererCapabilities& capabilities) { - main().renderer_capabilities_main_thread_copy = capabilities; -} - -bool ThreadProxy::SendCommitRequestToImplThreadIfNeeded( - CommitPipelineStage required_stage) { - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK_NE(NO_PIPELINE_STAGE, required_stage); - bool already_posted = - main().max_requested_pipeline_stage != NO_PIPELINE_STAGE; - main().max_requested_pipeline_stage = - std::max(main().max_requested_pipeline_stage, required_stage); - if (already_posted) - return false; - main().channel_main->SetNeedsCommitOnImpl(); - return true; -} - -void ThreadProxy::SetNeedsCommitOnImpl() { - SetNeedsCommitOnImplThread(); -} - -void ThreadProxy::DidCompletePageScaleAnimation() { - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->DidCompletePageScaleAnimation(); -} - -const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const { - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK(!main().layer_tree_host->output_surface_lost()); - return main().renderer_capabilities_main_thread_copy; -} - -void ThreadProxy::SetNeedsAnimate() { - DCHECK(task_runner_provider_->IsMainThread()); - if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE)) { - TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsAnimate", - TRACE_EVENT_SCOPE_THREAD); - } -} - -void ThreadProxy::SetNeedsUpdateLayers() { - DCHECK(task_runner_provider_->IsMainThread()); - // If we are currently animating, make sure we also update the layers. - if (main().current_pipeline_stage == ANIMATE_PIPELINE_STAGE) { - main().final_pipeline_stage = - std::max(main().final_pipeline_stage, UPDATE_LAYERS_PIPELINE_STAGE); - return; - } - if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE)) { - TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsUpdateLayers", - TRACE_EVENT_SCOPE_THREAD); - } -} - -void ThreadProxy::SetNeedsCommit() { - DCHECK(task_runner_provider_->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 (main().current_pipeline_stage == ANIMATE_PIPELINE_STAGE) { - main().final_pipeline_stage = - std::max(main().final_pipeline_stage, COMMIT_PIPELINE_STAGE); - return; - } - if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE)) { - TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsCommit", - TRACE_EVENT_SCOPE_THREAD); - } -} - -void ThreadProxy::UpdateRendererCapabilitiesOnImplThread() { - DCHECK(task_runner_provider_->IsImplThread()); - impl().channel_impl->SetRendererCapabilitiesMainCopy( - impl() - .layer_tree_host_impl->GetRendererCapabilities() - .MainThreadCapabilities()); -} - -void ThreadProxy::DidLoseOutputSurfaceOnImplThread() { - TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurfaceOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().channel_impl->DidLoseOutputSurface(); - impl().scheduler->DidLoseOutputSurface(); -} - -void ThreadProxy::CommitVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval) { - impl().scheduler->CommitVSyncParameters(timebase, interval); -} - -void ThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { - impl().scheduler->SetEstimatedParentDrawTime(draw_time); -} - -void ThreadProxy::DidSwapBuffersOnImplThread() { - impl().scheduler->DidSwapBuffers(); -} - -void ThreadProxy::DidSwapBuffersCompleteOnImplThread() { - TRACE_EVENT0("cc,benchmark", - "ThreadProxy::DidSwapBuffersCompleteOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->DidSwapBuffersComplete(); - impl().channel_impl->DidCompleteSwapBuffers(); -} - -void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { - impl().layer_tree_host_impl->WillBeginImplFrame(args); - if (impl().last_processed_begin_main_frame_args.IsValid()) { - // Last processed begin main frame args records the frame args that we sent - // to the main thread for the last frame that we've processed. If that is - // set, that means the current frame is one past the frame in which we've - // finished the processing. - impl().layer_tree_host_impl->RecordMainFrameTiming( - impl().last_processed_begin_main_frame_args, args); - impl().last_processed_begin_main_frame_args = BeginFrameArgs(); - } -} - -void ThreadProxy::OnResourcelessSoftareDrawStateChanged( - bool resourceless_draw) { - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetResourcelessSoftareDraw(resourceless_draw); -} - -void ThreadProxy::OnCanDrawStateChanged(bool can_draw) { - TRACE_EVENT1( - "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetCanDraw(can_draw); -} - -void ThreadProxy::NotifyReadyToActivate() { - TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate"); - impl().scheduler->NotifyReadyToActivate(); -} - -void ThreadProxy::NotifyReadyToDraw() { - TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToDraw"); - impl().scheduler->NotifyReadyToDraw(); -} - -void ThreadProxy::SetNeedsCommitOnImplThread() { - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetNeedsBeginMainFrame(); -} - -void ThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) { - TRACE_EVENT1("cc", "ThreadProxy::SetVideoNeedsBeginFrames", - "needs_begin_frames", needs_begin_frames); - DCHECK(task_runner_provider_->IsImplThread()); - // In tests the layer tree is destroyed after the scheduler is. - if (impl().scheduler) - impl().scheduler->SetVideoNeedsBeginFrames(needs_begin_frames); -} - -void ThreadProxy::PostAnimationEventsToMainThreadOnImplThread( - scoped_ptr<AnimationEventsVector> events) { - TRACE_EVENT0("cc", - "ThreadProxy::PostAnimationEventsToMainThreadOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().channel_impl->SetAnimationEvents(std::move(events)); -} - -bool ThreadProxy::IsInsideDraw() { return impl().inside_draw; } - -void ThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw"); - DCHECK(task_runner_provider_->IsMainThread()); - main().channel_main->SetNeedsRedrawOnImpl(damage_rect); -} - -void ThreadProxy::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) { - DCHECK(task_runner_provider_->IsImplThread()); - SetNeedsRedrawRectOnImplThread(damage_rect); -} - -void ThreadProxy::SetNextCommitWaitsForActivation() { - DCHECK(task_runner_provider_->IsMainThread()); - main().commit_waits_for_activation = true; -} - -void ThreadProxy::SetDeferCommits(bool defer_commits) { - DCHECK(task_runner_provider_->IsMainThread()); - if (main().defer_commits == defer_commits) - return; - - main().defer_commits = defer_commits; - if (main().defer_commits) - TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::SetDeferCommits", this); - else - TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this); - - main().channel_main->SetDeferCommitsOnImpl(defer_commits); -} - -void ThreadProxy::SetDeferCommitsOnImpl(bool defer_commits) const { - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetDeferCommits(defer_commits); -} - -bool ThreadProxy::CommitRequested() const { - DCHECK(task_runner_provider_->IsMainThread()); - // TODO(skyostil): Split this into something like CommitRequested() and - // CommitInProgress(). - return main().current_pipeline_stage != NO_PIPELINE_STAGE || - main().max_requested_pipeline_stage >= COMMIT_PIPELINE_STAGE; -} - -bool ThreadProxy::BeginMainFrameRequested() const { - DCHECK(task_runner_provider_->IsMainThread()); - return main().max_requested_pipeline_stage != NO_PIPELINE_STAGE; -} - -void ThreadProxy::SetNeedsRedrawOnImplThread() { - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetNeedsRedraw(); -} - -void ThreadProxy::SetNeedsOneBeginImplFrameOnImplThread() { - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsOneBeginImplFrameOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetNeedsOneBeginImplFrame(); -} - -void ThreadProxy::SetNeedsPrepareTilesOnImplThread() { - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->SetNeedsPrepareTiles(); -} - -void ThreadProxy::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) { - DCHECK(task_runner_provider_->IsImplThread()); - impl().layer_tree_host_impl->SetViewportDamage(damage_rect); - SetNeedsRedrawOnImplThread(); -} - -void ThreadProxy::MainThreadHasStoppedFlinging() { - DCHECK(task_runner_provider_->IsMainThread()); - main().channel_main->MainThreadHasStoppedFlingingOnImpl(); -} - -void ThreadProxy::MainThreadHasStoppedFlingingOnImpl() { - DCHECK(task_runner_provider_->IsImplThread()); - impl().layer_tree_host_impl->MainThreadHasStoppedFlinging(); -} - -void ThreadProxy::NotifyInputThrottledUntilCommit() { - DCHECK(task_runner_provider_->IsMainThread()); - main().channel_main->SetInputThrottledUntilCommitOnImpl(true); -} - -void ThreadProxy::SetInputThrottledUntilCommitOnImpl(bool is_throttled) { - DCHECK(task_runner_provider_->IsImplThread()); - if (is_throttled == impl().input_throttled_until_commit) - return; - impl().input_throttled_until_commit = is_throttled; - RenewTreePriority(); -} - -ThreadProxy::MainThreadOnly& ThreadProxy::main() { - DCHECK(task_runner_provider_->IsMainThread()); - return main_thread_only_vars_unsafe_; -} -const ThreadProxy::MainThreadOnly& ThreadProxy::main() const { - DCHECK(task_runner_provider_->IsMainThread()); - return main_thread_only_vars_unsafe_; -} - -ThreadProxy::BlockedMainCommitOnly& ThreadProxy::blocked_main_commit() { - DCHECK(impl().commit_completion_event); - DCHECK(task_runner_provider_->IsMainThreadBlocked()); - return main_thread_blocked_commit_vars_unsafe_; -} - -ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() { - DCHECK(task_runner_provider_->IsImplThread()); - return compositor_thread_vars_unsafe_; -} - -const ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() const { - DCHECK(task_runner_provider_->IsImplThread()); - return compositor_thread_vars_unsafe_; -} - -void ThreadProxy::Start() { - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK(task_runner_provider_->HasImplThread()); - - // Create LayerTreeHostImpl. - DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); - CompletionEvent completion; - main().channel_main->InitializeImplOnImpl(&completion, - main().layer_tree_host); - completion.Wait(); - - main_thread_weak_ptr_ = main().weak_factory.GetWeakPtr(); - - main().started = true; -} - -void ThreadProxy::Stop() { - TRACE_EVENT0("cc", "ThreadProxy::Stop"); - DCHECK(task_runner_provider_->IsMainThread()); - DCHECK(main().started); - - // Synchronously finishes pending GL operations and deletes the impl. - // The two steps are done as separate post tasks, so that tasks posted - // by the GL implementation due to the Finish can be executed by the - // renderer before shutting it down. - { - DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); - CompletionEvent completion; - main().channel_main->FinishGLOnImpl(&completion); - completion.Wait(); - } - { - DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); - - CompletionEvent completion; - main().channel_main->LayerTreeHostClosedOnImpl(&completion); - completion.Wait(); - } - - main().weak_factory.InvalidateWeakPtrs(); - main().layer_tree_host = nullptr; - main().started = false; -} - -bool ThreadProxy::SupportsImplScrolling() const { - return true; -} - -void ThreadProxy::FinishAllRenderingOnImpl(CompletionEvent* completion) { - TRACE_EVENT0("cc", "ThreadProxy::FinishAllRenderingOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().layer_tree_host_impl->FinishAllRendering(); - completion->Signal(); -} - -void ThreadProxy::ScheduledActionSendBeginMainFrame( - const BeginFrameArgs& args) { - unsigned int begin_frame_id = nextBeginFrameId++; - benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( - benchmark_instrumentation::kSendBeginFrame, begin_frame_id); - scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state( - new BeginMainFrameAndCommitState); - begin_main_frame_state->begin_frame_id = begin_frame_id; - begin_main_frame_state->begin_frame_args = args; - begin_main_frame_state->scroll_info = - impl().layer_tree_host_impl->ProcessScrollDeltas(); - begin_main_frame_state->memory_allocation_limit_bytes = - impl().layer_tree_host_impl->memory_allocation_limit_bytes(); - begin_main_frame_state->evicted_ui_resources = - impl().layer_tree_host_impl->EvictedUIResourcesExist(); - // TODO(vmpstr): This needs to be fixed if - // main_frame_before_activation_enabled is set, since we might run this code - // twice before recording a duration. crbug.com/469824 - impl().last_begin_main_frame_args = begin_main_frame_state->begin_frame_args; - impl().channel_impl->BeginMainFrame(std::move(begin_main_frame_state)); - devtools_instrumentation::DidRequestMainThreadFrame( - impl().layer_tree_host_id); -} - -void ThreadProxy::SendBeginMainFrameNotExpectedSoon() { - impl().channel_impl->BeginMainFrameNotExpectedSoon(); -} - -void ThreadProxy::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(task_runner_provider_->IsMainThread()); - DCHECK_EQ(NO_PIPELINE_STAGE, main().current_pipeline_stage); - - if (main().defer_commits) { - TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit", - TRACE_EVENT_SCOPE_THREAD); - main().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(main().layer_tree_host); - - main().final_pipeline_stage = main().max_requested_pipeline_stage; - main().max_requested_pipeline_stage = NO_PIPELINE_STAGE; - - if (!main().layer_tree_host->visible()) { - TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); - main().channel_main->BeginMainFrameAbortedOnImpl( - CommitEarlyOutReason::ABORTED_NOT_VISIBLE, begin_main_frame_start_time); - return; - } - - if (main().layer_tree_host->output_surface_lost()) { - TRACE_EVENT_INSTANT0( - "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD); - main().channel_main->BeginMainFrameAbortedOnImpl( - CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST, - begin_main_frame_start_time); - return; - } - - main().current_pipeline_stage = ANIMATE_PIPELINE_STAGE; - - main().layer_tree_host->ApplyScrollAndScale( - begin_main_frame_state->scroll_info.get()); - - main().layer_tree_host->WillBeginMainFrame(); - - main().layer_tree_host->BeginMainFrame( - begin_main_frame_state->begin_frame_args); - main().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) - main().layer_tree_host->RecreateUIResources(); - - main().layer_tree_host->RequestMainFrameUpdate(); - TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame"); - - bool can_cancel_this_commit = - main().final_pipeline_stage < COMMIT_PIPELINE_STAGE && - !begin_main_frame_state->evicted_ui_resources; - - main().current_pipeline_stage = UPDATE_LAYERS_PIPELINE_STAGE; - bool should_update_layers = - main().final_pipeline_stage >= UPDATE_LAYERS_PIPELINE_STAGE; - bool updated = should_update_layers && main().layer_tree_host->UpdateLayers(); - - main().layer_tree_host->WillCommit(); - devtools_instrumentation::ScopedCommitTrace commit_task( - main().layer_tree_host->id()); - - main().current_pipeline_stage = COMMIT_PIPELINE_STAGE; - if (!updated && can_cancel_this_commit) { - TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD); - main().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. - main().current_pipeline_stage = NO_PIPELINE_STAGE; - main().layer_tree_host->CommitComplete(); - main().layer_tree_host->DidBeginMainFrame(); - main().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", "ThreadProxy::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()); - - CompletionEvent completion; - main().channel_main->StartCommitOnImpl(&completion, main().layer_tree_host, - begin_main_frame_start_time, - main().commit_waits_for_activation); - completion.Wait(); - main().commit_waits_for_activation = false; - } - - main().current_pipeline_stage = NO_PIPELINE_STAGE; - main().layer_tree_host->CommitComplete(); - main().layer_tree_host->DidBeginMainFrame(); -} - -void ThreadProxy::BeginMainFrameNotExpectedSoon() { - TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameNotExpectedSoon"); - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->BeginMainFrameNotExpectedSoon(); -} - -void ThreadProxy::StartCommitOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host, - base::TimeTicks main_thread_start_time, - bool hold_commit_for_activation) { - TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread"); - DCHECK(!impl().commit_completion_event); - DCHECK(task_runner_provider_->IsImplThread() && - task_runner_provider_->IsMainThreadBlocked()); - DCHECK(impl().scheduler); - DCHECK(impl().scheduler->CommitPending()); - - if (hold_commit_for_activation) { - // This commit may be aborted. Store the value for - // hold_commit_for_activation so that whenever the next commit is started, - // the main thread will be unblocked only after pending tree activation. - impl().next_commit_waits_for_activation = hold_commit_for_activation; - } - - if (!impl().layer_tree_host_impl) { - TRACE_EVENT_INSTANT0( - "cc", "EarlyOut_NoLayerTree", TRACE_EVENT_SCOPE_THREAD); - completion->Signal(); - return; - } - - // Ideally, we should inform to impl thread when BeginMainFrame is started. - // But, we can avoid a PostTask in here. - impl().scheduler->NotifyBeginMainFrameStarted(main_thread_start_time); - impl().commit_completion_event = completion; - DCHECK(!blocked_main_commit().layer_tree_host); - blocked_main_commit().layer_tree_host = layer_tree_host; - impl().scheduler->NotifyReadyToCommit(); -} - -void ThreadProxy::BeginMainFrameAbortedOnImpl( - CommitEarlyOutReason reason, - base::TimeTicks main_thread_start_time) { - TRACE_EVENT1("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread", "reason", - CommitEarlyOutReasonToString(reason)); - DCHECK(task_runner_provider_->IsImplThread()); - DCHECK(impl().scheduler); - DCHECK(impl().scheduler->CommitPending()); - DCHECK(!impl().layer_tree_host_impl->pending_tree()); - - if (CommitEarlyOutHandledCommit(reason)) { - SetInputThrottledUntilCommitOnImpl(false); - impl().last_processed_begin_main_frame_args = - impl().last_begin_main_frame_args; - } - impl().layer_tree_host_impl->BeginMainFrameAborted(reason); - impl().scheduler->NotifyBeginMainFrameStarted(main_thread_start_time); - impl().scheduler->BeginMainFrameAborted(reason); -} - -void ThreadProxy::ScheduledActionCommit() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit"); - DCHECK(task_runner_provider_->IsImplThread()); - DCHECK(task_runner_provider_->IsMainThreadBlocked()); - DCHECK(impl().commit_completion_event); - DCHECK(blocked_main_commit().layer_tree_host); - - impl().layer_tree_host_impl->BeginCommit(); - blocked_main_commit().layer_tree_host->FinishCommitOnImplThread( - impl().layer_tree_host_impl.get()); - - // Remove the LayerTreeHost reference before the completion event is signaled - // and cleared. This is necessary since blocked_main_commit() allows access - // only while we have the completion event to ensure the main thread is - // blocked for a commit. - blocked_main_commit().layer_tree_host = nullptr; - - if (impl().next_commit_waits_for_activation) { - // For some layer types in impl-side painting, the commit is held until - // the sync tree is activated. It's also possible that the - // sync tree has already activated if there was no work to be done. - TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD); - } else { - impl().commit_completion_event->Signal(); - impl().commit_completion_event = nullptr; - } - - impl().scheduler->DidCommit(); - - // Delay this step until afer the main thread has been released as it's - // often a good bit of work to update the tree and prepare the new frame. - impl().layer_tree_host_impl->CommitComplete(); - - SetInputThrottledUntilCommitOnImpl(false); - - impl().next_frame_is_newly_committed_frame = true; -} - -void ThreadProxy::ScheduledActionActivateSyncTree() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().layer_tree_host_impl->ActivateSyncTree(); -} - -void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionBeginOutputSurfaceCreation"); - DCHECK(task_runner_provider_->IsImplThread()); - impl().channel_impl->RequestNewOutputSurface(); -} - -DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) { - TRACE_EVENT_SYNTHETIC_DELAY("cc.DrawAndSwap"); - DrawResult result; - - DCHECK(task_runner_provider_->IsImplThread()); - DCHECK(impl().layer_tree_host_impl.get()); - - base::AutoReset<bool> mark_inside(&impl().inside_draw, true); - - if (impl().layer_tree_host_impl->pending_tree()) { - bool update_lcd_text = false; - impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties( - update_lcd_text); - } - - // This method is called on a forced draw, regardless of whether we are able - // to produce a frame, as the calling site on main thread is blocked until its - // request completes, and we signal completion here. If CanDraw() is false, we - // will indicate success=false to the caller, but we must still signal - // completion to avoid deadlock. - - // We guard PrepareToDraw() with CanDraw() because it always returns a valid - // frame, so can only be used when such a frame is possible. Since - // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on - // CanDraw() as well. - - LayerTreeHostImpl::FrameData frame; - bool draw_frame = false; - - if (impl().layer_tree_host_impl->CanDraw()) { - result = impl().layer_tree_host_impl->PrepareToDraw(&frame); - draw_frame = forced_draw || result == DRAW_SUCCESS; - } else { - result = DRAW_ABORTED_CANT_DRAW; - } - - if (draw_frame) { - impl().layer_tree_host_impl->DrawLayers(&frame); - result = DRAW_SUCCESS; - } else { - DCHECK_NE(DRAW_SUCCESS, result); - } - impl().layer_tree_host_impl->DidDrawAllLayers(frame); - - bool start_ready_animations = draw_frame; - impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations); - - if (draw_frame) - impl().layer_tree_host_impl->SwapBuffers(frame); - - // Tell the main thread that the the newly-commited frame was drawn. - if (impl().next_frame_is_newly_committed_frame) { - impl().next_frame_is_newly_committed_frame = false; - impl().channel_impl->DidCommitAndDrawFrame(); - } - - DCHECK_NE(INVALID_RESULT, result); - return result; -} - -void ThreadProxy::ScheduledActionPrepareTiles() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionPrepareTiles"); - impl().layer_tree_host_impl->PrepareTiles(); -} - -DrawResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap"); - - // SchedulerStateMachine::DidDrawIfPossibleCompleted isn't set up to - // handle DRAW_ABORTED_CANT_DRAW. Moreover, the scheduler should - // never generate this call when it can't draw. - DCHECK(impl().layer_tree_host_impl->CanDraw()); - - bool forced_draw = false; - return DrawSwapInternal(forced_draw); -} - -DrawResult ThreadProxy::ScheduledActionDrawAndSwapForced() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced"); - bool forced_draw = true; - return DrawSwapInternal(forced_draw); -} - -void ThreadProxy::ScheduledActionInvalidateOutputSurface() { - TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionInvalidateOutputSurface"); - DCHECK(impl().layer_tree_host_impl->output_surface()); - impl().layer_tree_host_impl->output_surface()->Invalidate(); -} - -void ThreadProxy::DidFinishImplFrame() { - impl().layer_tree_host_impl->DidFinishImplFrame(); -} - -void ThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) { - NOTREACHED() << "Only used by SingleThreadProxy"; -} - -void ThreadProxy::SetAuthoritativeVSyncInterval( - const base::TimeDelta& interval) { - NOTREACHED() << "Only used by SingleThreadProxy"; -} - -void ThreadProxy::DidCommitAndDrawFrame() { - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->DidCommitAndDrawFrame(); -} - -void ThreadProxy::DidCompleteSwapBuffers() { - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->DidCompleteSwapBuffers(); -} - -void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) { - TRACE_EVENT0("cc", "ThreadProxy::SetAnimationEvents"); - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->SetAnimationEvents(std::move(events)); -} - -void ThreadProxy::InitializeImplOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host) { - TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - DCHECK(task_runner_provider_->IsMainThreadBlocked()); - DCHECK(layer_tree_host); - - // TODO(khushalsagar): ThreadedChannel will create ProxyImpl here and pass a - // reference to itself. - impl().channel_impl = threaded_channel_.get(); - - impl().layer_tree_host_impl = layer_tree_host->CreateLayerTreeHostImpl(this); - - SchedulerSettings scheduler_settings( - layer_tree_host->settings().ToSchedulerSettings()); - - scoped_ptr<CompositorTimingHistory> compositor_timing_history( - new CompositorTimingHistory(CompositorTimingHistory::RENDERER_UMA, - impl().rendering_stats_instrumentation)); - - impl().scheduler = - Scheduler::Create(this, scheduler_settings, impl().layer_tree_host_id, - task_runner_provider_->ImplThreadTaskRunner(), - impl().external_begin_frame_source.get(), - std::move(compositor_timing_history)); - - DCHECK_EQ(impl().scheduler->visible(), - impl().layer_tree_host_impl->visible()); - impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr(); - completion->Signal(); -} - -void ThreadProxy::InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) { - TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - - LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get(); - bool success = host_impl->InitializeRenderer(output_surface); - RendererCapabilities capabilities; - if (success) { - capabilities = - host_impl->GetRendererCapabilities().MainThreadCapabilities(); - } - - impl().channel_impl->DidInitializeOutputSurface(success, capabilities); - - if (success) - impl().scheduler->DidCreateAndInitializeOutputSurface(); -} - -void ThreadProxy::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) { - DCHECK(task_runner_provider_->IsImplThread()); - - // Unlike DidLoseOutputSurfaceOnImplThread, we don't need to call - // LayerTreeHost::DidLoseOutputSurface since it already knows. - impl().scheduler->DidLoseOutputSurface(); - impl().layer_tree_host_impl->ReleaseOutputSurface(); - completion->Signal(); -} - -void ThreadProxy::FinishGLOnImpl(CompletionEvent* completion) { - TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - if (impl().layer_tree_host_impl->output_surface()) { - ContextProvider* context_provider = - impl().layer_tree_host_impl->output_surface()->context_provider(); - if (context_provider) - context_provider->ContextGL()->Finish(); - } - completion->Signal(); -} - -void ThreadProxy::LayerTreeHostClosedOnImpl(CompletionEvent* completion) { - TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - DCHECK(task_runner_provider_->IsMainThreadBlocked()); - impl().scheduler = nullptr; - impl().external_begin_frame_source = nullptr; - impl().layer_tree_host_impl = nullptr; - impl().weak_factory.InvalidateWeakPtrs(); - // We need to explicitly shutdown the notifier to destroy any weakptrs it is - // holding while still on the compositor thread. This also ensures any - // callbacks holding a ThreadProxy pointer are cancelled. - impl().smoothness_priority_expiration_notifier.Shutdown(); - completion->Signal(); -} - -bool ThreadProxy::MainFrameWillHappenForTesting() { - DCHECK(task_runner_provider_->IsMainThread()); - bool main_frame_will_happen = false; - { - DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); - CompletionEvent completion; - main().channel_main->MainFrameWillHappenOnImplForTesting( - &completion, &main_frame_will_happen); - completion.Wait(); - } - return main_frame_will_happen; -} - -void ThreadProxy::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { - NOTREACHED() << "Only used by SingleThreadProxy"; -} - -void ThreadProxy::MainFrameWillHappenOnImplForTesting( - CompletionEvent* completion, - bool* main_frame_will_happen) { - DCHECK(task_runner_provider_->IsImplThread()); - if (impl().layer_tree_host_impl->output_surface()) { - *main_frame_will_happen = impl().scheduler->MainFrameForTestingWillHappen(); - } else { - *main_frame_will_happen = false; - } - completion->Signal(); -} - -void ThreadProxy::RenewTreePriority() { - DCHECK(task_runner_provider_->IsImplThread()); - bool smoothness_takes_priority = - impl().layer_tree_host_impl->pinch_gesture_active() || - impl().layer_tree_host_impl->page_scale_animation_active() || - impl().layer_tree_host_impl->IsActivelyScrolling(); - - // Schedule expiration if smoothness currently takes priority. - if (smoothness_takes_priority) - impl().smoothness_priority_expiration_notifier.Schedule(); - - // We use the same priority for both trees by default. - TreePriority tree_priority = SAME_PRIORITY_FOR_BOTH_TREES; - - // Smoothness takes priority if we have an expiration for it scheduled. - if (impl().smoothness_priority_expiration_notifier.HasPendingNotification()) - tree_priority = SMOOTHNESS_TAKES_PRIORITY; - - // New content always takes priority when there is an invalid viewport size or - // ui resources have been evicted. - if (impl().layer_tree_host_impl->active_tree()->ViewportSizeInvalid() || - impl().layer_tree_host_impl->EvictedUIResourcesExist() || - impl().input_throttled_until_commit) { - // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active - // tree might be freed. We need to set RequiresHighResToDraw to ensure that - // high res tiles will be required to activate pending tree. - impl().layer_tree_host_impl->SetRequiresHighResToDraw(); - tree_priority = NEW_CONTENT_TAKES_PRIORITY; - } - - impl().layer_tree_host_impl->SetTreePriority(tree_priority); - - // Only put the scheduler in impl latency prioritization mode if we don't - // have a scroll listener. This gives the scroll listener a better chance of - // handling scroll updates within the same frame. The tree itself is still - // kept in prefer smoothness mode to allow checkerboarding. - ScrollHandlerState scroll_handler_state = - impl().layer_tree_host_impl->scroll_affects_scroll_handler() - ? ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER - : ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER; - impl().scheduler->SetTreePrioritiesAndScrollState(tree_priority, - scroll_handler_state); - - // Notify the the client of this compositor via the output surface. - // TODO(epenner): Route this to compositor-thread instead of output-surface - // after GTFO refactor of compositor-thread (http://crbug/170828). - if (impl().layer_tree_host_impl->output_surface()) { - impl() - .layer_tree_host_impl->output_surface() - ->UpdateSmoothnessTakesPriority(tree_priority == - SMOOTHNESS_TAKES_PRIORITY); - } -} - -void ThreadProxy::PostDelayedAnimationTaskOnImplThread( - const base::Closure& task, - base::TimeDelta delay) { - task_runner_provider_->ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, - task, delay); -} - -void ThreadProxy::DidActivateSyncTree() { - TRACE_EVENT0("cc", "ThreadProxy::DidActivateSyncTreeOnImplThread"); - DCHECK(task_runner_provider_->IsImplThread()); - - if (impl().next_commit_waits_for_activation) { - TRACE_EVENT_INSTANT0( - "cc", "ReleaseCommitbyActivation", TRACE_EVENT_SCOPE_THREAD); - DCHECK(impl().commit_completion_event); - impl().commit_completion_event->Signal(); - impl().commit_completion_event = nullptr; - impl().next_commit_waits_for_activation = false; - } - - impl().last_processed_begin_main_frame_args = - impl().last_begin_main_frame_args; -} - -void ThreadProxy::WillPrepareTiles() { - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->WillPrepareTiles(); -} - -void ThreadProxy::DidPrepareTiles() { - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->DidPrepareTiles(); -} - -void ThreadProxy::DidCompletePageScaleAnimationOnImplThread() { - DCHECK(task_runner_provider_->IsImplThread()); - impl().channel_impl->DidCompletePageScaleAnimation(); -} - -void ThreadProxy::OnDrawForOutputSurface() { - DCHECK(task_runner_provider_->IsImplThread()); - impl().scheduler->OnDrawForOutputSurface(); -} - -void ThreadProxy::UpdateTopControlsState(TopControlsState constraints, - TopControlsState current, - bool animate) { - main().channel_main->UpdateTopControlsStateOnImpl(constraints, current, - animate); -} - -void ThreadProxy::UpdateTopControlsStateOnImpl(TopControlsState constraints, - TopControlsState current, - bool animate) { - DCHECK(task_runner_provider_->IsImplThread()); - impl().layer_tree_host_impl->top_controls_manager()->UpdateTopControlsState( - constraints, current, animate); -} - -void ThreadProxy::PostFrameTimingEventsOnImplThread( - scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, - scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { - DCHECK(task_runner_provider_->IsImplThread()); - impl().channel_impl->PostFrameTimingEventsOnMain( - std::move(composite_events), std::move(main_frame_events)); -} - -void ThreadProxy::PostFrameTimingEventsOnMain( - scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, - scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { - DCHECK(task_runner_provider_->IsMainThread()); - main().layer_tree_host->RecordFrameTimingEvents(std::move(composite_events), - std::move(main_frame_events)); -} - -base::WeakPtr<ProxyMain> ThreadProxy::GetMainWeakPtr() { - return main_thread_weak_ptr_; -} - -base::WeakPtr<ProxyImpl> ThreadProxy::GetImplWeakPtr() { - return impl_thread_weak_ptr_; -} - -} // namespace cc diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h deleted file mode 100644 index e10c57e..0000000 --- a/cc/trees/thread_proxy.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2011 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. - -#ifndef CC_TREES_THREAD_PROXY_H_ -#define CC_TREES_THREAD_PROXY_H_ - -#include <string> - -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "cc/animation/animation_events.h" -#include "cc/base/completion_event.h" -#include "cc/base/delayed_unique_notifier.h" -#include "cc/scheduler/commit_earlyout_reason.h" -#include "cc/scheduler/scheduler.h" -#include "cc/trees/layer_tree_host_impl.h" -#include "cc/trees/proxy.h" -#include "cc/trees/threaded_channel.h" - -namespace base { -class SingleThreadTaskRunner; -} - -namespace cc { - -class BeginFrameSource; -class ChannelImpl; -class ChannelMain; -class ContextProvider; -class InputHandlerClient; -class LayerTreeHost; -class ProxyImpl; -class ProxyMain; -class Scheduler; -class ScopedThreadProxy; -class ThreadedChannel; - -class CC_EXPORT ThreadProxy : public Proxy, - public ProxyMain, - public ProxyImpl, - NON_EXPORTED_BASE(LayerTreeHostImplClient), - NON_EXPORTED_BASE(SchedulerClient) { - public: - static scoped_ptr<Proxy> Create( - LayerTreeHost* layer_tree_host, - TaskRunnerProvider* task_runner_provider, - scoped_ptr<BeginFrameSource> external_begin_frame_source); - - ~ThreadProxy() override; - - // Commits between the main and impl threads are processed through a pipeline - // with the following stages. For efficiency we can early out at any stage if - // we decide that no further processing is necessary. - enum CommitPipelineStage { - NO_PIPELINE_STAGE, - ANIMATE_PIPELINE_STAGE, - UPDATE_LAYERS_PIPELINE_STAGE, - COMMIT_PIPELINE_STAGE, - }; - - struct MainThreadOnly { - MainThreadOnly(ThreadProxy* proxy, LayerTreeHost* layer_tree_host); - ~MainThreadOnly(); - - const int layer_tree_host_id; - - LayerTreeHost* layer_tree_host; - - // The furthest pipeline stage which has been requested for the next - // commit. - CommitPipelineStage max_requested_pipeline_stage; - // The commit pipeline stage that is currently being processed. - CommitPipelineStage current_pipeline_stage; - // The commit pipeline stage at which processing for the current commit - // will stop. Only valid while we are executing the pipeline (i.e., - // |current_pipeline_stage| is set to a pipeline stage). - CommitPipelineStage final_pipeline_stage; - - bool commit_waits_for_activation; - - bool started; - bool prepare_tiles_pending; - bool defer_commits; - - RendererCapabilities renderer_capabilities_main_thread_copy; - - // TODO(khushalsagar): Make this scoped_ptr<ChannelMain> when ProxyMain - // and ProxyImpl are split. - ChannelMain* channel_main; - - base::WeakPtrFactory<ThreadProxy> weak_factory; - }; - - // Accessed on the impl thread when the main thread is blocked for a commit. - struct BlockedMainCommitOnly { - BlockedMainCommitOnly(); - ~BlockedMainCommitOnly(); - LayerTreeHost* layer_tree_host; - }; - - struct CompositorThreadOnly { - CompositorThreadOnly( - ThreadProxy* proxy, - int layer_tree_host_id, - RenderingStatsInstrumentation* rendering_stats_instrumentation, - scoped_ptr<BeginFrameSource> external_begin_frame_source); - ~CompositorThreadOnly(); - - const int layer_tree_host_id; - - scoped_ptr<Scheduler> scheduler; - - // Set when the main thread is waiting on a pending tree activation. - bool next_commit_waits_for_activation; - - // Set when the main thread is waiting on a commit to complete or on a - // pending tree activation. - CompletionEvent* commit_completion_event; - - // Set when the next draw should post DidCommitAndDrawFrame to the main - // thread. - bool next_frame_is_newly_committed_frame; - - bool inside_draw; - - bool input_throttled_until_commit; - - // Whether a commit has been completed since the last time animations were - // ticked. If this happens, we need to animate again. - bool did_commit_after_animating; - - DelayedUniqueNotifier smoothness_priority_expiration_notifier; - - scoped_ptr<BeginFrameSource> external_begin_frame_source; - - RenderingStatsInstrumentation* rendering_stats_instrumentation; - - // Values used to keep track of frame durations. Used only in frame timing. - BeginFrameArgs last_begin_main_frame_args; - BeginFrameArgs last_processed_begin_main_frame_args; - - scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl; - - ChannelImpl* channel_impl; - - base::WeakPtrFactory<ThreadProxy> weak_factory; - }; - - const MainThreadOnly& main() const; - const CompositorThreadOnly& impl() const; - TaskRunnerProvider* task_runner_provider() { return task_runner_provider_; } - - // Proxy implementation - void FinishAllRendering() override; - bool IsStarted() const override; - bool CommitToActiveTree() const override; - void SetOutputSurface(OutputSurface* output_surface) override; - void SetVisible(bool visible) override; - void SetThrottleFrameProduction(bool throttle) override; - const RendererCapabilities& GetRendererCapabilities() const override; - void SetNeedsAnimate() override; - void SetNeedsUpdateLayers() override; - void SetNeedsCommit() override; - void SetNeedsRedraw(const gfx::Rect& damage_rect) override; - void SetNextCommitWaitsForActivation() override; - void NotifyInputThrottledUntilCommit() override; - void SetDeferCommits(bool defer_commits) override; - bool CommitRequested() const override; - bool BeginMainFrameRequested() const override; - void MainThreadHasStoppedFlinging() override; - void Start() override; - void Stop() override; - bool SupportsImplScrolling() const override; - bool MainFrameWillHappenForTesting() override; - void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override; - void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) override; - void ReleaseOutputSurface() override; - void UpdateTopControlsState(TopControlsState constraints, - TopControlsState current, - bool animate) override; - - // LayerTreeHostImplClient implementation - void UpdateRendererCapabilitiesOnImplThread() override; - void DidLoseOutputSurfaceOnImplThread() override; - void CommitVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval) override; - void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override; - void DidSwapBuffersOnImplThread() override; - void DidSwapBuffersCompleteOnImplThread() override; - void OnResourcelessSoftareDrawStateChanged(bool resourceless_draw) override; - void OnCanDrawStateChanged(bool can_draw) override; - void NotifyReadyToActivate() override; - void NotifyReadyToDraw() override; - // Please call these 3 functions through - // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and - // SetNeedsOneBeginImplFrame(). - void SetNeedsRedrawOnImplThread() override; - void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override; - void SetNeedsOneBeginImplFrameOnImplThread() override; - void SetNeedsPrepareTilesOnImplThread() override; - void SetNeedsCommitOnImplThread() override; - void SetVideoNeedsBeginFrames(bool needs_begin_frames) override; - void PostAnimationEventsToMainThreadOnImplThread( - scoped_ptr<AnimationEventsVector> queue) override; - bool IsInsideDraw() override; - void RenewTreePriority() override; - void PostDelayedAnimationTaskOnImplThread(const base::Closure& task, - base::TimeDelta delay) override; - void DidActivateSyncTree() override; - void WillPrepareTiles() override; - void DidPrepareTiles() override; - void DidCompletePageScaleAnimationOnImplThread() override; - void OnDrawForOutputSurface() override; - // This should only be called by LayerTreeHostImpl::PostFrameTimingEvents. - void PostFrameTimingEventsOnImplThread( - scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, - scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) - override; - - // SchedulerClient implementation - void WillBeginImplFrame(const BeginFrameArgs& args) override; - void DidFinishImplFrame() override; - void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override; - DrawResult ScheduledActionDrawAndSwapIfPossible() override; - DrawResult ScheduledActionDrawAndSwapForced() override; - void ScheduledActionCommit() override; - void ScheduledActionActivateSyncTree() override; - void ScheduledActionBeginOutputSurfaceCreation() override; - void ScheduledActionPrepareTiles() override; - void ScheduledActionInvalidateOutputSurface() override; - void SendBeginFramesToChildren(const BeginFrameArgs& args) override; - void SendBeginMainFrameNotExpectedSoon() override; - - // ProxyMain implementation - void SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) override; - - protected: - ThreadProxy(LayerTreeHost* layer_tree_host, - TaskRunnerProvider* task_runner_provider, - scoped_ptr<BeginFrameSource> external_begin_frame_source); - - private: - friend class ThreadProxyForTest; - - // ProxyMain implementation. - base::WeakPtr<ProxyMain> GetMainWeakPtr() override; - void DidCompleteSwapBuffers() override; - void SetRendererCapabilitiesMainCopy( - const RendererCapabilities& capabilities) override; - void BeginMainFrameNotExpectedSoon() override; - void DidCommitAndDrawFrame() override; - void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue) override; - void DidLoseOutputSurface() override; - void RequestNewOutputSurface() override; - void DidInitializeOutputSurface( - bool success, - const RendererCapabilities& capabilities) override; - void DidCompletePageScaleAnimation() override; - void PostFrameTimingEventsOnMain( - scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, - scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) - override; - void BeginMainFrame( - scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) override; - - // ProxyImpl implementation - base::WeakPtr<ProxyImpl> GetImplWeakPtr() override; - void SetThrottleFrameProductionOnImpl(bool throttle) override; - void UpdateTopControlsStateOnImpl(TopControlsState constraints, - TopControlsState current, - bool animate) override; - void InitializeOutputSurfaceOnImpl(OutputSurface* output_surface) override; - void MainThreadHasStoppedFlingingOnImpl() override; - void SetInputThrottledUntilCommitOnImpl(bool is_throttled) override; - void SetDeferCommitsOnImpl(bool defer_commits) const override; - void FinishAllRenderingOnImpl(CompletionEvent* completion) override; - void SetVisibleOnImpl(bool visible) override; - void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override; - void FinishGLOnImpl(CompletionEvent* completion) override; - void MainFrameWillHappenOnImplForTesting( - CompletionEvent* completion, - bool* main_frame_will_happen) override; - void SetNeedsCommitOnImpl() override; - void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override; - void BeginMainFrameAbortedOnImpl( - CommitEarlyOutReason reason, - base::TimeTicks main_thread_start_time) override; - void StartCommitOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host, - base::TimeTicks main_thread_start_time, - bool hold_commit_for_activation) override; - void InitializeImplOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host) override; - void LayerTreeHostClosedOnImpl(CompletionEvent* completion) override; - - // Returns |true| if the request was actually sent, |false| if one was - // already outstanding. - bool SendCommitRequestToImplThreadIfNeeded( - CommitPipelineStage required_stage); - - // Called on impl thread. - struct SchedulerStateRequest; - - DrawResult DrawSwapInternal(bool forced_draw); - - TaskRunnerProvider* task_runner_provider_; - - // Use accessors instead of this variable directly. - MainThreadOnly main_thread_only_vars_unsafe_; - MainThreadOnly& main(); - - // Use accessors instead of this variable directly. - BlockedMainCommitOnly main_thread_blocked_commit_vars_unsafe_; - BlockedMainCommitOnly& blocked_main_commit(); - - // Use accessors instead of this variable directly. - CompositorThreadOnly compositor_thread_vars_unsafe_; - CompositorThreadOnly& impl(); - - // TODO(khushalsagar): Remove this. Temporary variable to hold the channel. - scoped_ptr<ThreadedChannel> threaded_channel_; - - base::WeakPtr<ThreadProxy> main_thread_weak_ptr_; - base::WeakPtr<ThreadProxy> impl_thread_weak_ptr_; - - DISALLOW_COPY_AND_ASSIGN(ThreadProxy); -}; - -} // namespace cc - -#endif // CC_TREES_THREAD_PROXY_H_ diff --git a/cc/trees/threaded_channel.cc b/cc/trees/threaded_channel.cc index 37ed58f..3d2eb33 100644 --- a/cc/trees/threaded_channel.cc +++ b/cc/trees/threaded_channel.cc @@ -7,222 +7,312 @@ #include "base/bind.h" #include "base/single_thread_task_runner.h" #include "base/trace_event/trace_event.h" +#include "cc/trees/layer_tree_host.h" namespace cc { -scoped_ptr<ThreadedChannel> ThreadedChannel::Create( - ThreadProxy* thread_proxy, - TaskRunnerProvider* task_runner_provider) { - return make_scoped_ptr( - new ThreadedChannel(thread_proxy, task_runner_provider)); +ThreadedChannel::ThreadedChannel(ProxyMain* proxy_main, + TaskRunnerProvider* task_runner_provider) + : task_runner_provider_(task_runner_provider), + main_thread_only_vars_unsafe_(proxy_main), + compositor_thread_vars_unsafe_( + main() + .proxy_main_weak_factory.GetWeakPtr()) { + DCHECK(IsMainThread()); } -ThreadedChannel::ThreadedChannel(ThreadProxy* thread_proxy, - TaskRunnerProvider* task_runner_provider) - : proxy_main_(thread_proxy), - proxy_impl_(thread_proxy), - task_runner_provider_(task_runner_provider) {} +ThreadedChannel::~ThreadedChannel() { + TRACE_EVENT0("cc", "ThreadChannel::~ThreadChannel"); + DCHECK(IsMainThread()); + DCHECK(!IsInitialized()); +} void ThreadedChannel::SetThrottleFrameProductionOnImpl(bool throttle) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyImpl::SetThrottleFrameProductionOnImpl, - proxy_impl_->GetImplWeakPtr(), throttle)); + proxy_impl_weak_ptr_, throttle)); } void ThreadedChannel::UpdateTopControlsStateOnImpl(TopControlsState constraints, TopControlsState current, bool animate) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ProxyImpl::UpdateTopControlsStateOnImpl, - proxy_impl_->GetImplWeakPtr(), constraints, current, animate)); + base::Bind(&ProxyImpl::UpdateTopControlsStateOnImpl, proxy_impl_weak_ptr_, + constraints, current, animate)); } void ThreadedChannel::InitializeOutputSurfaceOnImpl( OutputSurface* output_surface) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyImpl::InitializeOutputSurfaceOnImpl, - proxy_impl_->GetImplWeakPtr(), output_surface)); + proxy_impl_weak_ptr_, output_surface)); } void ThreadedChannel::MainThreadHasStoppedFlingingOnImpl() { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyImpl::MainThreadHasStoppedFlingingOnImpl, - proxy_impl_->GetImplWeakPtr())); + proxy_impl_weak_ptr_)); } void ThreadedChannel::SetInputThrottledUntilCommitOnImpl(bool is_throttled) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyImpl::SetInputThrottledUntilCommitOnImpl, - proxy_impl_->GetImplWeakPtr(), is_throttled)); + proxy_impl_weak_ptr_, is_throttled)); } void ThreadedChannel::SetDeferCommitsOnImpl(bool defer_commits) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyImpl::SetDeferCommitsOnImpl, - proxy_impl_->GetImplWeakPtr(), defer_commits)); -} - -void ThreadedChannel::FinishAllRenderingOnImpl(CompletionEvent* completion) { - ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::Bind(&ProxyImpl::FinishAllRenderingOnImpl, - proxy_impl_->GetImplWeakPtr(), completion)); + proxy_impl_weak_ptr_, defer_commits)); } void ThreadedChannel::SetNeedsCommitOnImpl() { - ImplThreadTaskRunner()->PostTask(FROM_HERE, - base::Bind(&ProxyImpl::SetNeedsCommitOnImpl, - proxy_impl_->GetImplWeakPtr())); + DCHECK(IsMainThread()); + ImplThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ProxyImpl::SetNeedsCommitOnImpl, proxy_impl_weak_ptr_)); } void ThreadedChannel::BeginMainFrameAbortedOnImpl( CommitEarlyOutReason reason, base::TimeTicks main_thread_start_time) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::Bind(&ProxyImpl::BeginMainFrameAbortedOnImpl, - proxy_impl_->GetImplWeakPtr(), reason, - main_thread_start_time)); + FROM_HERE, + base::Bind(&ProxyImpl::BeginMainFrameAbortedOnImpl, proxy_impl_weak_ptr_, + reason, main_thread_start_time)); } void ThreadedChannel::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyImpl::SetNeedsRedrawOnImpl, - proxy_impl_->GetImplWeakPtr(), damage_rect)); -} - -void ThreadedChannel::StartCommitOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host, - base::TimeTicks main_thread_start_time, - bool hold_commit_for_activation) { - ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ProxyImpl::StartCommitOnImpl, proxy_impl_->GetImplWeakPtr(), - completion, layer_tree_host, main_thread_start_time, - hold_commit_for_activation)); + proxy_impl_weak_ptr_, damage_rect)); } -void ThreadedChannel::InitializeImplOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host) { +void ThreadedChannel::SetVisibleOnImpl(bool visible) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ProxyImpl::InitializeImplOnImpl, - base::Unretained(proxy_impl_), completion, layer_tree_host)); -} - -void ThreadedChannel::LayerTreeHostClosedOnImpl(CompletionEvent* completion) { - ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::Bind(&ProxyImpl::LayerTreeHostClosedOnImpl, - proxy_impl_->GetImplWeakPtr(), completion)); - proxy_impl_ = nullptr; + base::Bind(&ProxyImpl::SetVisibleOnImpl, proxy_impl_weak_ptr_, visible)); } -void ThreadedChannel::SetVisibleOnImpl(bool visible) { +void ThreadedChannel::FinishAllRenderingOnImpl(CompletionEvent* completion) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::Bind(&ProxyImpl::SetVisibleOnImpl, - proxy_impl_->GetImplWeakPtr(), visible)); + FROM_HERE, base::Bind(&ProxyImpl::FinishAllRenderingOnImpl, + proxy_impl_weak_ptr_, completion)); } void ThreadedChannel::ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyImpl::ReleaseOutputSurfaceOnImpl, - proxy_impl_->GetImplWeakPtr(), completion)); -} - -void ThreadedChannel::FinishGLOnImpl(CompletionEvent* completion) { - ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::Bind(&ProxyImpl::FinishGLOnImpl, - proxy_impl_->GetImplWeakPtr(), completion)); + proxy_impl_weak_ptr_, completion)); } void ThreadedChannel::MainFrameWillHappenOnImplForTesting( CompletionEvent* completion, bool* main_frame_will_happen) { + DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::Bind(&ProxyImpl::MainFrameWillHappenOnImplForTesting, - proxy_impl_->GetImplWeakPtr(), completion, - main_frame_will_happen)); + FROM_HERE, + base::Bind(&ProxyImpl::MainFrameWillHappenOnImplForTesting, + proxy_impl_weak_ptr_, completion, main_frame_will_happen)); +} + +void ThreadedChannel::StartCommitOnImpl(CompletionEvent* completion, + LayerTreeHost* layer_tree_host, + base::TimeTicks main_thread_start_time, + bool hold_commit_for_activation) { + DCHECK(IsMainThread()); + ImplThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ProxyImpl::StartCommitOnImpl, proxy_impl_weak_ptr_, + completion, layer_tree_host, main_thread_start_time, + hold_commit_for_activation)); +} + +void ThreadedChannel::SynchronouslyInitializeImpl( + LayerTreeHost* layer_tree_host, + scoped_ptr<BeginFrameSource> external_begin_frame_source) { + TRACE_EVENT0("cc", "ThreadChannel::SynchronouslyInitializeImpl"); + DCHECK(IsMainThread()); + { + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); + CompletionEvent completion; + ImplThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ThreadedChannel::InitializeImplOnImpl, + base::Unretained(this), &completion, layer_tree_host, + base::Passed(&external_begin_frame_source))); + completion.Wait(); + } + main().initialized = true; +} + +void ThreadedChannel::SynchronouslyCloseImpl() { + TRACE_EVENT0("cc", "ThreadChannel::~SynchronouslyCloseImpl"); + DCHECK(IsMainThread()); + + // Synchronously finishes pending GL operations and deletes the impl. + // The two steps are done as separate post tasks, so that tasks posted + // by the GL implementation due to the Finish can be executed by the + // renderer before shutting it down. + { + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); + CompletionEvent completion; + ImplThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ProxyImpl::FinishGLOnImpl, proxy_impl_weak_ptr_, + &completion)); + completion.Wait(); + } + { + DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_); + CompletionEvent completion; + ImplThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ThreadedChannel::CloseImplOnImpl, + base::Unretained(this), &completion)); + completion.Wait(); + } + main().proxy_main_weak_factory.InvalidateWeakPtrs(); + main().initialized = false; } void ThreadedChannel::DidCompleteSwapBuffers() { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyMain::DidCompleteSwapBuffers, - proxy_main_->GetMainWeakPtr())); + impl().proxy_main_weak_ptr)); } void ThreadedChannel::SetRendererCapabilitiesMainCopy( const RendererCapabilities& capabilities) { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( - FROM_HERE, base::Bind(&ProxyMain::SetRendererCapabilitiesMainCopy, - proxy_main_->GetMainWeakPtr(), capabilities)); + FROM_HERE, base::Bind(&ProxyMain::SetRendererCapabilities, + impl().proxy_main_weak_ptr, capabilities)); } void ThreadedChannel::BeginMainFrameNotExpectedSoon() { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyMain::BeginMainFrameNotExpectedSoon, - proxy_main_->GetMainWeakPtr())); + impl().proxy_main_weak_ptr)); } void ThreadedChannel::DidCommitAndDrawFrame() { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask(FROM_HERE, base::Bind(&ProxyMain::DidCommitAndDrawFrame, - proxy_main_->GetMainWeakPtr())); + impl().proxy_main_weak_ptr)); } void ThreadedChannel::SetAnimationEvents( scoped_ptr<AnimationEventsVector> queue) { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ProxyMain::SetAnimationEvents, proxy_main_->GetMainWeakPtr(), - base::Passed(&queue))); + FROM_HERE, base::Bind(&ProxyMain::SetAnimationEvents, + impl().proxy_main_weak_ptr, base::Passed(&queue))); } void ThreadedChannel::DidLoseOutputSurface() { - MainThreadTaskRunner()->PostTask(FROM_HERE, - base::Bind(&ProxyMain::DidLoseOutputSurface, - proxy_main_->GetMainWeakPtr())); + DCHECK(IsImplThread()); + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ProxyMain::DidLoseOutputSurface, impl().proxy_main_weak_ptr)); } void ThreadedChannel::RequestNewOutputSurface() { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyMain::RequestNewOutputSurface, - proxy_main_->GetMainWeakPtr())); + impl().proxy_main_weak_ptr)); } void ThreadedChannel::DidInitializeOutputSurface( bool success, const RendererCapabilities& capabilities) { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ProxyMain::DidInitializeOutputSurface, - proxy_main_->GetMainWeakPtr(), success, capabilities)); + FROM_HERE, base::Bind(&ProxyMain::DidInitializeOutputSurface, + impl().proxy_main_weak_ptr, success, capabilities)); } void ThreadedChannel::DidCompletePageScaleAnimation() { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyMain::DidCompletePageScaleAnimation, - proxy_main_->GetMainWeakPtr())); + impl().proxy_main_weak_ptr)); } void ThreadedChannel::PostFrameTimingEventsOnMain( scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ProxyMain::PostFrameTimingEventsOnMain, - proxy_main_->GetMainWeakPtr(), + impl().proxy_main_weak_ptr, base::Passed(std::move(composite_events)), base::Passed(std::move(main_frame_events)))); } void ThreadedChannel::BeginMainFrame( scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) { + DCHECK(IsImplThread()); MainThreadTaskRunner()->PostTask( FROM_HERE, - base::Bind(&ProxyMain::BeginMainFrame, proxy_main_->GetMainWeakPtr(), + base::Bind(&ProxyMain::BeginMainFrame, impl().proxy_main_weak_ptr, base::Passed(&begin_main_frame_state))); } -ThreadedChannel::~ThreadedChannel() { - TRACE_EVENT0("cc", "ThreadChannel::~ThreadChannel"); +ProxyImpl* ThreadedChannel::GetProxyImplForTesting() const { + return impl().proxy_impl.get(); +} + +scoped_ptr<ProxyImpl> ThreadedChannel::CreateProxyImpl( + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source) { + DCHECK(IsImplThread()); + return ProxyImpl::Create(channel_impl, layer_tree_host, task_runner_provider, + std::move(external_begin_frame_source)); +} + +void ThreadedChannel::InitializeImplOnImpl( + CompletionEvent* completion, + LayerTreeHost* layer_tree_host, + scoped_ptr<BeginFrameSource> external_begin_frame_source) { + DCHECK(IsImplThread()); + impl().proxy_impl = + CreateProxyImpl(this, layer_tree_host, task_runner_provider_, + std::move(external_begin_frame_source)); + impl().proxy_impl_weak_factory = make_scoped_ptr( + new base::WeakPtrFactory<ProxyImpl>(impl().proxy_impl.get())); + proxy_impl_weak_ptr_ = impl().proxy_impl_weak_factory->GetWeakPtr(); + completion->Signal(); +} + +void ThreadedChannel::CloseImplOnImpl(CompletionEvent* completion) { + DCHECK(IsImplThread()); + + // We must destroy the factory and ensure that the ProxyImpl weak pointers are + // invalidated before destroying proxy_impl. + impl().proxy_impl_weak_factory.reset(); + + impl().proxy_impl.reset(); + completion->Signal(); +} + +bool ThreadedChannel::IsInitialized() const { + return main().initialized; } base::SingleThreadTaskRunner* ThreadedChannel::MainThreadTaskRunner() const { @@ -233,4 +323,49 @@ base::SingleThreadTaskRunner* ThreadedChannel::ImplThreadTaskRunner() const { return task_runner_provider_->ImplThreadTaskRunner(); } +bool ThreadedChannel::IsMainThread() const { + return task_runner_provider_->IsMainThread(); +} + +bool ThreadedChannel::IsImplThread() const { + return task_runner_provider_->IsImplThread(); +} + +ThreadedChannel::MainThreadOnly& ThreadedChannel::main() { + DCHECK(task_runner_provider_->IsMainThread()); + return main_thread_only_vars_unsafe_; +} + +const ThreadedChannel::MainThreadOnly& ThreadedChannel::main() const { + DCHECK(task_runner_provider_->IsMainThread()); + return main_thread_only_vars_unsafe_; +} + +ThreadedChannel::CompositorThreadOnly& ThreadedChannel::impl() { + DCHECK(task_runner_provider_->IsImplThread()); + return compositor_thread_vars_unsafe_; +} + +const ThreadedChannel::CompositorThreadOnly& ThreadedChannel::impl() const { + DCHECK(task_runner_provider_->IsImplThread()); + return compositor_thread_vars_unsafe_; +} + +ThreadedChannel::MainThreadOnly::MainThreadOnly(ProxyMain* proxy_main) + : proxy_main_weak_factory(proxy_main), initialized(false) {} + +ThreadedChannel::MainThreadOnly::~MainThreadOnly() {} + +ThreadedChannel::CompositorThreadOnly::CompositorThreadOnly( + base::WeakPtr<ProxyMain> proxy_main_weak_ptr) + : proxy_main_weak_ptr(proxy_main_weak_ptr) {} + +ThreadedChannel::CompositorThreadOnly::~CompositorThreadOnly() {} + +scoped_ptr<ThreadedChannel> ThreadedChannel::Create( + ProxyMain* proxy_main, + TaskRunnerProvider* task_runner_provider) { + return make_scoped_ptr(new ThreadedChannel(proxy_main, task_runner_provider)); +} + } // namespace cc diff --git a/cc/trees/threaded_channel.h b/cc/trees/threaded_channel.h index ca7fc04..5d10f4a 100644 --- a/cc/trees/threaded_channel.h +++ b/cc/trees/threaded_channel.h @@ -7,13 +7,13 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "cc/base/cc_export.h" #include "cc/trees/channel_impl.h" #include "cc/trees/channel_main.h" #include "cc/trees/proxy_common.h" #include "cc/trees/proxy_impl.h" #include "cc/trees/proxy_main.h" -#include "cc/trees/thread_proxy.h" namespace base { class SingleThreadTaskRunner; @@ -22,9 +22,9 @@ class SingleThreadTaskRunner; namespace cc { class ChannelImpl; class ChannelMain; +class LayerTreeHost; class ProxyImpl; class ProxyMain; -class ThreadProxy; // An implementation of ChannelMain and ChannelImpl that sends commands between // ProxyMain and ProxyImpl across thread boundaries. @@ -39,8 +39,8 @@ class ThreadProxy; // ProxyMain->Start() | // | ThreadedChannel // --------------------------------------------------------------------------- -// ChannelMain::InitializeImpl ---PostTask---> ThreadedChannel:: -// InitializeImplOnImplThread +// ChannelMain::SynchronouslyInitializeImpl ---PostTask---> ThreadedChannel:: +// InitializeImplOnImpl // | // ProxyImpl::Create // | @@ -56,20 +56,27 @@ class ThreadProxy; // ProxyMain->RequestNewOutputSurface()<----PostTask-------- // . // . -// ProxyMain->LayerTreeHostClosed +// ProxyMain->Stop() // | // --------------------------------------------------------------------------- -// ChannelMain::SetLayerTreeClosedOnImpl---PostTask---> ProxyImpl-> -// SetLayerTreeClosed +// ChannelMain::SynchronouslyCloseImpl ---PostTask---> ThreadedChannel:: +// CloseImplOnImpl // ---------------------------------------------------------------------------- +// +// ThreadedChannel is created and destroyed on the main thread but can be +// called from main or impl thread. It is safe for the Threadedchannel to be +// called on the impl thread because: +// 1) The only impl-threaded callers of ThreadedChannel are the ThreadedChannel +// itself and ProxyImpl which is created and owned by the ThreadedChannel. +// 2) ThreadedChannel blocks the main thread in +// ThreadedChannel::SynchronouslyCloseImpl to wait for the impl-thread teardown +// to complete, so there is no risk of any queued tasks calling it on the impl +// thread after it has been deleted on the main thread. class CC_EXPORT ThreadedChannel : public ChannelMain, public ChannelImpl { public: static scoped_ptr<ThreadedChannel> Create( - // TODO(khushalsagar): Make this ProxyMain* and write the initialization - // sequence. Currently ThreadProxy implements both so we pass the pointer - // and set ProxyImpl. - ThreadProxy* thread_proxy, + ProxyMain* proxy_main, TaskRunnerProvider* task_runner_provider); ~ThreadedChannel() override; @@ -93,7 +100,6 @@ class CC_EXPORT ThreadedChannel : public ChannelMain, public ChannelImpl { // Blocking calls to ProxyImpl void FinishAllRenderingOnImpl(CompletionEvent* completion) override; void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) override; - void FinishGLOnImpl(CompletionEvent* completion) override; void MainFrameWillHappenOnImplForTesting( CompletionEvent* completion, bool* main_frame_will_happen) override; @@ -101,9 +107,10 @@ class CC_EXPORT ThreadedChannel : public ChannelMain, public ChannelImpl { LayerTreeHost* layer_tree_host, base::TimeTicks main_thread_start_time, bool hold_commit_for_activation) override; - void InitializeImplOnImpl(CompletionEvent* completion, - LayerTreeHost* layer_tree_host) override; - void LayerTreeHostClosedOnImpl(CompletionEvent* completion) override; + void SynchronouslyInitializeImpl( + LayerTreeHost* layer_tree_host, + scoped_ptr<BeginFrameSource> external_begin_frame_source) override; + void SynchronouslyCloseImpl() override; // ChannelImpl Implementation void DidCompleteSwapBuffers() override; @@ -125,23 +132,84 @@ class CC_EXPORT ThreadedChannel : public ChannelMain, public ChannelImpl { void BeginMainFrame( scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) override; + // Should be called on impl thread only. + ProxyImpl* GetProxyImplForTesting() const; + protected: - ThreadedChannel(ThreadProxy* thread_proxy, + ThreadedChannel(ProxyMain* proxy_main, TaskRunnerProvider* task_runner_provider); + // Virtual for testing. + virtual scoped_ptr<ProxyImpl> CreateProxyImpl( + ChannelImpl* channel_impl, + LayerTreeHost* layer_tree_host, + TaskRunnerProvider* task_runner_provider, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + private: + // The members of this struct should be accessed on the main thread only. + struct MainThreadOnly { + explicit MainThreadOnly(ProxyMain* proxy_main); + ~MainThreadOnly(); + + base::WeakPtrFactory<ProxyMain> proxy_main_weak_factory; + bool initialized; + }; + + // The members of this struct should be accessed on the impl thread only. + struct CompositorThreadOnly { + explicit CompositorThreadOnly(base::WeakPtr<ProxyMain> proxy_main_weak_ptr); + ~CompositorThreadOnly(); + + scoped_ptr<ProxyImpl> proxy_impl; + + // We use a scoped_ptr for the weak ptr factory here since the factory is + // created after ProxyImpl is created in InitializeImplOnImpl. Since the + // weak ptrs are needed only by the ThreadedChannel to safely post tasks on + // ProxyImpl to be run on the impl thread, we avoid creating it in ProxyImpl + // and ensure that it is destroyed before ProxyImpl during the impl-thread + // tear down in CloseImplOnImpl. + scoped_ptr<base::WeakPtrFactory<ProxyImpl>> proxy_impl_weak_factory; + + // Used on the impl thread to queue calls to ProxyMain to be run on the main + // thread. Since the weak pointer is invalidated after the impl-thread tear + // down in SynchronouslyCloseImpl, this ensures that any tasks posted to + // ProxyMain from the impl thread are abandoned after the impl side has been + // destroyed. + base::WeakPtr<ProxyMain> proxy_main_weak_ptr; + }; + + // Called on impl thread. + void InitializeImplOnImpl( + CompletionEvent* completion, + LayerTreeHost* layer_tree_host, + scoped_ptr<BeginFrameSource> external_begin_frame_source); + void CloseImplOnImpl(CompletionEvent* completion); + + bool IsInitialized() const; + base::SingleThreadTaskRunner* MainThreadTaskRunner() const; base::SingleThreadTaskRunner* ImplThreadTaskRunner() const; + bool IsMainThread() const; + bool IsImplThread() const; + + TaskRunnerProvider* task_runner_provider_; - ProxyMain* proxy_main_; + MainThreadOnly& main(); + const MainThreadOnly& main() const; - ProxyImpl* proxy_impl_; + CompositorThreadOnly& impl(); + const CompositorThreadOnly& impl() const; - TaskRunnerProvider* task_runner_provider_; + // Use accessors instead of this variable directly. + MainThreadOnly main_thread_only_vars_unsafe_; - scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; + // Use accessors instead of this variable directly. + CompositorThreadOnly compositor_thread_vars_unsafe_; - scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_; + // Used on the main thread to safely queue calls to ProxyImpl to be run on the + // impl thread. + base::WeakPtr<ProxyImpl> proxy_impl_weak_ptr_; DISALLOW_COPY_AND_ASSIGN(ThreadedChannel); }; diff --git a/cc/trees/threaded_channel_unittest.cc b/cc/trees/threaded_channel_unittest.cc index 152ff59..17350d8 100644 --- a/cc/trees/threaded_channel_unittest.cc +++ b/cc/trees/threaded_channel_unittest.cc @@ -1,4 +1,4 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. +// 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. @@ -13,13 +13,12 @@ namespace cc { // The ThreadedChannel tests are run only for threaded and direct mode. class ThreadedChannelTest : public LayerTreeTest { protected: - ThreadedChannelTest() : thread_proxy_(nullptr), calls_received_(0) {} + ThreadedChannelTest() : calls_received_(0) {} ~ThreadedChannelTest() override {} void BeginTest() override { DCHECK(HasImplThread()); - thread_proxy_ = static_cast<ThreadProxy*>(proxy()); BeginChannelTest(); }; virtual void BeginChannelTest() {} @@ -36,9 +35,6 @@ class ThreadedChannelTest : public LayerTreeTest { void AfterTest() override {} - // TODO(khushalsagar): Remove this once ProxyImpl is added to the - // LayerTreeTest. - ThreadProxy* thread_proxy_; int calls_received_; private: @@ -47,8 +43,6 @@ class ThreadedChannelTest : public LayerTreeTest { class ThreadedChannelTestInitializationAndShutdown : public ThreadedChannelTest { - void InitializeImplOnImpl() override { calls_received_++; } - void SetVisibleOnImpl(bool visible) override { calls_received_++; } void ReceivedRequestNewOutputSurface() override { calls_received_++; } @@ -69,10 +63,9 @@ class ThreadedChannelTestInitializationAndShutdown EndTest(); } - void WillCloseLayerTreeHostOnImpl() override { calls_received_++; } void FinishGLOnImpl() override { calls_received_++; } - void AfterTest() override { EXPECT_EQ(8, calls_received_); } + void AfterTest() override { EXPECT_EQ(6, calls_received_); } }; MULTI_THREAD_DIRECT_RENDERER_TEST_F( @@ -246,7 +239,7 @@ class ThreadedChannelTestBeginMainFrameNotExpectedSoon void BeginChannelTest() override { PostOnImplThread(); } void StartTestOnImplThread() override { - thread_proxy_->SendBeginMainFrameNotExpectedSoon(); + GetProxyImplForTest()->SendBeginMainFrameNotExpectedSoon(); } void ReceivedBeginMainFrameNotExpectedSoon() override { @@ -266,7 +259,7 @@ class ThreadedChannelTestSetAnimationEvents : public ThreadedChannelTest { void StartTestOnImplThread() override { scoped_ptr<AnimationEventsVector> events( make_scoped_ptr(new AnimationEventsVector)); - thread_proxy_->PostAnimationEventsToMainThreadOnImplThread( + GetProxyImplForTest()->PostAnimationEventsToMainThreadOnImplThread( std::move(events)); } @@ -284,7 +277,7 @@ class ThreadedChannelTestLoseOutputSurface : public ThreadedChannelTest { void BeginChannelTest() override { PostOnImplThread(); } void StartTestOnImplThread() override { - thread_proxy_->DidLoseOutputSurfaceOnImplThread(); + GetProxyImplForTest()->DidLoseOutputSurfaceOnImplThread(); } void ReceivedDidLoseOutputSurface() override { @@ -301,7 +294,7 @@ class ThreadedChannelTestPageScaleAnimation : public ThreadedChannelTest { void BeginChannelTest() override { PostOnImplThread(); } void StartTestOnImplThread() override { - thread_proxy_->DidCompletePageScaleAnimationOnImplThread(); + GetProxyImplForTest()->DidCompletePageScaleAnimationOnImplThread(); } void ReceivedDidCompletePageScaleAnimation() override { |