diff options
44 files changed, 695 insertions, 503 deletions
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc index 818d3c5..86dd667 100644 --- a/android_webview/browser/hardware_renderer.cc +++ b/android_webview/browser/hardware_renderer.cc @@ -93,8 +93,11 @@ HardwareRenderer::HardwareRenderer(SharedRendererState* state) // Webview does not own the surface so should not clear it. settings.should_clear_root_render_pass = false; - layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded( - this, this, NULL, settings, NULL); + // TODO(enne): Update this this compositor to use a synchronous scheduler. + settings.single_thread_proxy_scheduler = false; + + layer_tree_host_ = + cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings, NULL); layer_tree_host_->SetRootLayer(root_layer_); layer_tree_host_->SetLayerTreeHostClientReady(); layer_tree_host_->set_has_transparent_background(true); diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h index f87890b..b07d36d 100644 --- a/android_webview/browser/hardware_renderer.h +++ b/android_webview/browser/hardware_renderer.h @@ -54,8 +54,6 @@ class HardwareRenderer : public cc::LayerTreeHostClient, virtual void DidCompleteSwapBuffers() OVERRIDE {} // cc::LayerTreeHostSingleThreadClient overrides. - virtual void ScheduleComposite() OVERRIDE {} - virtual void ScheduleAnimation() OVERRIDE {} virtual void DidPostSwapBuffers() OVERRIDE {} virtual void DidAbortSwapBuffers() OVERRIDE {} diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 0688868..6a6cd02 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn @@ -451,6 +451,7 @@ component("cc") { "trees/proxy.h", "trees/proxy_timing_history.cc", "trees/proxy_timing_history.h", + "trees/scoped_abort_remaining_swap_promises.h", "trees/single_thread_proxy.cc", "trees/single_thread_proxy.h", "trees/thread_proxy.cc", @@ -480,6 +480,7 @@ 'trees/proxy.h', 'trees/proxy_timing_history.cc', 'trees/proxy_timing_history.h', + 'trees/scoped_abort_remaining_swap_promises.h', 'trees/single_thread_proxy.cc', 'trees/single_thread_proxy.h', 'trees/thread_proxy.cc', diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 1451237..a20bfd2b 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc @@ -79,11 +79,11 @@ Scheduler::Scheduler( SchedulerClient* client, const SchedulerSettings& scheduler_settings, int layer_tree_host_id, - const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) : settings_(scheduler_settings), client_(client), layer_tree_host_id_(layer_tree_host_id), - impl_task_runner_(impl_task_runner), + task_runner_(task_runner), vsync_interval_(BeginFrameArgs::DefaultInterval()), last_set_needs_begin_frame_(false), begin_unthrottled_frame_posted_(false), @@ -128,7 +128,7 @@ Scheduler::~Scheduler() { void Scheduler::SetupSyntheticBeginFrames() { DCHECK(!synthetic_begin_frame_source_); synthetic_begin_frame_source_.reset( - new SyntheticBeginFrameSource(this, impl_task_runner_.get())); + new SyntheticBeginFrameSource(this, task_runner_.get())); } void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, @@ -274,6 +274,9 @@ base::TimeTicks Scheduler::LastBeginImplFrameTime() { } void Scheduler::SetupNextBeginFrameIfNeeded() { + if (!task_runner_) + return; + bool needs_begin_frame = state_machine_.BeginFrameNeeded(); if (settings_.throttle_frame_production) { @@ -328,7 +331,7 @@ void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled( } begin_unthrottled_frame_posted_ = true; - impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); + task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); } // BeginUnthrottledFrame is used when we aren't throttling frame production. @@ -362,7 +365,7 @@ void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { base::TimeDelta delay = begin_impl_frame_args_.IsValid() ? begin_impl_frame_args_.interval : BeginFrameArgs::DefaultInterval(); - impl_task_runner_->PostDelayedTask( + task_runner_->PostDelayedTask( FROM_HERE, poll_for_draw_triggers_task_.callback(), delay); } } else { @@ -387,9 +390,9 @@ void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { // Since we'd rather get a BeginImplFrame by the normal mechanism, we // set the interval to twice the interval from the previous frame. advance_commit_state_task_.Reset(advance_commit_state_closure_); - impl_task_runner_->PostDelayedTask(FROM_HERE, - advance_commit_state_task_.callback(), - begin_impl_frame_args_.interval * 2); + task_runner_->PostDelayedTask(FROM_HERE, + advance_commit_state_task_.callback(), + begin_impl_frame_args_.interval * 2); } } else { advance_commit_state_task_.Cancel(); @@ -491,7 +494,7 @@ void Scheduler::PostBeginRetroFrameIfNeeded() { return; begin_retro_frame_posted_ = true; - impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); + task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); } // BeginImplFrame starts a compositor frame that will wait up until a deadline @@ -499,8 +502,8 @@ void Scheduler::PostBeginRetroFrameIfNeeded() { // any asynchronous animation and scroll/pinch updates. void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue()); - DCHECK(state_machine_.begin_impl_frame_state() == - SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); + DCHECK_EQ(state_machine_.begin_impl_frame_state(), + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); DCHECK(state_machine_.HasInitializedOutputSurface()); advance_commit_state_task_.Cancel(); @@ -567,7 +570,7 @@ void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { base::TimeDelta delta = deadline - gfx::FrameTime::Now(); if (delta <= base::TimeDelta()) delta = base::TimeDelta(); - impl_task_runner_->PostDelayedTask( + task_runner_->PostDelayedTask( FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); } diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index afb9e9d..311a71d 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h @@ -57,9 +57,9 @@ class CC_EXPORT Scheduler { SchedulerClient* client, const SchedulerSettings& scheduler_settings, int layer_tree_host_id, - const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) { + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { return make_scoped_ptr(new Scheduler( - client, scheduler_settings, layer_tree_host_id, impl_task_runner)); + client, scheduler_settings, layer_tree_host_id, task_runner)); } virtual ~Scheduler(); @@ -173,16 +173,15 @@ class CC_EXPORT Scheduler { scoped_refptr<DelayBasedTimeSource> time_source_; }; - Scheduler( - SchedulerClient* client, - const SchedulerSettings& scheduler_settings, - int layer_tree_host_id, - const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner); + Scheduler(SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id, + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); const SchedulerSettings settings_; SchedulerClient* client_; int layer_tree_host_id_; - scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; base::TimeDelta vsync_interval_; base::TimeDelta estimated_parent_draw_time_; diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index a37a74a..723c40c 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc @@ -1006,7 +1006,9 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) { } } -void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; } +void SchedulerStateMachine::SetNeedsCommit() { + needs_commit_ = true; +} void SchedulerStateMachine::NotifyReadyToCommit() { DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED) diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h index f928453..7f7bd35 100644 --- a/cc/test/fake_layer_tree_host_client.h +++ b/cc/test/fake_layer_tree_host_client.h @@ -42,8 +42,6 @@ class FakeLayerTreeHostClient : public LayerTreeHostClient, virtual void DidCompleteSwapBuffers() OVERRIDE {} // LayerTreeHostSingleThreadClient implementation. - virtual void ScheduleComposite() OVERRIDE {} - virtual void ScheduleAnimation() OVERRIDE {} virtual void DidPostSwapBuffers() OVERRIDE {} virtual void DidAbortSwapBuffers() OVERRIDE {} diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index d72860d..312f643 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc @@ -312,14 +312,6 @@ class LayerTreeHostClientForTesting : public LayerTreeHostClient, test_hooks_->DidCompleteSwapBuffers(); } - virtual void ScheduleComposite() OVERRIDE { - test_hooks_->ScheduleComposite(); - } - - virtual void ScheduleAnimation() OVERRIDE { - test_hooks_->ScheduleAnimation(); - } - virtual void DidPostSwapBuffers() OVERRIDE {} virtual void DidAbortSwapBuffers() OVERRIDE {} @@ -394,7 +386,6 @@ LayerTreeTest::LayerTreeTest() end_when_begin_returns_(false), timed_out_(false), scheduled_(false), - schedule_when_set_visible_true_(false), started_(false), ended_(false), delegating_renderer_(false), @@ -558,15 +549,6 @@ void LayerTreeTest::Timeout() { EndTest(); } -void LayerTreeTest::ScheduleComposite() { - if (!started_ || scheduled_) - return; - scheduled_ = true; - main_task_runner_->PostTask( - FROM_HERE, - base::Bind(&LayerTreeTest::DispatchComposite, main_thread_weak_ptr_)); -} - void LayerTreeTest::RealEndTest() { if (layer_tree_host_ && proxy()->CommitPendingForTesting()) { main_task_runner_->PostTask( @@ -618,16 +600,8 @@ void LayerTreeTest::DispatchSetNeedsRedrawRect(const gfx::Rect& damage_rect) { void LayerTreeTest::DispatchSetVisible(bool visible) { DCHECK(!proxy() || proxy()->IsMainThread()); - - if (!layer_tree_host_) - return; - - layer_tree_host_->SetVisible(visible); - - // If the LTH is being made visible and a previous ScheduleComposite() was - // deferred because the LTH was not visible, re-schedule the composite now. - if (layer_tree_host_->visible() && schedule_when_set_visible_true_) - ScheduleComposite(); + if (layer_tree_host_) + layer_tree_host_->SetVisible(visible); } void LayerTreeTest::DispatchSetNextCommitForcesRedraw() { @@ -637,24 +611,6 @@ void LayerTreeTest::DispatchSetNextCommitForcesRedraw() { layer_tree_host_->SetNextCommitForcesRedraw(); } -void LayerTreeTest::DispatchComposite() { - scheduled_ = false; - - if (!layer_tree_host_) - return; - - // If the LTH is not visible, defer the composite until the LTH is made - // visible. - if (!layer_tree_host_->visible()) { - schedule_when_set_visible_true_ = true; - return; - } - - schedule_when_set_visible_true_ = false; - base::TimeTicks now = gfx::FrameTime::Now(); - layer_tree_host_->Composite(now); -} - void LayerTreeTest::RunTest(bool threaded, bool delegating_renderer, bool impl_side_painting) { diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index 8f38dda..619ae96 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h @@ -71,8 +71,6 @@ class TestHooks : public AnimationDelegate { virtual void DidCommit() {} virtual void DidCommitAndDrawFrame() {} virtual void DidCompleteSwapBuffers() {} - virtual void ScheduleComposite() {} - virtual void ScheduleAnimation() {} virtual void DidDeferCommit() {} virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl, bool visible) {} @@ -139,8 +137,6 @@ class LayerTreeTest : public testing::Test, public TestHooks { virtual void InitializeSettings(LayerTreeSettings* settings) {} - virtual void ScheduleComposite() OVERRIDE; - void RealEndTest(); virtual void DispatchAddAnimation(Layer* layer_to_receive_animation, @@ -151,7 +147,6 @@ class LayerTreeTest : public testing::Test, public TestHooks { void DispatchSetNeedsRedrawRect(const gfx::Rect& damage_rect); void DispatchSetVisible(bool visible); void DispatchSetNextCommitForcesRedraw(); - void DispatchComposite(); void DispatchDidAddAnimation(); virtual void AfterTest() = 0; @@ -204,7 +199,6 @@ class LayerTreeTest : public testing::Test, public TestHooks { bool end_when_begin_returns_; bool timed_out_; bool scheduled_; - bool schedule_when_set_visible_true_; bool started_; bool ended_; bool delegating_renderer_; diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index ed7472d..03969f2 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc @@ -697,8 +697,12 @@ void LayerTreeHost::NotifyInputThrottledUntilCommit() { void LayerTreeHost::Composite(base::TimeTicks frame_begin_time) { DCHECK(!proxy_->HasImplThread()); + // This function is only valid when not using the scheduler. + DCHECK(!settings_.single_thread_proxy_scheduler); SingleThreadProxy* proxy = static_cast<SingleThreadProxy*>(proxy_.get()); + SetLayerTreeHostClientReady(); + if (output_surface_lost_) proxy->CreateAndInitializeOutputSurface(); if (output_surface_lost_) diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc index 70b2a64..4ddb1f2 100644 --- a/cc/trees/layer_tree_host_perftest.cc +++ b/cc/trees/layer_tree_host_perftest.cc @@ -228,6 +228,8 @@ class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader { } virtual void Layout() OVERRIDE { + if (TestEnded()) + return; static const gfx::Vector2d delta = gfx::Vector2d(0, 10); scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta); } diff --git a/cc/trees/layer_tree_host_single_thread_client.h b/cc/trees/layer_tree_host_single_thread_client.h index cb61450..dbca28c 100644 --- a/cc/trees/layer_tree_host_single_thread_client.h +++ b/cc/trees/layer_tree_host_single_thread_client.h @@ -10,10 +10,10 @@ namespace cc { class LayerTreeHostSingleThreadClient { public: // Request that the client schedule a composite. - virtual void ScheduleComposite() = 0; + virtual void ScheduleComposite() {} // Request that the client schedule a composite now, and calculate appropriate // delay for potential future frame. - virtual void ScheduleAnimation() = 0; + virtual void ScheduleAnimation() {} // Called whenever the compositor posts a SwapBuffers (either full or // partial). After DidPostSwapBuffers(), exactly one of diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 2ddee12..453c75c 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc @@ -91,8 +91,8 @@ class LayerTreeHostTestSetNeedsCommit1 : public LayerTreeHostTest { } virtual void AfterTest() OVERRIDE { - EXPECT_GE(1, num_commits_); - EXPECT_GE(1, num_draws_); + EXPECT_LE(1, num_commits_); + EXPECT_LE(1, num_draws_); } private: @@ -694,31 +694,6 @@ class LayerTreeHostTestUndrawnLayersPushContentBoundsLater SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostTestUndrawnLayersPushContentBoundsLater); -class LayerTreeHostTestAbortFrameWhenInvisible : public LayerTreeHostTest { - public: - LayerTreeHostTestAbortFrameWhenInvisible() {} - - virtual void BeginTest() OVERRIDE { - // Request a commit (from the main thread), Which will trigger the commit - // flow from the impl side. - layer_tree_host()->SetNeedsCommit(); - // Then mark ourselves as not visible before processing any more messages - // on the main thread. - layer_tree_host()->SetVisible(false); - // If we make it without kicking a frame, we pass! - EndTestAfterDelay(1); - } - - virtual void Layout() OVERRIDE { - ASSERT_FALSE(true); - EndTest(); - } - - virtual void AfterTest() OVERRIDE {} -}; - -MULTI_THREAD_TEST_F(LayerTreeHostTestAbortFrameWhenInvisible); - // This test verifies that properties on the layer tree host are commited // to the impl side. class LayerTreeHostTestCommit : public LayerTreeHostTest { @@ -1959,7 +1934,7 @@ class LayerTreeHostTestDeferCommits : public LayerTreeHostTest { int num_complete_commits_; }; -MULTI_THREAD_TEST_F(LayerTreeHostTestDeferCommits); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferCommits); class LayerTreeHostWithProxy : public LayerTreeHost { public: @@ -2032,6 +2007,7 @@ TEST(LayerTreeHostTest, PartialUpdatesWithGLRenderer) { LayerTreeSettings settings; settings.max_partial_texture_updates = 4; + settings.single_thread_proxy_scheduler = false; scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); @@ -2051,6 +2027,7 @@ TEST(LayerTreeHostTest, PartialUpdatesWithSoftwareRenderer) { LayerTreeSettings settings; settings.max_partial_texture_updates = 4; + settings.single_thread_proxy_scheduler = false; scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); @@ -2070,6 +2047,7 @@ TEST(LayerTreeHostTest, PartialUpdatesWithDelegatingRendererAndGLContent) { LayerTreeSettings settings; settings.max_partial_texture_updates = 4; + settings.single_thread_proxy_scheduler = false; scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); @@ -2090,6 +2068,7 @@ TEST(LayerTreeHostTest, LayerTreeSettings settings; settings.max_partial_texture_updates = 4; + settings.single_thread_proxy_scheduler = false; scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); @@ -4586,10 +4565,11 @@ class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest { // TODO(miletus): Flaky test: crbug.com/393995 // MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise); -class LayerTreeHostTestBreakSwapPromiseForAbortedCommit +class LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit : public LayerTreeHostTest { protected: - LayerTreeHostTestBreakSwapPromiseForAbortedCommit() : commit_count_(0) {} + LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit() + : commit_count_(0) {} virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } @@ -4628,7 +4608,54 @@ class LayerTreeHostTestBreakSwapPromiseForAbortedCommit TestSwapPromiseResult swap_promise_result_; }; -MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromiseForAbortedCommit); +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit); + +class LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit + : public LayerTreeHostTest { + protected: + LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit() + : commit_count_(0) {} + + virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void WillBeginMainFrame() OVERRIDE { + layer_tree_host()->SetDeferCommits(true); + layer_tree_host()->SetNeedsCommit(); + } + + virtual void DidDeferCommit() OVERRIDE { + layer_tree_host()->DidLoseOutputSurface(); + layer_tree_host()->SetDeferCommits(false); + + scoped_ptr<SwapPromise> swap_promise( + new TestSwapPromise(&swap_promise_result_)); + layer_tree_host()->QueueSwapPromise(swap_promise.Pass()); + } + + virtual void DidCommit() OVERRIDE { PostSetNeedsCommitToMainThread(); } + + virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, + bool did_handle) OVERRIDE { + EndTest(); + } + + virtual void AfterTest() OVERRIDE { + { + base::AutoLock lock(swap_promise_result_.lock); + EXPECT_FALSE(swap_promise_result_.did_swap_called); + EXPECT_TRUE(swap_promise_result_.did_not_swap_called); + EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason); + EXPECT_TRUE(swap_promise_result_.dtor_called); + } + } + + int commit_count_; + TestSwapPromiseResult swap_promise_result_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit); class SimpleSwapPromiseMonitor : public SwapPromiseMonitor { public: @@ -4708,7 +4735,7 @@ class LayerTreeHostTestSimpleSwapPromiseMonitor : public LayerTreeHostTest { virtual void AfterTest() OVERRIDE {} }; -MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor); class LayerTreeHostTestHighResRequiredAfterEvictingUIResources : public LayerTreeHostTest { diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc index f717c2a..1853bfc 100644 --- a/cc/trees/layer_tree_host_unittest_animation.cc +++ b/cc/trees/layer_tree_host_unittest_animation.cc @@ -726,9 +726,7 @@ class LayerTreeHostAnimationTestContinuousAnimate : public LayerTreeHostAnimationTest { public: LayerTreeHostAnimationTestContinuousAnimate() - : num_commit_complete_(0), - num_draw_layers_(0) { - } + : num_commit_complete_(0), num_draw_layers_(0), have_animated_(false) {} virtual void SetupTree() OVERRIDE { LayerTreeHostAnimationTest::SetupTree(); @@ -747,6 +745,7 @@ class LayerTreeHostAnimationTestContinuousAnimate if (num_draw_layers_ == 2) return; layer_tree_host()->SetNeedsAnimate(); + have_animated_ = true; } virtual void Layout() OVERRIDE { @@ -767,16 +766,18 @@ class LayerTreeHostAnimationTestContinuousAnimate virtual void AfterTest() OVERRIDE { // Check that we didn't commit twice between first and second draw. EXPECT_EQ(1, num_commit_complete_); + EXPECT_TRUE(have_animated_); } private: int num_commit_complete_; int num_draw_layers_; + bool have_animated_; FakeContentLayerClient client_; scoped_refptr<FakeContentLayer> content_; }; -MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestContinuousAnimate); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestContinuousAnimate); class LayerTreeHostAnimationTestCancelAnimateCommit : public LayerTreeHostAnimationTest { diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc index 80898d2..887e603 100644 --- a/cc/trees/layer_tree_host_unittest_context.cc +++ b/cc/trees/layer_tree_host_unittest_context.cc @@ -65,6 +65,9 @@ class LayerTreeHostContextTest : public LayerTreeTest { } void LoseContext() { + // For sanity-checking tests, they should only call this when the + // context is not lost. + CHECK(context3d_); context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); context3d_ = NULL; @@ -200,45 +203,53 @@ class LayerTreeHostContextTestLostContextSucceeds static const TestCase kTests[] = { // Losing the context and failing to recreate it (or losing it again // immediately) a small number of times should succeed. - {1, // times_to_lose_during_commit + { + 1, // times_to_lose_during_commit 0, // times_to_lose_during_draw 0, // times_to_fail_recreate false, // fallback_context_works }, - {0, // times_to_lose_during_commit + { + 0, // times_to_lose_during_commit 1, // times_to_lose_during_draw 0, // times_to_fail_recreate false, // fallback_context_works }, - {1, // times_to_lose_during_commit + { + 1, // times_to_lose_during_commit 0, // times_to_lose_during_draw 3, // times_to_fail_recreate false, // fallback_context_works }, - {0, // times_to_lose_during_commit + { + 0, // times_to_lose_during_commit 1, // times_to_lose_during_draw 3, // times_to_fail_recreate false, // fallback_context_works }, // Losing the context and recreating it any number of times should // succeed. - {10, // times_to_lose_during_commit + { + 10, // times_to_lose_during_commit 0, // times_to_lose_during_draw 0, // times_to_fail_recreate false, // fallback_context_works }, - {0, // times_to_lose_during_commit + { + 0, // times_to_lose_during_commit 10, // times_to_lose_during_draw 0, // times_to_fail_recreate false, // fallback_context_works }, // Losing the context, failing to reinitialize it, and making a fallback // context should work. - {0, // times_to_lose_during_commit + { + 0, // times_to_lose_during_commit 1, // times_to_lose_during_draw 0, // times_to_fail_recreate true, // fallback_context_works - }, }; + }, + }; if (test_case_ >= arraysize(kTests)) return false; @@ -300,7 +311,8 @@ class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface } }; -MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface); +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostClientNotReadyDoesNotCreateOutputSurface); class LayerTreeHostContextTestLostContextSucceedsWithContent : public LayerTreeHostContextTestLostContextSucceeds { @@ -358,10 +370,11 @@ class LayerTreeHostContextTestCreateOutputSurfaceFails : times_to_fail_(times_to_fail), expect_fallback_attempt_(expect_fallback_attempt), did_attempt_fallback_(false), - times_initialized_(0) {} + times_initialized_(0) { + times_to_fail_create_ = times_to_fail_; + } virtual void BeginTest() OVERRIDE { - times_to_fail_create_ = times_to_fail_; PostSetNeedsCommitToMainThread(); } @@ -975,12 +988,6 @@ class ScrollbarLayerLostContext : public LayerTreeHostContextTest { EXPECT_EQ(2, scrollbar_layer_->update_count()); EndTest(); break; - case 3: - // Single thread proxy issues extra commits after context lost. - // http://crbug.com/287250 - if (HasImplThread()) - NOTREACHED(); - break; default: NOTREACHED(); } @@ -1024,12 +1031,10 @@ class UIResourceLostTest : public LayerTreeHostContextTest { void PostLoseContextToImplThread() { EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - base::SingleThreadTaskRunner* task_runner = - HasImplThread() ? ImplThreadTaskRunner() - : base::MessageLoopProxy::current(); - task_runner->PostTask(FROM_HERE, - base::Bind(&LayerTreeHostContextTest::LoseContext, - base::Unretained(this))); + ImplThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&LayerTreeHostContextTest::LoseContext, + base::Unretained(this))); } protected: @@ -1084,13 +1089,8 @@ class UIResourceLostAfterCommit : public UIResourceLostTestSimple { EndTest(); break; case 5: - // Single thread proxy issues extra commits after context lost. - // http://crbug.com/287250 - if (HasImplThread()) - NOTREACHED(); - break; - case 6: NOTREACHED(); + break; } } @@ -1178,13 +1178,8 @@ class UIResourceLostBeforeCommit : public UIResourceLostTestSimple { EndTest(); break; case 6: - // Single thread proxy issues extra commits after context lost. - // http://crbug.com/287250 - if (HasImplThread()) - NOTREACHED(); - break; - case 8: NOTREACHED(); + break; } } @@ -1205,15 +1200,8 @@ class UIResourceLostBeforeCommit : public UIResourceLostTestSimple { // Sequence 2 (continued): // The previous resource should have been deleted. EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_)); - if (HasImplThread()) { - // The second resource should have been created. - EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_)); - } else { - // The extra commit that happens at context lost in the single thread - // proxy changes the timing so that the resource has been destroyed. - // http://crbug.com/287250 - EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id1_)); - } + // The second resource should have been created. + EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_)); // The second resource called the resource callback once and since the // context is lost, a "resource lost" callback was also issued. EXPECT_EQ(2, ui_resource_->resource_create_count); @@ -1529,8 +1517,8 @@ class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame bool deferred_; }; -// TODO(danakj): We don't use scheduler with SingleThreadProxy yet. -MULTI_THREAD_TEST_F(LayerTreeHostContextTestLoseAfterSendingBeginMainFrame); +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostContextTestLoseAfterSendingBeginMainFrame); } // namespace } // namespace cc diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc index 1a24ba5..ea3bfc6 100644 --- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc +++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc @@ -74,8 +74,6 @@ class LayerTreeHostNoMessageLoopTest virtual void DidCompleteSwapBuffers() OVERRIDE {} // LayerTreeHostSingleThreadClient overrides. - virtual void ScheduleComposite() OVERRIDE {} - virtual void ScheduleAnimation() OVERRIDE {} virtual void DidPostSwapBuffers() OVERRIDE {} virtual void DidAbortSwapBuffers() OVERRIDE {} @@ -96,6 +94,7 @@ class LayerTreeHostNoMessageLoopTest void SetupLayerTreeHost() { LayerTreeSettings settings; + settings.single_thread_proxy_scheduler = false; layer_tree_host_ = LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings, NULL); layer_tree_host_->SetViewportSize(size_); diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc index bf72893..56e18a2 100644 --- a/cc/trees/layer_tree_settings.cc +++ b/cc/trees/layer_tree_settings.cc @@ -16,6 +16,7 @@ LayerTreeSettings::LayerTreeSettings() : impl_side_painting(false), allow_antialiasing(true), throttle_frame_production(true), + single_thread_proxy_scheduler(true), begin_frame_scheduling_enabled(false), main_frame_before_draw_enabled(true), main_frame_before_activation_enabled(false), diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h index 14cec67..bad3bf4 100644 --- a/cc/trees/layer_tree_settings.h +++ b/cc/trees/layer_tree_settings.h @@ -21,6 +21,7 @@ class CC_EXPORT LayerTreeSettings { bool impl_side_painting; bool allow_antialiasing; bool throttle_frame_production; + bool single_thread_proxy_scheduler; bool begin_frame_scheduling_enabled; bool main_frame_before_draw_enabled; bool main_frame_before_activation_enabled; diff --git a/cc/trees/scoped_abort_remaining_swap_promises.h b/cc/trees/scoped_abort_remaining_swap_promises.h new file mode 100644 index 0000000..f8dfc01 --- /dev/null +++ b/cc/trees/scoped_abort_remaining_swap_promises.h @@ -0,0 +1,30 @@ +// Copyright 2014 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_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_ +#define CC_TREES_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_ + +#include "cc/base/swap_promise.h" +#include "cc/trees/layer_tree_host.h" + +namespace cc { + +class ScopedAbortRemainingSwapPromises { + public: + explicit ScopedAbortRemainingSwapPromises(LayerTreeHost* layer_tree_host) + : layer_tree_host_(layer_tree_host) {} + + ~ScopedAbortRemainingSwapPromises() { + layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_FAILS); + } + + private: + LayerTreeHost* layer_tree_host_; + + DISALLOW_COPY_AND_ASSIGN(ScopedAbortRemainingSwapPromises); +}; + +} // namespace cc + +#endif // CC_TREES_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_ diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 2f67740..24e5e2a 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc @@ -16,6 +16,7 @@ #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_single_thread_client.h" #include "cc/trees/layer_tree_impl.h" +#include "cc/trees/scoped_abort_remaining_swap_promises.h" #include "ui/gfx/frame_time.h" namespace cc { @@ -36,8 +37,13 @@ SingleThreadProxy::SingleThreadProxy( : Proxy(main_task_runner, NULL), layer_tree_host_(layer_tree_host), client_(client), + timing_history_(layer_tree_host->rendering_stats_instrumentation()), next_frame_is_newly_committed_frame_(false), - inside_draw_(false) { + inside_draw_(false), + defer_commits_(false), + commit_was_deferred_(false), + commit_requested_(false), + weak_factory_(this) { TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy"); DCHECK(Proxy::IsMainThread()); DCHECK(layer_tree_host); @@ -77,13 +83,26 @@ void SingleThreadProxy::SetLayerTreeHostClientReady() { TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady"); // Scheduling is controlled by the embedder in the single thread case, so // nothing to do. + DCHECK(Proxy::IsMainThread()); + DebugScopedSetImplThread impl(this); + if (layer_tree_host_->settings().single_thread_proxy_scheduler && + !scheduler_on_impl_thread_) { + SchedulerSettings scheduler_settings(layer_tree_host_->settings()); + scheduler_on_impl_thread_ = Scheduler::Create(this, + scheduler_settings, + layer_tree_host_->id(), + MainThreadTaskRunner()); + scheduler_on_impl_thread_->SetCanStart(); + scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); + } } void SingleThreadProxy::SetVisible(bool visible) { TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible"); DebugScopedSetImplThread impl(this); layer_tree_host_impl_->SetVisible(visible); - + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible()); // Changing visibility could change ShouldComposite(). UpdateBackgroundAnimateTicking(); } @@ -110,9 +129,14 @@ void SingleThreadProxy::CreateAndInitializeOutputSurface() { layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success); - if (!success) { - // Force another recreation attempt to happen by requesting another commit. - SetNeedsCommit(); + if (success) { + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface(); + } else if (Proxy::MainThreadTaskRunner()) { + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&SingleThreadProxy::CreateAndInitializeOutputSurface, + weak_factory_.GetWeakPtr())); } } @@ -126,17 +150,40 @@ void SingleThreadProxy::SetNeedsAnimate() { TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate"); DCHECK(Proxy::IsMainThread()); client_->ScheduleAnimation(); + SetNeedsCommit(); } void SingleThreadProxy::SetNeedsUpdateLayers() { TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers"); DCHECK(Proxy::IsMainThread()); - client_->ScheduleComposite(); + SetNeedsCommit(); } -void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { +void SingleThreadProxy::DoCommit(base::TimeTicks frame_begin_time) { TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit"); DCHECK(Proxy::IsMainThread()); + layer_tree_host_->WillBeginMainFrame(); + layer_tree_host_->UpdateClientAnimations(frame_begin_time); + layer_tree_host_->AnimateLayers(frame_begin_time); + layer_tree_host_->Layout(); + commit_requested_ = false; + + if (PrioritizedResourceManager* contents_texture_manager = + layer_tree_host_->contents_texture_manager()) { + contents_texture_manager->UnlinkAndClearEvictedBackings(); + contents_texture_manager->SetMaxMemoryLimitBytes( + layer_tree_host_impl_->memory_allocation_limit_bytes()); + contents_texture_manager->SetExternalPriorityCutoff( + layer_tree_host_impl_->memory_allocation_priority_cutoff()); + } + + scoped_ptr<ResourceUpdateQueue> queue = + make_scoped_ptr(new ResourceUpdateQueue); + + layer_tree_host_->UpdateLayers(queue.get()); + + layer_tree_host_->WillCommit(); + // Commit immediately. { DebugScopedSetMainThreadBlocked main_thread_blocked(this); @@ -158,7 +205,7 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { scoped_ptr<ResourceUpdateController> update_controller = ResourceUpdateController::Create( NULL, - Proxy::MainThreadTaskRunner(), + MainThreadTaskRunner(), queue.Pass(), layer_tree_host_impl_->resource_provider()); update_controller->Finalize(); @@ -170,6 +217,8 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { layer_tree_host_impl_->CommitComplete(); + UpdateBackgroundAnimateTicking(); + #if DCHECK_IS_ON // In the single-threaded case, the scale and scroll deltas should never be // touched on the impl layer tree. @@ -186,30 +235,63 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { stats_instrumentation->AccumulateAndClearMainThreadStats(); } layer_tree_host_->CommitComplete(); + layer_tree_host_->DidBeginMainFrame(); + timing_history_.DidCommit(); + next_frame_is_newly_committed_frame_ = true; } void SingleThreadProxy::SetNeedsCommit() { DCHECK(Proxy::IsMainThread()); + DebugScopedSetImplThread impl(this); client_->ScheduleComposite(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetNeedsCommit(); + commit_requested_ = true; } void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw"); - SetNeedsRedrawRectOnImplThread(damage_rect); + DCHECK(Proxy::IsMainThread()); + DebugScopedSetImplThread impl(this); client_->ScheduleComposite(); + SetNeedsRedrawRectOnImplThread(damage_rect); } void SingleThreadProxy::SetNextCommitWaitsForActivation() { // There is no activation here other than commit. So do nothing. + DCHECK(Proxy::IsMainThread()); } void SingleThreadProxy::SetDeferCommits(bool defer_commits) { + DCHECK(Proxy::IsMainThread()); + // Deferring commits only makes sense if there's a scheduler. + if (!scheduler_on_impl_thread_) + return; + if (defer_commits_ == defer_commits) + return; + + if (defer_commits) + TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this); + else + TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this); + + defer_commits_ = defer_commits; + if (!defer_commits_ && commit_was_deferred_) { + commit_was_deferred_ = false; + BeginMainFrame(); + } } -bool SingleThreadProxy::CommitRequested() const { return false; } +bool SingleThreadProxy::CommitRequested() const { + DCHECK(Proxy::IsMainThread()); + return commit_requested_; +} -bool SingleThreadProxy::BeginMainFrameRequested() const { return false; } +bool SingleThreadProxy::BeginMainFrameRequested() const { + DCHECK(Proxy::IsMainThread()); + return commit_requested_; +} size_t SingleThreadProxy::MaxPartialTextureUpdates() const { return std::numeric_limits<size_t>::max(); @@ -225,6 +307,7 @@ void SingleThreadProxy::Stop() { BlockingTaskRunner::CapturePostTasks blocked; layer_tree_host_->DeleteContentsTexturesOnImplThread( layer_tree_host_impl_->resource_provider()); + scheduler_on_impl_thread_.reset(); layer_tree_host_impl_.reset(); } layer_tree_host_ = NULL; @@ -235,15 +318,19 @@ void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) { "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); DCHECK(Proxy::IsImplThread()); UpdateBackgroundAnimateTicking(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetCanDraw(can_draw); } void SingleThreadProxy::NotifyReadyToActivate() { - // Thread-only feature. + // Impl-side painting only. NOTREACHED(); } void SingleThreadProxy::SetNeedsRedrawOnImplThread() { client_->ScheduleComposite(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetNeedsRedraw(); } void SingleThreadProxy::SetNeedsAnimateOnImplThread() { @@ -251,17 +338,14 @@ void SingleThreadProxy::SetNeedsAnimateOnImplThread() { } void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { - // Thread-only/Impl-side-painting-only feature. + // Impl-side painting only. NOTREACHED(); } void SingleThreadProxy::SetNeedsRedrawRectOnImplThread( const gfx::Rect& damage_rect) { - // TODO(brianderson): Once we move render_widget scheduling into this class, - // we can treat redraw requests more efficiently than CommitAndRedraw - // requests. layer_tree_host_impl_->SetViewportDamage(damage_rect); - SetNeedsCommit(); + SetNeedsRedrawOnImplThread(); } void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { @@ -271,6 +355,8 @@ void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { void SingleThreadProxy::SetNeedsCommitOnImplThread() { client_->ScheduleComposite(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->SetNeedsCommit(); } void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread( @@ -307,66 +393,53 @@ void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() { layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities(); } +void SingleThreadProxy::DidManageTiles() { + // Impl-side painting only. + NOTREACHED(); +} + void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() { TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread"); - // Cause a commit so we can notice the lost context. - SetNeedsCommitOnImplThread(); + { + DebugScopedSetMainThread main(this); + // This must happen before we notify the scheduler as it may try to recreate + // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE. + layer_tree_host_->DidLoseOutputSurface(); + } client_->DidAbortSwapBuffers(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidLoseOutputSurface(); } void SingleThreadProxy::DidSwapBuffersOnImplThread() { + TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread"); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidSwapBuffers(); client_->DidPostSwapBuffers(); } void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() { TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread"); - client_->DidCompleteSwapBuffers(); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidSwapBuffersComplete(); + layer_tree_host_->DidCompleteSwapBuffers(); +} + +void SingleThreadProxy::BeginFrame(const BeginFrameArgs& args) { + TRACE_EVENT0("cc", "SingleThreadProxy::BeginFrame"); + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->BeginImplFrame(args); } -// Called by the legacy scheduling path (e.g. where render_widget does the -// scheduling) void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately"); DCHECK(Proxy::IsMainThread()); DCHECK(!layer_tree_host_->output_surface_lost()); - layer_tree_host_->AnimateLayers(frame_begin_time); - - if (PrioritizedResourceManager* contents_texture_manager = - layer_tree_host_->contents_texture_manager()) { - contents_texture_manager->UnlinkAndClearEvictedBackings(); - contents_texture_manager->SetMaxMemoryLimitBytes( - layer_tree_host_impl_->memory_allocation_limit_bytes()); - contents_texture_manager->SetExternalPriorityCutoff( - layer_tree_host_impl_->memory_allocation_priority_cutoff()); - } - - scoped_ptr<ResourceUpdateQueue> queue = - make_scoped_ptr(new ResourceUpdateQueue); - layer_tree_host_->UpdateLayers(queue.get()); - layer_tree_host_->WillCommit(); - DoCommit(queue.Pass()); - layer_tree_host_->DidBeginMainFrame(); + DoCommit(frame_begin_time); LayerTreeHostImpl::FrameData frame; - if (DoComposite(frame_begin_time, &frame)) { - { - DebugScopedSetMainThreadBlocked main_thread_blocked(this); - DebugScopedSetImplThread impl(this); - - // This CapturePostTasks should be destroyed before - // DidCommitAndDrawFrame() is called since that goes out to the embedder, - // and we want the embedder to receive its callbacks before that. - // NOTE: This maintains consistent ordering with the ThreadProxy since - // the DidCommitAndDrawFrame() must be post-tasked from the impl thread - // there as the main thread is not blocked, so any posted tasks inside - // the swap buffers will execute first. - BlockingTaskRunner::CapturePostTasks blocked; - - layer_tree_host_impl_->SwapBuffers(frame); - } - DidSwapFrame(); - } + DoComposite(frame_begin_time, &frame); } void SingleThreadProxy::AsValueInto(base::debug::TracedValue* state) const { @@ -406,13 +479,11 @@ void SingleThreadProxy::UpdateBackgroundAnimateTicking() { !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer()); } -bool SingleThreadProxy::DoComposite( - base::TimeTicks frame_begin_time, - LayerTreeHostImpl::FrameData* frame) { +DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time, + LayerTreeHostImpl::FrameData* frame) { TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite"); DCHECK(!layer_tree_host_->output_surface_lost()); - bool lost_output_surface = false; { DebugScopedSetImplThread impl(this); base::AutoReset<bool> mark_inside(&inside_draw_, true); @@ -423,9 +494,11 @@ bool SingleThreadProxy::DoComposite( // CanDraw() as well. if (!ShouldComposite()) { UpdateBackgroundAnimateTicking(); - return false; + return DRAW_ABORTED_CANT_DRAW; } + timing_history_.DidStartDrawing(); + layer_tree_host_impl_->Animate( layer_tree_host_impl_->CurrentFrameTimeTicks()); UpdateBackgroundAnimateTicking(); @@ -435,24 +508,43 @@ bool SingleThreadProxy::DoComposite( layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); layer_tree_host_impl_->DidDrawAllLayers(*frame); } - lost_output_surface = layer_tree_host_impl_->IsContextLost(); bool start_ready_animations = true; layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); + + timing_history_.DidFinishDrawing(); } - if (lost_output_surface) { - layer_tree_host_->DidLoseOutputSurface(); - return false; + { + DebugScopedSetImplThread impl(this); + + if (layer_tree_host_impl_->IsContextLost()) { + DidLoseOutputSurfaceOnImplThread(); + } else { + // This CapturePostTasks should be destroyed before + // DidCommitAndDrawFrame() is called since that goes out to the + // embedder, + // and we want the embedder to receive its callbacks before that. + // NOTE: This maintains consistent ordering with the ThreadProxy since + // the DidCommitAndDrawFrame() must be post-tasked from the impl thread + // there as the main thread is not blocked, so any posted tasks inside + // the swap buffers will execute first. + DebugScopedSetMainThreadBlocked main_thread_blocked(this); + + BlockingTaskRunner::CapturePostTasks blocked; + layer_tree_host_impl_->SwapBuffers(*frame); + } } + DidCommitAndDrawFrame(); - return true; + return DRAW_SUCCESS; } -void SingleThreadProxy::DidSwapFrame() { +void SingleThreadProxy::DidCommitAndDrawFrame() { if (next_frame_is_newly_committed_frame_) { + DebugScopedSetMainThread main(this); next_frame_is_newly_committed_frame_ = false; layer_tree_host_->DidCommitAndDrawFrame(); } @@ -460,4 +552,146 @@ void SingleThreadProxy::DidSwapFrame() { bool SingleThreadProxy::CommitPendingForTesting() { return false; } +void SingleThreadProxy::SetNeedsBeginFrame(bool enable) { + layer_tree_host_impl_->SetNeedsBeginFrame(enable); +} + +void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { + layer_tree_host_impl_->WillBeginImplFrame(args); +} + +void SingleThreadProxy::ScheduledActionSendBeginMainFrame() { + TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame"); + // Although this proxy is single-threaded, it's problematic to synchronously + // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame. This + // could cause a commit to occur in between a series of SetNeedsCommit calls + // (i.e. property modifications) causing some to fall on one frame and some to + // fall on the next. Doing it asynchronously instead matches the semantics of + // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a + // synchronous commit. + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&SingleThreadProxy::BeginMainFrame, + weak_factory_.GetWeakPtr())); +} + +void SingleThreadProxy::BeginMainFrame() { + if (defer_commits_) { + DCHECK(!commit_was_deferred_); + commit_was_deferred_ = true; + layer_tree_host_->DidDeferCommit(); + return; + } + + // This checker assumes NotifyReadyToCommit below causes a synchronous commit. + ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_); + + if (!layer_tree_host_->visible()) { + TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); + BeginMainFrameAbortedOnImplThread(); + return; + } + + if (layer_tree_host_->output_surface_lost()) { + TRACE_EVENT_INSTANT0( + "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD); + BeginMainFrameAbortedOnImplThread(); + return; + } + + timing_history_.DidBeginMainFrame(); + + DCHECK(scheduler_on_impl_thread_); + scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(); + scheduler_on_impl_thread_->NotifyReadyToCommit(); +} + +void SingleThreadProxy::BeginMainFrameAbortedOnImplThread() { + DebugScopedSetImplThread impl(this); + DCHECK(scheduler_on_impl_thread_->CommitPending()); + DCHECK(!layer_tree_host_impl_->pending_tree()); + + // TODO(enne): SingleThreadProxy does not support cancelling commits yet so + // did_handle is always false. + bool did_handle = false; + layer_tree_host_impl_->BeginMainFrameAborted(did_handle); + scheduler_on_impl_thread_->BeginMainFrameAborted(did_handle); +} + +DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() { + DebugScopedSetImplThread impl(this); + if (layer_tree_host_impl_->IsContextLost()) { + DidCommitAndDrawFrame(); + return DRAW_SUCCESS; + } + + LayerTreeHostImpl::FrameData frame; + return DoComposite(layer_tree_host_impl_->CurrentFrameTimeTicks(), &frame); +} + +DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapForced() { + NOTREACHED(); + return INVALID_RESULT; +} + +void SingleThreadProxy::ScheduledActionCommit() { + DebugScopedSetMainThread main(this); + DoCommit(layer_tree_host_impl_->CurrentFrameTimeTicks()); +} + +void SingleThreadProxy::ScheduledActionAnimate() { + TRACE_EVENT0("cc", "ScheduledActionAnimate"); + layer_tree_host_impl_->Animate( + layer_tree_host_impl_->CurrentFrameTimeTicks()); +} + +void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() { + // Impl-side painting only. + NOTREACHED(); +} + +void SingleThreadProxy::ScheduledActionActivateSyncTree() { +} + +void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { + DebugScopedSetMainThread main(this); + DCHECK(scheduler_on_impl_thread_); + // If possible, create the output surface in a post task. Synchronously + // creating the output surface makes tests more awkward since this differs + // from the ThreadProxy behavior. However, sometimes there is no + // task runner. + if (Proxy::MainThreadTaskRunner()) { + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&SingleThreadProxy::CreateAndInitializeOutputSurface, + weak_factory_.GetWeakPtr())); + } else { + CreateAndInitializeOutputSurface(); + } +} + +void SingleThreadProxy::ScheduledActionManageTiles() { + // Impl-side painting only. + NOTREACHED(); +} + +void SingleThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { +} + +base::TimeDelta SingleThreadProxy::DrawDurationEstimate() { + return timing_history_.DrawDurationEstimate(); +} + +base::TimeDelta SingleThreadProxy::BeginMainFrameToCommitDurationEstimate() { + return timing_history_.BeginMainFrameToCommitDurationEstimate(); +} + +base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() { + return timing_history_.CommitToActivateDurationEstimate(); +} + +void SingleThreadProxy::DidBeginImplFrameDeadline() { + layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); +} + } // namespace cc diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index 2b70d70..0582f1e 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h @@ -10,8 +10,10 @@ #include "base/time/time.h" #include "cc/animation/animation_events.h" #include "cc/output/begin_frame_args.h" +#include "cc/scheduler/scheduler.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/proxy.h" +#include "cc/trees/proxy_timing_history.h" namespace cc { @@ -20,7 +22,8 @@ class LayerTreeHost; class LayerTreeHostSingleThreadClient; class CC_EXPORT SingleThreadProxy : public Proxy, - NON_EXPORTED_BASE(LayerTreeHostImplClient) { + NON_EXPORTED_BASE(LayerTreeHostImplClient), + SchedulerClient { public: static scoped_ptr<Proxy> Create( LayerTreeHost* layer_tree_host, @@ -52,6 +55,24 @@ class CC_EXPORT SingleThreadProxy : public Proxy, virtual void AsValueInto(base::debug::TracedValue* state) const OVERRIDE; virtual bool CommitPendingForTesting() OVERRIDE; + // SchedulerClient implementation + virtual void SetNeedsBeginFrame(bool enable) OVERRIDE; + virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE; + virtual void ScheduledActionSendBeginMainFrame() OVERRIDE; + virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE; + virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE; + virtual void ScheduledActionCommit() OVERRIDE; + virtual void ScheduledActionAnimate() OVERRIDE; + virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE; + virtual void ScheduledActionActivateSyncTree() OVERRIDE; + virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE; + virtual void ScheduledActionManageTiles() OVERRIDE; + virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) OVERRIDE; + virtual base::TimeDelta DrawDurationEstimate() OVERRIDE; + virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE; + virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE; + virtual void DidBeginImplFrameDeadline() OVERRIDE; + // LayerTreeHostImplClient implementation virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE; virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE; @@ -61,7 +82,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE {} virtual void DidSwapBuffersOnImplThread() OVERRIDE; virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE; - virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {} + virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE; virtual void NotifyReadyToActivate() OVERRIDE; virtual void SetNeedsRedrawOnImplThread() OVERRIDE; @@ -82,7 +103,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, const base::Closure& start_fade, base::TimeDelta delay) OVERRIDE {} virtual void DidActivateSyncTree() OVERRIDE {} - virtual void DidManageTiles() OVERRIDE {} + virtual void DidManageTiles() OVERRIDE; virtual void SetDebugState(const LayerTreeDebugState& debug_state) OVERRIDE {} // Attempts to create the context and renderer synchronously. Calls @@ -98,10 +119,13 @@ class CC_EXPORT SingleThreadProxy : public Proxy, LayerTreeHostSingleThreadClient* client, scoped_refptr<base::SingleThreadTaskRunner> main_task_runner); - void DoCommit(scoped_ptr<ResourceUpdateQueue> queue); - bool DoComposite(base::TimeTicks frame_begin_time, - LayerTreeHostImpl::FrameData* frame); - void DidSwapFrame(); + void BeginMainFrame(); + void BeginMainFrameAbortedOnImplThread(); + void DoCommit(base::TimeTicks frame_begin_time); + DrawResult DoComposite(base::TimeTicks frame_begin_time, + LayerTreeHostImpl::FrameData* frame); + void DoSwap(); + void DidCommitAndDrawFrame(); bool ShouldComposite() const; void UpdateBackgroundAnimateTicking(); @@ -115,9 +139,18 @@ class CC_EXPORT SingleThreadProxy : public Proxy, scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl_; RendererCapabilities renderer_capabilities_for_main_thread_; + // Accessed from both threads. + scoped_ptr<Scheduler> scheduler_on_impl_thread_; + ProxyTimingHistory timing_history_; + bool next_frame_is_newly_committed_frame_; bool inside_draw_; + bool defer_commits_; + bool commit_was_deferred_; + bool commit_requested_; + + base::WeakPtrFactory<SingleThreadProxy> weak_factory_; DISALLOW_COPY_AND_ASSIGN(SingleThreadProxy); }; diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc index a379d0e..d5301ee 100644 --- a/cc/trees/thread_proxy.cc +++ b/cc/trees/thread_proxy.cc @@ -25,6 +25,7 @@ #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" #include "ui/gfx/frame_time.h" @@ -37,19 +38,6 @@ const double kSmoothnessTakesPriorityExpirationDelay = 0.25; unsigned int nextBeginFrameId = 0; -class SwapPromiseChecker { - public: - explicit SwapPromiseChecker(LayerTreeHost* layer_tree_host) - : layer_tree_host_(layer_tree_host) {} - - ~SwapPromiseChecker() { - layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_FAILS); - } - - private: - LayerTreeHost* layer_tree_host_; -}; - } // namespace struct ThreadProxy::CommitPendingRequest { @@ -458,9 +446,10 @@ void ThreadProxy::SetNextCommitWaitsForActivation() { void ThreadProxy::SetDeferCommits(bool defer_commits) { DCHECK(IsMainThread()); - DCHECK_NE(main().defer_commits, defer_commits); - main().defer_commits = defer_commits; + 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 @@ -740,9 +729,9 @@ void ThreadProxy::BeginMainFrame( } // If the commit finishes, LayerTreeHost will transfer its swap promises to - // LayerTreeImpl. The destructor of SwapPromiseChecker checks LayerTressHost's - // swap promises. - SwapPromiseChecker swap_promise_checker(layer_tree_host()); + // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the + // remaining swap promises. + ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host()); main().commit_requested = false; main().commit_request_sent_to_impl_thread = false; diff --git a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc index 4e9c4ae..7fb4ec8 100644 --- a/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc +++ b/chrome/browser/ui/views/menu_view_drag_and_drop_test.cc @@ -17,8 +17,9 @@ namespace { // Borrowed from chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc, // since these are also disabled on Linux for drag and drop. -// TODO(erg): Fix DND tests on linux_aura. crbug.com/163931 -#if defined(OS_LINUX) && defined(USE_AURA) +// TODO(erg): Fix DND tests on linux_aura. http://crbug.com/163931 +// TODO(enne): Windows version has flaky timeouts. http://crbug.com/401226 +#if defined(USE_AURA) #define MAYBE(x) DISABLED_##x #else #define MAYBE(x) x diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 3ca74a2..13b0735 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -314,7 +314,6 @@ void CompositorImpl::Composite(CompositingTrigger trigger) { // animation updates that will already be reflected in the current frame // we are about to draw. ignore_schedule_composite_ = true; - client_->Layout(); const base::TimeTicks frame_time = gfx::FrameTime::Now(); if (needs_animate_) { @@ -426,7 +425,6 @@ void CompositorImpl::SetVisible(bool visible) { } else if (!host_) { DCHECK(!WillComposite()); needs_composite_ = false; - needs_animate_ = false; pending_swapbuffers_ = 0; cc::LayerTreeSettings settings; settings.refresh_rate = 60.0; @@ -441,6 +439,8 @@ void CompositorImpl::SetVisible(bool visible) { command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking)); settings.initial_debug_state.show_fps_counter = command_line->HasSwitch(cc::switches::kUIShowFPSCounter); + // TODO(enne): Update this this compositor to use the scheduler. + settings.single_thread_proxy_scheduler = false; host_ = cc::LayerTreeHost::CreateSingleThreaded( this, @@ -523,10 +523,9 @@ CreateGpuProcessViewContext( } void CompositorImpl::Layout() { - // TODO: If we get this callback from the SingleThreadProxy, we need - // to stop calling it ourselves in CompositorImpl::Composite(). - NOTREACHED(); + ignore_schedule_composite_ = true; client_->Layout(); + ignore_schedule_composite_ = false; } scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( @@ -575,7 +574,6 @@ void CompositorImpl::ScheduleComposite() { } void CompositorImpl::ScheduleAnimation() { - DCHECK(!needs_animate_ || needs_composite_); DCHECK(!needs_composite_ || WillComposite()); needs_animate_ = true; @@ -605,6 +603,7 @@ void CompositorImpl::DidAbortSwapBuffers() { // This really gets called only once from // SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() when the // context was lost. + ScheduleComposite(); client_->OnSwapBuffersCompleted(0); } diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index a9cf52f..1144516 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -246,6 +246,10 @@ const char kDisableSetuidSandbox[] = "disable-setuid-sandbox"; // Disable shared workers. const char kDisableSharedWorkers[] = "disable-shared-workers"; +// For tests, disable single thread scheduler and only manually composite. +const char kDisableSingleThreadProxyScheduler[] = + "disable-single-thread-proxy-scheduler"; + // Disables site-specific tailoring to compatibility issues in WebKit. const char kDisableSiteSpecificQuirks[] = "disable-site-specific-quirks"; diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 8a19213..908e544 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -79,6 +79,7 @@ CONTENT_EXPORT extern const char kDisableSeccompFilterSandbox[]; extern const char kDisableSessionStorage[]; CONTENT_EXPORT extern const char kDisableSetuidSandbox[]; CONTENT_EXPORT extern const char kDisableSharedWorkers[]; +CONTENT_EXPORT extern const char kDisableSingleThreadProxyScheduler[]; extern const char kDisableSiteSpecificQuirks[]; CONTENT_EXPORT extern const char kDisableSmoothScrolling[]; CONTENT_EXPORT extern const char kDisableSoftwareRasterizer[]; diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 64e0982..baf1ac1 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc @@ -277,6 +277,8 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create( cmd->HasSwitch(cc::switches::kEnablePinchVirtualViewport); settings.allow_antialiasing &= !cmd->HasSwitch(cc::switches::kDisableCompositedAntialiasing); + settings.single_thread_proxy_scheduler = + !cmd->HasSwitch(switches::kDisableSingleThreadProxyScheduler); // These flags should be mirrored by UI versions in ui/compositor/. settings.initial_debug_state.show_debug_borders = @@ -409,7 +411,6 @@ scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create( RenderWidgetCompositor::RenderWidgetCompositor(RenderWidget* widget, bool threaded) : threaded_(threaded), - suppress_schedule_composite_(false), widget_(widget) { } @@ -420,27 +421,10 @@ RenderWidgetCompositor::GetInputHandler() { return layer_tree_host_->GetInputHandler(); } -void RenderWidgetCompositor::SetSuppressScheduleComposite(bool suppress) { - if (suppress_schedule_composite_ == suppress) - return; - - if (suppress) - TRACE_EVENT_ASYNC_BEGIN0("gpu", - "RenderWidgetCompositor::SetSuppressScheduleComposite", this); - else - TRACE_EVENT_ASYNC_END0("gpu", - "RenderWidgetCompositor::SetSuppressScheduleComposite", this); - suppress_schedule_composite_ = suppress; -} - bool RenderWidgetCompositor::BeginMainFrameRequested() const { return layer_tree_host_->BeginMainFrameRequested(); } -void RenderWidgetCompositor::UpdateAnimations(base::TimeTicks time) { - layer_tree_host_->UpdateClientAnimations(time); -} - void RenderWidgetCompositor::SetNeedsDisplayOnAllLayers() { layer_tree_host_->SetNeedsDisplayOnAllLayers(); } @@ -549,7 +533,10 @@ void RenderWidgetCompositor::Initialize(cc::LayerTreeSettings settings) { } void RenderWidgetCompositor::setSurfaceReady() { - layer_tree_host_->SetLayerTreeHostClientReady(); + // In tests without a RenderThreadImpl, don't set ready as this kicks + // off creating output surfaces that the test can't create. + if (RenderThreadImpl::current()) + layer_tree_host_->SetLayerTreeHostClientReady(); } void RenderWidgetCompositor::setRootLayer(const blink::WebLayer& layer) { @@ -702,9 +689,9 @@ void RenderWidgetCompositor::compositeAndReadbackAsync( cc::CopyOutputRequest::CreateBitmapRequest( base::Bind(&CompositeAndReadbackAsyncCallback, callback)); layer_tree_host_->root_layer()->RequestCopyOfOutput(request.Pass()); - if (!threaded_) { - widget_->webwidget()->animate(0.0); - widget_->webwidget()->layout(); + + if (!threaded_ && + !layer_tree_host_->settings().single_thread_proxy_scheduler) { layer_tree_host_->Composite(gfx::FrameTime::Now()); } } @@ -800,11 +787,6 @@ void RenderWidgetCompositor::DidCompleteSwapBuffers() { widget_->OnSwapBuffersComplete(); } -void RenderWidgetCompositor::ScheduleComposite() { - if (!suppress_schedule_composite_) - widget_->scheduleComposite(); -} - void RenderWidgetCompositor::ScheduleAnimation() { widget_->scheduleAnimation(); } diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h index e0541ec..79a03b4 100644 --- a/content/renderer/gpu/render_widget_compositor.h +++ b/content/renderer/gpu/render_widget_compositor.h @@ -44,9 +44,7 @@ class RenderWidgetCompositor : public blink::WebLayerTreeView, virtual ~RenderWidgetCompositor(); const base::WeakPtr<cc::InputHandler>& GetInputHandler(); - void SetSuppressScheduleComposite(bool suppress); bool BeginMainFrameRequested() const; - void UpdateAnimations(base::TimeTicks time); void SetNeedsDisplayOnAllLayers(); void SetRasterizeOnlyVisibleContent(); void UpdateTopControlsState(cc::TopControlsState constraints, @@ -143,7 +141,6 @@ class RenderWidgetCompositor : public blink::WebLayerTreeView, virtual void RateLimitSharedMainThreadContext() OVERRIDE; // cc::LayerTreeHostSingleThreadClient implementation. - virtual void ScheduleComposite() OVERRIDE; virtual void ScheduleAnimation() OVERRIDE; virtual void DidPostSwapBuffers() OVERRIDE; virtual void DidAbortSwapBuffers() OVERRIDE; @@ -154,7 +151,6 @@ class RenderWidgetCompositor : public blink::WebLayerTreeView, void Initialize(cc::LayerTreeSettings settings); bool threaded_; - bool suppress_schedule_composite_; RenderWidget* widget_; scoped_ptr<cc::LayerTreeHost> layer_tree_host_; }; diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 10d87e1..7e7fb2d 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc @@ -393,6 +393,7 @@ RenderWidget::RenderWidget(blink::WebPopupType popup_type, handling_event_type_(WebInputEvent::Undefined), ignore_ack_for_mouse_move_from_debugger_(false), closing_(false), + host_closing_(false), is_swapped_out_(swapped_out), input_method_is_active_(false), text_input_type_(ui::TEXT_INPUT_TYPE_NONE), @@ -1201,6 +1202,8 @@ void RenderWidget::AutoResizeCompositor() { } void RenderWidget::initializeLayerTreeView() { + DCHECK(!host_closing_); + compositor_ = RenderWidgetCompositor::Create(this, IsThreadedCompositingEnabled()); compositor_->setViewportSize(size_, physical_backing_size_); @@ -1208,20 +1211,20 @@ void RenderWidget::initializeLayerTreeView() { StartCompositor(); } -blink::WebLayerTreeView* RenderWidget::layerTreeView() { - return compositor_.get(); +void RenderWidget::DestroyLayerTreeView() { + // Always send this notification to prevent new layer tree views from + // being created, even if one hasn't been created yet. + webwidget_->willCloseLayerTreeView(); + compositor_.reset(); } -void RenderWidget::suppressCompositorScheduling(bool enable) { - if (compositor_) - compositor_->SetSuppressScheduleComposite(enable); +blink::WebLayerTreeView* RenderWidget::layerTreeView() { + return compositor_.get(); } void RenderWidget::willBeginCompositorFrame() { TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame"); - DCHECK(RenderThreadImpl::current()->compositor_message_loop_proxy().get()); - // The following two can result in further layout and possibly // enable GPU acceleration so they need to be called before any painting // is done. @@ -1378,6 +1381,12 @@ void RenderWidget::didBlur() { } void RenderWidget::DoDeferredClose() { + // No more compositing is possible. This prevents shutdown races between + // previously posted CreateOutputSurface tasks and the host being unable to + // create them because the close message was handled. + DestroyLayerTreeView(); + // Also prevent new compositors from being created. + host_closing_ = true; Send(new ViewHostMsg_Close(routing_id_)); } @@ -1418,8 +1427,7 @@ void RenderWidget::QueueSyntheticGesture( void RenderWidget::Close() { screen_metrics_emulator_.reset(); if (webwidget_) { - webwidget_->willCloseLayerTreeView(); - compositor_.reset(); + DestroyLayerTreeView(); webwidget_->close(); webwidget_ = NULL; } diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index bd97588..22612a5 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h @@ -142,7 +142,6 @@ class CONTENT_EXPORT RenderWidget virtual bool Send(IPC::Message* msg) OVERRIDE; // blink::WebWidgetClient - virtual void suppressCompositorScheduling(bool enable); virtual void willBeginCompositorFrame(); virtual void didAutoResize(const blink::WebSize& new_size); virtual void initializeLayerTreeView(); @@ -173,6 +172,9 @@ class CONTENT_EXPORT RenderWidget // Begins the compositor's scheduler to start producing frames. void StartCompositor(); + // Stop compositing. + void DestroyLayerTreeView(); + // Called when a plugin is moved. These events are queued up and sent with // the next paint or scroll message to the host. void SchedulePluginMove(const WebPluginGeometry& move); @@ -624,6 +626,9 @@ class CONTENT_EXPORT RenderWidget // be sent, except for a Close. bool closing_; + // True if it is known that the host is in the process of being shut down. + bool host_closing_; + // Whether this RenderWidget is currently swapped out, such that the view is // being rendered by another process. If all RenderWidgets in a process are // swapped out, the process can exit. diff --git a/content/shell/renderer/test_runner/web_test_proxy.cc b/content/shell/renderer/test_runner/web_test_proxy.cc index 7e36976..18086de 100644 --- a/content/shell/renderer/test_runner/web_test_proxy.cc +++ b/content/shell/renderer/test_runner/web_test_proxy.cc @@ -7,9 +7,11 @@ #include <cctype> #include "base/callback_helpers.h" +#include "base/command_line.h" #include "base/debug/trace_event.h" #include "base/logging.h" #include "base/strings/stringprintf.h" +#include "content/public/common/content_switches.h" #include "content/shell/renderer/test_runner/TestPlugin.h" #include "content/shell/renderer/test_runner/WebTestDelegate.h" #include "content/shell/renderer/test_runner/WebTestInterfaces.h" @@ -313,6 +315,10 @@ WebTestProxyBase::WebTestProxyBase() web_widget_(NULL), spellcheck_(new SpellCheckClient(this)), chooser_count_(0) { + // TODO(enne): using the scheduler introduces additional composite steps + // that create flakiness. This should go away eventually. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kDisableSingleThreadProxyScheduler); Reset(); } diff --git a/content/test/web_layer_tree_view_impl_for_testing.h b/content/test/web_layer_tree_view_impl_for_testing.h index 13d6ee4..730c210 100644 --- a/content/test/web_layer_tree_view_impl_for_testing.h +++ b/content/test/web_layer_tree_view_impl_for_testing.h @@ -80,8 +80,6 @@ class WebLayerTreeViewImplForTesting virtual void DidCompleteSwapBuffers() OVERRIDE {} // cc::LayerTreeHostSingleThreadClient implementation. - virtual void ScheduleComposite() OVERRIDE {} - virtual void ScheduleAnimation() OVERRIDE {} virtual void DidPostSwapBuffers() OVERRIDE {} virtual void DidAbortSwapBuffers() OVERRIDE {} diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 14b5366..6be8530 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc @@ -61,14 +61,6 @@ void CompositorLock::CancelLock() { compositor_ = NULL; } -} // namespace ui - -namespace { - -} // namespace - -namespace ui { - Compositor::Compositor(gfx::AcceleratedWidget widget, ui::ContextFactory* context_factory, scoped_refptr<base::SingleThreadTaskRunner> task_runner) @@ -79,16 +71,9 @@ Compositor::Compositor(gfx::AcceleratedWidget widget, task_runner_(task_runner), vsync_manager_(new CompositorVSyncManager()), device_scale_factor_(0.0f), - last_started_frame_(0), - last_ended_frame_(0), disable_schedule_composite_(false), compositor_lock_(NULL), - defer_draw_scheduling_(false), - waiting_on_compositing_end_(false), - draw_on_compositing_end_(false), - swap_state_(SWAP_NONE), - layer_animator_collection_(this), - schedule_draw_factory_(this) { + layer_animator_collection_(this) { root_web_layer_ = cc::Layer::Create(); CommandLine* command_line = CommandLine::ForCurrentProcess(); @@ -177,14 +162,7 @@ Compositor::~Compositor() { } void Compositor::ScheduleDraw() { - if (compositor_thread_loop_) { - host_->SetNeedsCommit(); - } else if (!defer_draw_scheduling_) { - defer_draw_scheduling_ = true; - task_runner_->PostTask( - FROM_HERE, - base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr())); - } + host_->SetNeedsCommit(); } void Compositor::SetRootLayer(Layer* root_layer) { @@ -205,42 +183,19 @@ void Compositor::SetHostHasTransparentBackground( host_->set_has_transparent_background(host_has_transparent_background); } -void Compositor::Draw() { - DCHECK(!compositor_thread_loop_); - - defer_draw_scheduling_ = false; - if (waiting_on_compositing_end_) { - draw_on_compositing_end_ = true; - return; - } - if (!root_layer_) - return; - - TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1); - - DCHECK_NE(swap_state_, SWAP_POSTED); - swap_state_ = SWAP_NONE; - - waiting_on_compositing_end_ = true; - last_started_frame_++; - if (!IsLocked()) { - // TODO(nduca): Temporary while compositor calls - // compositeImmediately() directly. - base::TimeTicks now = gfx::FrameTime::Now(); - Animate(now); - Layout(); - host_->Composite(now); - } - if (swap_state_ == SWAP_NONE) - NotifyEnd(); -} - void Compositor::ScheduleFullRedraw() { + // TODO(enne): Some callers (mac) call this function expecting that it + // will also commit. This should probably just redraw the screen + // from damage and not commit. ScheduleDraw/ScheduleRedraw need + // better names. host_->SetNeedsRedraw(); + host_->SetNeedsCommit(); } void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) { + // TODO(enne): Make this not commit. See ScheduleFullRedraw. host_->SetNeedsRedrawRect(damage_rect); + host_->SetNeedsCommit(); } void Compositor::FinishAllRendering() { @@ -347,45 +302,30 @@ void Compositor::DidCommit() { } void Compositor::DidCommitAndDrawFrame() { - base::TimeTicks start_time = gfx::FrameTime::Now(); - FOR_EACH_OBSERVER(CompositorObserver, - observer_list_, - OnCompositingStarted(this, start_time)); } void Compositor::DidCompleteSwapBuffers() { + // DidPostSwapBuffers is a SingleThreadProxy-only feature. Synthetically + // generate OnCompositingStarted messages for the threaded case so that + // OnCompositingStarted/OnCompositingEnded messages match. if (compositor_thread_loop_) { - NotifyEnd(); - } else { - DCHECK_EQ(swap_state_, SWAP_POSTED); - NotifyEnd(); - swap_state_ = SWAP_COMPLETED; + base::TimeTicks start_time = gfx::FrameTime::Now(); + FOR_EACH_OBSERVER(CompositorObserver, + observer_list_, + OnCompositingStarted(this, start_time)); } -} - -void Compositor::ScheduleComposite() { - if (!disable_schedule_composite_) - ScheduleDraw(); -} - -void Compositor::ScheduleAnimation() { - ScheduleComposite(); + FOR_EACH_OBSERVER( + CompositorObserver, observer_list_, OnCompositingEnded(this)); } void Compositor::DidPostSwapBuffers() { - DCHECK(!compositor_thread_loop_); - DCHECK_EQ(swap_state_, SWAP_NONE); - swap_state_ = SWAP_POSTED; + base::TimeTicks start_time = gfx::FrameTime::Now(); + FOR_EACH_OBSERVER(CompositorObserver, + observer_list_, + OnCompositingStarted(this, start_time)); } void Compositor::DidAbortSwapBuffers() { - if (!compositor_thread_loop_) { - if (swap_state_ == SWAP_POSTED) { - NotifyEnd(); - swap_state_ = SWAP_COMPLETED; - } - } - FOR_EACH_OBSERVER(CompositorObserver, observer_list_, OnCompositingAborted(this)); @@ -403,8 +343,7 @@ void Compositor::SetLayerTreeDebugState( scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { if (!compositor_lock_) { compositor_lock_ = new CompositorLock(this); - if (compositor_thread_loop_) - host_->SetDeferCommits(true); + host_->SetDeferCommits(true); FOR_EACH_OBSERVER(CompositorObserver, observer_list_, OnCompositingLockStateChanged(this)); @@ -415,8 +354,7 @@ scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { void Compositor::UnlockCompositor() { DCHECK(compositor_lock_); compositor_lock_ = NULL; - if (compositor_thread_loop_) - host_->SetDeferCommits(false); + host_->SetDeferCommits(false); FOR_EACH_OBSERVER(CompositorObserver, observer_list_, OnCompositingLockStateChanged(this)); @@ -427,21 +365,4 @@ void Compositor::CancelCompositorLock() { compositor_lock_->CancelLock(); } -void Compositor::NotifyEnd() { - last_ended_frame_++; - TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_); - waiting_on_compositing_end_ = false; - if (draw_on_compositing_end_) { - draw_on_compositing_end_ = false; - - // Call ScheduleDraw() instead of Draw() in order to allow other - // CompositorObservers to be notified before starting another - // draw cycle. - ScheduleDraw(); - } - FOR_EACH_OBSERVER(CompositorObserver, - observer_list_, - OnCompositingEnded(this)); -} - } // namespace ui diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 0e4ac8a..b2d2779 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h @@ -24,8 +24,6 @@ #include "ui/gfx/size.h" #include "ui/gfx/vector2d.h" -class SkBitmap; - namespace base { class MessageLoopProxy; class RunLoop; @@ -159,9 +157,6 @@ class COMPOSITOR_EXPORT Compositor // compositing layers on. float device_scale_factor() const { return device_scale_factor_; } - // Draws the scene created by the layer tree and any visual effects. - void Draw(); - // Where possible, draws are scissored to a damage region calculated from // changes to layer properties. This bypasses that and indicates that // the whole frame needs to be drawn. @@ -234,14 +229,9 @@ class COMPOSITOR_EXPORT Compositor virtual void DidCompleteSwapBuffers() OVERRIDE; // cc::LayerTreeHostSingleThreadClient implementation. - virtual void ScheduleComposite() OVERRIDE; - virtual void ScheduleAnimation() OVERRIDE; virtual void DidPostSwapBuffers() OVERRIDE; virtual void DidAbortSwapBuffers() OVERRIDE; - int last_started_frame() { return last_started_frame_; } - int last_ended_frame() { return last_ended_frame_; } - bool IsLocked() { return compositor_lock_ != NULL; } const cc::LayerTreeDebugState& GetLayerTreeDebugState() const; @@ -261,9 +251,6 @@ class COMPOSITOR_EXPORT Compositor // Called to release any pending CompositorLock void CancelCompositorLock(); - // Notifies the compositor that compositing is complete. - void NotifyEnd(); - gfx::Size size_; ui::ContextFactory* context_factory_; @@ -294,19 +281,8 @@ class COMPOSITOR_EXPORT Compositor CompositorLock* compositor_lock_; - // Prevent more than one draw from being scheduled. - bool defer_draw_scheduling_; - - // Used to prevent Draw()s while a composite is in progress. - bool waiting_on_compositing_end_; - bool draw_on_compositing_end_; - enum SwapState { SWAP_NONE, SWAP_POSTED, SWAP_COMPLETED }; - SwapState swap_state_; - LayerAnimatorCollection layer_animator_collection_; - base::WeakPtrFactory<Compositor> schedule_draw_factory_; - DISALLOW_COPY_AND_ASSIGN(Compositor); }; diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index ac1a47b..b5c473c 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc @@ -95,8 +95,8 @@ class LayerWithRealCompositorTest : public testing::Test { InitializeContextFactoryForTests(enable_pixel_output); const gfx::Rect host_bounds(10, 10, 500, 500); - compositor_host_.reset(TestCompositorHost::Create( - host_bounds, context_factory)); + compositor_host_.reset( + TestCompositorHost::Create(host_bounds, context_factory)); compositor_host_->Show(); } @@ -126,7 +126,7 @@ class LayerWithRealCompositorTest : public testing::Test { void DrawTree(Layer* root) { GetCompositor()->SetRootLayer(root); GetCompositor()->ScheduleDraw(); - WaitForDraw(); + WaitForSwap(); } bool ReadPixels(SkBitmap* bitmap) { @@ -142,11 +142,13 @@ class LayerWithRealCompositorTest : public testing::Test { GetCompositor()->root_layer()->RequestCopyOfOutput(request.Pass()); - // Wait for copy response. This needs to wait as the compositor could - // be in the middle of a draw right now, and the commit with the - // copy output request may not be done on the first draw. - for (int i = 0; i < 2; i++) { - GetCompositor()->ScheduleDraw(); + // Wait for copy response. The copy output request will get committed + // before the first draw, but may not be part of the first draw's frame. + // The second draw will perform the async copy request, post the callback. + // The second loop finishes before the callback is run, so a third + // loop is needed. + for (int i = 0; i < 3; i++) { + GetCompositor()->ScheduleFullRedraw(); WaitForDraw(); } @@ -161,7 +163,11 @@ class LayerWithRealCompositorTest : public testing::Test { } void WaitForDraw() { - ui::DrawWaiterForTest::Wait(GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingStarted(GetCompositor()); + } + + void WaitForSwap() { + DrawWaiterForTest::WaitForCompositingEnded(GetCompositor()); } void WaitForCommit() { @@ -450,7 +456,7 @@ class LayerWithDelegateTest : public testing::Test { } void WaitForDraw() { - DrawWaiterForTest::Wait(compositor()); + DrawWaiterForTest::WaitForCompositingStarted(compositor()); } void WaitForCommit() { @@ -945,25 +951,25 @@ TEST_F(LayerWithRealCompositorTest, CompositorObservers) { // Moving, but not resizing, a layer should alert the observers. observer.Reset(); l2->SetBounds(gfx::Rect(0, 0, 350, 350)); - WaitForDraw(); + WaitForSwap(); EXPECT_TRUE(observer.notified()); // So should resizing a layer. observer.Reset(); l2->SetBounds(gfx::Rect(0, 0, 400, 400)); - WaitForDraw(); + WaitForSwap(); EXPECT_TRUE(observer.notified()); // Opacity changes should alert the observers. observer.Reset(); l2->SetOpacity(0.5f); - WaitForDraw(); + WaitForSwap(); EXPECT_TRUE(observer.notified()); // So should setting the opacity back. observer.Reset(); l2->SetOpacity(1.0f); - WaitForDraw(); + WaitForSwap(); EXPECT_TRUE(observer.notified()); // Setting the transform of a layer should alert the observers. @@ -973,7 +979,7 @@ TEST_F(LayerWithRealCompositorTest, CompositorObservers) { transform.Rotate(90.0); transform.Translate(-200.0, -200.0); l2->SetTransform(transform); - WaitForDraw(); + WaitForSwap(); EXPECT_TRUE(observer.notified()); // A change resulting in an aborted swap buffer should alert the observer @@ -981,7 +987,7 @@ TEST_F(LayerWithRealCompositorTest, CompositorObservers) { observer.Reset(); l2->SetOpacity(0.1f); GetCompositor()->DidAbortSwapBuffers(); - WaitForDraw(); + WaitForSwap(); EXPECT_TRUE(observer.notified()); EXPECT_TRUE(observer.aborted()); @@ -990,7 +996,7 @@ TEST_F(LayerWithRealCompositorTest, CompositorObservers) { // Opacity changes should no longer alert the removed observer. observer.Reset(); l2->SetOpacity(0.5f); - WaitForDraw(); + WaitForSwap(); EXPECT_FALSE(observer.notified()); } diff --git a/ui/compositor/test/draw_waiter_for_test.cc b/ui/compositor/test/draw_waiter_for_test.cc index c471a6f..f256ecc 100644 --- a/ui/compositor/test/draw_waiter_for_test.cc +++ b/ui/compositor/test/draw_waiter_for_test.cc @@ -9,20 +9,25 @@ namespace ui { // static -void DrawWaiterForTest::Wait(Compositor* compositor) { - DrawWaiterForTest waiter; - waiter.wait_for_commit_ = false; +void DrawWaiterForTest::WaitForCompositingStarted(Compositor* compositor) { + DrawWaiterForTest waiter(WAIT_FOR_COMPOSITING_STARTED); + waiter.WaitImpl(compositor); +} + +void DrawWaiterForTest::WaitForCompositingEnded(Compositor* compositor) { + DrawWaiterForTest waiter(WAIT_FOR_COMPOSITING_ENDED); waiter.WaitImpl(compositor); } // static void DrawWaiterForTest::WaitForCommit(Compositor* compositor) { - DrawWaiterForTest waiter; - waiter.wait_for_commit_ = true; + DrawWaiterForTest waiter(WAIT_FOR_COMMIT); waiter.WaitImpl(compositor); } -DrawWaiterForTest::DrawWaiterForTest() {} +DrawWaiterForTest::DrawWaiterForTest(WaitEvent wait_event) + : wait_event_(wait_event) { +} DrawWaiterForTest::~DrawWaiterForTest() {} @@ -34,19 +39,23 @@ void DrawWaiterForTest::WaitImpl(Compositor* compositor) { } void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) { - if (wait_for_commit_) + if (wait_event_ == WAIT_FOR_COMMIT) wait_run_loop_->Quit(); } void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor, - base::TimeTicks start_time) {} + base::TimeTicks start_time) { + if (wait_event_ == WAIT_FOR_COMPOSITING_STARTED) + wait_run_loop_->Quit(); +} void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) { - if (!wait_for_commit_) + if (wait_event_ == WAIT_FOR_COMPOSITING_ENDED) wait_run_loop_->Quit(); } -void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) {} +void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) { +} void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) {} diff --git a/ui/compositor/test/draw_waiter_for_test.h b/ui/compositor/test/draw_waiter_for_test.h index 051c58f..e1d63ff 100644 --- a/ui/compositor/test/draw_waiter_for_test.h +++ b/ui/compositor/test/draw_waiter_for_test.h @@ -20,13 +20,22 @@ class DrawWaiterForTest : public CompositorObserver { // Waits for a draw to be issued by the compositor. If the test times out // here, there may be a logic error in the compositor code causing it // not to draw. - static void Wait(Compositor* compositor); + static void WaitForCompositingStarted(Compositor* compositor); + + // Waits for a swap to be completed from the compositor. + static void WaitForCompositingEnded(Compositor* compositor); // Waits for a commit instead of a draw. static void WaitForCommit(Compositor* compositor); private: - DrawWaiterForTest(); + enum WaitEvent { + WAIT_FOR_COMMIT, + WAIT_FOR_COMPOSITING_STARTED, + WAIT_FOR_COMPOSITING_ENDED, + }; + + DrawWaiterForTest(WaitEvent wait_event); virtual ~DrawWaiterForTest(); void WaitImpl(Compositor* compositor); @@ -41,7 +50,7 @@ class DrawWaiterForTest : public CompositorObserver { scoped_ptr<base::RunLoop> wait_run_loop_; - bool wait_for_commit_; + WaitEvent wait_event_; DISALLOW_COPY_AND_ASSIGN(DrawWaiterForTest); }; diff --git a/ui/compositor/test/test_compositor_host_mac.mm b/ui/compositor/test/test_compositor_host_mac.mm index 8d533d0..7201fde 100644 --- a/ui/compositor/test/test_compositor_host_mac.mm +++ b/ui/compositor/test/test_compositor_host_mac.mm @@ -40,7 +40,7 @@ - (void)drawRect:(NSRect)rect { DCHECK(compositor_) << "Drawing with no compositor set."; - compositor_->Draw(); + compositor_->ScheduleFullRedraw(); } @end diff --git a/ui/compositor/test/test_compositor_host_ozone.cc b/ui/compositor/test/test_compositor_host_ozone.cc index 1c4b0cc..903c3b6 100644 --- a/ui/compositor/test/test_compositor_host_ozone.cc +++ b/ui/compositor/test/test_compositor_host_ozone.cc @@ -27,8 +27,6 @@ class TestCompositorHostOzone : public TestCompositorHost { virtual void Show() OVERRIDE; virtual ui::Compositor* GetCompositor() OVERRIDE; - void Draw(); - gfx::Rect bounds_; ui::ContextFactory* context_factory_; @@ -64,11 +62,6 @@ ui::Compositor* TestCompositorHostOzone::GetCompositor() { return compositor_.get(); } -void TestCompositorHostOzone::Draw() { - if (compositor_.get()) - compositor_->Draw(); -} - // static TestCompositorHost* TestCompositorHost::Create( const gfx::Rect& bounds, diff --git a/ui/compositor/test/test_compositor_host_win.cc b/ui/compositor/test/test_compositor_host_win.cc index 9c732f6..80db4ae 100644 --- a/ui/compositor/test/test_compositor_host_win.cc +++ b/ui/compositor/test/test_compositor_host_win.cc @@ -42,7 +42,7 @@ class TestCompositorHostWin : public TestCompositorHost, CR_END_MSG_MAP() void OnPaint(HDC dc) { - compositor_->Draw(); + compositor_->ScheduleFullRedraw(); ValidateRect(hwnd(), NULL); } diff --git a/ui/compositor/test/test_compositor_host_x11.cc b/ui/compositor/test/test_compositor_host_x11.cc index 9b2d265..1c3f674 100644 --- a/ui/compositor/test/test_compositor_host_x11.cc +++ b/ui/compositor/test/test_compositor_host_x11.cc @@ -30,8 +30,6 @@ class TestCompositorHostX11 : public TestCompositorHost { virtual void Show() OVERRIDE; virtual ui::Compositor* GetCompositor() OVERRIDE; - void Draw(); - gfx::Rect bounds_; ui::ContextFactory* context_factory_; @@ -85,11 +83,6 @@ ui::Compositor* TestCompositorHostX11::GetCompositor() { return compositor_.get(); } -void TestCompositorHostX11::Draw() { - if (compositor_.get()) - compositor_->Draw(); -} - // static TestCompositorHost* TestCompositorHost::Create( const gfx::Rect& bounds, diff --git a/ui/snapshot/snapshot_aura_unittest.cc b/ui/snapshot/snapshot_aura_unittest.cc index 5fe05a8..018394b 100644 --- a/ui/snapshot/snapshot_aura_unittest.cc +++ b/ui/snapshot/snapshot_aura_unittest.cc @@ -115,7 +115,8 @@ class SnapshotAuraTest : public testing::Test { void WaitForDraw() { helper_->host()->compositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(helper_->host()->compositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + helper_->host()->compositor()); } void SetupTestWindow(const gfx::Rect& window_bounds) { diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index c4e6dcb..87164b0 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc @@ -3087,20 +3087,23 @@ TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) { widget()->SetContentsView(content_view); content_view->SetPaintToLayer(true); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); GetRootLayer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); content_view->set_painted(false); // content_view no longer has a dirty rect. Paint from the root and make sure // PaintTrackingView isn't painted. GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_FALSE(content_view->painted()); // Make content_view have a dirty rect, paint the layers and make sure // PaintTrackingView is painted. content_view->layer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_TRUE(content_view->painted()); } @@ -3340,13 +3343,15 @@ TEST_F(ViewLayerTest, BoundsTreePaintUpdatesCullSet) { // Schedule a full-view paint to get everyone's rectangles updated. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Now we have test_view - v1 - v2. Damage to only test_view should only // return root_view and test_view. test_view->SchedulePaintInRect(gfx::Rect(0, 0, 1, 1)); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_EQ(2U, test_view->last_cull_set_.size()); EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); @@ -3354,7 +3359,8 @@ TEST_F(ViewLayerTest, BoundsTreePaintUpdatesCullSet) { // Damage to v1 only should only return root_view, test_view, and v1. test_view->SchedulePaintInRect(gfx::Rect(11, 16, 1, 1)); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_EQ(3U, test_view->last_cull_set_.size()); EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); @@ -3364,7 +3370,8 @@ TEST_F(ViewLayerTest, BoundsTreePaintUpdatesCullSet) { // on call to TestView::Paint(), along with the widget root view. test_view->SchedulePaintInRect(gfx::Rect(31, 49, 1, 1)); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_EQ(4U, test_view->last_cull_set_.size()); EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); @@ -3391,13 +3398,15 @@ TEST_F(ViewLayerTest, BoundsTreeWithRTL) { // Schedule a full-view paint to get everyone's rectangles updated. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Damage to the right side of the parent view should touch both child views. gfx::Rect rtl_damage(test_view->bounds().width() - 16, 18, 1, 1); test_view->SchedulePaintInRect(rtl_damage); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_EQ(4U, test_view->last_cull_set_.size()); EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); @@ -3409,7 +3418,8 @@ TEST_F(ViewLayerTest, BoundsTreeWithRTL) { gfx::Rect ltr_damage(16, 18, 1, 1); test_view->SchedulePaintInRect(ltr_damage); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_EQ(2U, test_view->last_cull_set_.size()); EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); @@ -3433,18 +3443,21 @@ TEST_F(ViewLayerTest, BoundsTreeSetBoundsChangesCullSet) { // Schedule a full-view paint to get everyone's rectangles updated. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Move v1 to a new origin out of the way of our next query. v1->SetBoundsRect(gfx::Rect(50, 60, 100, 101)); // The move will force a repaint. GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Schedule a paint with damage rect where v1 used to be. test_view->SchedulePaintInRect(gfx::Rect(5, 6, 10, 11)); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Should only have picked up root_view and test_view. EXPECT_EQ(2U, test_view->last_cull_set_.size()); @@ -3467,7 +3480,8 @@ TEST_F(ViewLayerTest, BoundsTreeLayerChangeMakesNewTree) { // Schedule a full-view paint to get everyone's rectangles updated. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Set v1 to paint to its own layer, it should remove itself from the // test_view heiarchy and no longer intersect with damage rects in that cull @@ -3477,7 +3491,8 @@ TEST_F(ViewLayerTest, BoundsTreeLayerChangeMakesNewTree) { // Schedule another full-view paint. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // v1 and v2 should no longer be present in the test_view cull_set. EXPECT_EQ(2U, test_view->last_cull_set_.size()); EXPECT_EQ(0U, test_view->last_cull_set_.count(v1)); @@ -3488,7 +3503,8 @@ TEST_F(ViewLayerTest, BoundsTreeLayerChangeMakesNewTree) { // Schedule another full-view paint. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // We should be back to the full cull set including v1 and v2. EXPECT_EQ(4U, test_view->last_cull_set_.size()); EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); @@ -3512,7 +3528,8 @@ TEST_F(ViewLayerTest, BoundsTreeRemoveChildRemovesBounds) { // Schedule a full-view paint to get everyone's rectangles updated. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Now remove v1 from the root view. test_view->RemoveChildView(v1); @@ -3520,7 +3537,8 @@ TEST_F(ViewLayerTest, BoundsTreeRemoveChildRemovesBounds) { // Schedule another full-view paint. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // v1 and v2 should no longer be present in the test_view cull_set. EXPECT_EQ(2U, test_view->last_cull_set_.size()); EXPECT_EQ(0U, test_view->last_cull_set_.count(v1)); @@ -3551,7 +3569,8 @@ TEST_F(ViewLayerTest, BoundsTreeMoveViewMovesBounds) { // Schedule a full-view paint and ensure all views are present in the cull. test_view->SchedulePaintInRect(test_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); EXPECT_EQ(5U, test_view->last_cull_set_.size()); EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); @@ -3574,7 +3593,8 @@ TEST_F(ViewLayerTest, BoundsTreeMoveViewMovesBounds) { test_view->SchedulePaintInRect(test_view->bounds()); widget_view->SchedulePaintInRect(widget_view->bounds()); GetRootLayer()->GetCompositor()->ScheduleDraw(); - ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); + ui::DrawWaiterForTest::WaitForCompositingEnded( + GetRootLayer()->GetCompositor()); // Only v1 should be present in the first cull set. EXPECT_EQ(3U, test_view->last_cull_set_.size()); |