| // 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. |
| |
| #include <stdint.h> |
| |
| #include <iostream> |
| #include <set> |
| #include <vector> |
| |
| #include "base/location.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "cc/animation/animation_host.h" |
| #include "cc/layers/solid_color_layer.h" |
| #include "cc/layers/surface_layer.h" |
| #include "cc/layers/surface_layer_impl.h" |
| #include "cc/test/fake_impl_task_runner_provider.h" |
| #include "cc/test/fake_layer_tree_host.h" |
| #include "cc/test/fake_layer_tree_host_client.h" |
| #include "cc/test/fake_layer_tree_host_impl.h" |
| #include "cc/test/layer_tree_test.h" |
| #include "cc/test/test_task_graph_runner.h" |
| #include "cc/trees/layer_tree_host.h" |
| #include "components/viz/common/quads/compositor_frame.h" |
| #include "components/viz/common/surfaces/surface_info.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace cc { |
| namespace { |
| |
| using testing::_; |
| using testing::Eq; |
| using testing::ElementsAre; |
| using testing::SizeIs; |
| |
| constexpr viz::FrameSinkId kArbitraryFrameSinkId(1, 1); |
| |
| class SurfaceLayerTest : public testing::Test { |
| public: |
| SurfaceLayerTest() |
| : host_impl_(&task_runner_provider_, &task_graph_runner_) {} |
| |
| // Synchronizes |layer_tree_host_| and |host_impl_| and pushes surface ids. |
| void SynchronizeTrees() { |
| TreeSynchronizer::PushLayerProperties(layer_tree_host_.get(), |
| host_impl_.pending_tree()); |
| layer_tree_host_->PushSurfaceRangesTo(host_impl_.pending_tree()); |
| } |
| |
| protected: |
| void SetUp() override { |
| animation_host_ = AnimationHost::CreateForTesting(ThreadInstance::MAIN); |
| layer_tree_host_ = FakeLayerTreeHost::Create( |
| &fake_client_, &task_graph_runner_, animation_host_.get()); |
| layer_tree_host_->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f, |
| viz::LocalSurfaceIdAllocation()); |
| host_impl_.CreatePendingTree(); |
| } |
| |
| void TearDown() override { |
| if (layer_tree_host_) { |
| layer_tree_host_->SetRootLayer(nullptr); |
| layer_tree_host_ = nullptr; |
| } |
| } |
| |
| FakeLayerTreeHostClient fake_client_; |
| FakeImplTaskRunnerProvider task_runner_provider_; |
| TestTaskGraphRunner task_graph_runner_; |
| std::unique_ptr<AnimationHost> animation_host_; |
| std::unique_ptr<FakeLayerTreeHost> layer_tree_host_; |
| FakeLayerTreeHostImpl host_impl_; |
| }; |
| |
| // This test verifies that if UseExistingDeadline() is used on a new |
| // SurfaceLayer then the deadline will be 0 frames. |
| TEST_F(SurfaceLayerTest, UseExistingDeadlineForNewSurfaceLayer) { |
| scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(); |
| layer_tree_host_->SetRootLayer(layer); |
| viz::SurfaceId primary_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| layer->SetSurfaceId(primary_id, DeadlinePolicy::UseExistingDeadline()); |
| EXPECT_EQ(0u, layer->deadline_in_frames()); |
| } |
| |
| // This test verifies that if UseInfiniteDeadline() is used on a new |
| // SurfaceLayer then the deadline will be max number of frames. |
| TEST_F(SurfaceLayerTest, UseInfiniteDeadlineForNewSurfaceLayer) { |
| scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(); |
| layer_tree_host_->SetRootLayer(layer); |
| viz::SurfaceId primary_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| layer->SetSurfaceId(primary_id, DeadlinePolicy::UseInfiniteDeadline()); |
| EXPECT_EQ(std::numeric_limits<uint32_t>::max(), layer->deadline_in_frames()); |
| } |
| |
| // This test verifies that if an invalid primary surface ID is set then the |
| // deadline will be reset to 0 frames. |
| TEST_F(SurfaceLayerTest, ResetDeadlineOnInvalidSurfaceId) { |
| scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(); |
| layer_tree_host_->SetRootLayer(layer); |
| viz::SurfaceId primary_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| layer->SetSurfaceId(primary_id, DeadlinePolicy::UseSpecifiedDeadline(3u)); |
| EXPECT_EQ(3u, layer->deadline_in_frames()); |
| |
| // Reset the surface layer to an invalid SurfaceId. Verify that the deadline |
| // is reset. |
| layer->SetSurfaceId(viz::SurfaceId(), |
| DeadlinePolicy::UseSpecifiedDeadline(3u)); |
| EXPECT_EQ(0u, layer->deadline_in_frames()); |
| } |
| |
| // This test verifies that SurfaceLayer properties are pushed across to |
| // SurfaceLayerImpl. |
| TEST_F(SurfaceLayerTest, PushProperties) { |
| scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(); |
| layer_tree_host_->SetRootLayer(layer); |
| viz::SurfaceId primary_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| layer->SetSurfaceId(primary_id, DeadlinePolicy::UseSpecifiedDeadline(1u)); |
| layer->SetSurfaceId(primary_id, DeadlinePolicy::UseSpecifiedDeadline(2u)); |
| layer->SetSurfaceId(primary_id, DeadlinePolicy::UseExistingDeadline()); |
| layer->SetOldestAcceptableFallback(primary_id); |
| layer->SetBackgroundColor(SK_ColorBLUE); |
| layer->SetStretchContentToFillBounds(true); |
| |
| EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync()); |
| EXPECT_EQ(layer_tree_host_->SurfaceRanges().size(), 1u); |
| |
| // Verify that pending tree has no surface ids already. |
| EXPECT_FALSE(host_impl_.pending_tree()->needs_surface_ranges_sync()); |
| EXPECT_EQ(host_impl_.pending_tree()->SurfaceRanges().size(), 0u); |
| |
| std::unique_ptr<SurfaceLayerImpl> layer_impl = |
| SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer->id()); |
| SynchronizeTrees(); |
| |
| // Verify that pending tree received the surface id and also has |
| // needs_surface_ranges_sync set to true as it needs to sync with active tree. |
| EXPECT_TRUE(host_impl_.pending_tree()->needs_surface_ranges_sync()); |
| EXPECT_EQ(host_impl_.pending_tree()->SurfaceRanges().size(), 1u); |
| |
| // Verify we have reset the state on layer tree host. |
| EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync()); |
| |
| // Verify that the primary and fallback SurfaceIds are pushed through. |
| EXPECT_EQ(primary_id, layer_impl->range().end()); |
| EXPECT_EQ(primary_id, layer_impl->range().start()); |
| EXPECT_EQ(SK_ColorBLUE, layer_impl->background_color()); |
| EXPECT_TRUE(layer_impl->stretch_content_to_fill_bounds()); |
| EXPECT_EQ(2u, layer_impl->deadline_in_frames()); |
| |
| viz::SurfaceId fallback_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(2, base::UnguessableToken::Create())); |
| layer->SetOldestAcceptableFallback(fallback_id); |
| layer->SetSurfaceId(fallback_id, DeadlinePolicy::UseExistingDeadline()); |
| layer->SetBackgroundColor(SK_ColorGREEN); |
| layer->SetStretchContentToFillBounds(false); |
| |
| // Verify that fallback surface id is not recorded on the layer tree host as |
| // surface synchronization is not enabled. |
| EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync()); |
| EXPECT_EQ(layer_tree_host_->SurfaceRanges().size(), 1u); |
| |
| SynchronizeTrees(); |
| |
| EXPECT_EQ(host_impl_.pending_tree()->SurfaceRanges().size(), 1u); |
| |
| // Verify that the primary viz::SurfaceId stays the same and the new |
| // fallback viz::SurfaceId is pushed through. |
| EXPECT_EQ(fallback_id, layer_impl->range().end()); |
| EXPECT_EQ(fallback_id, layer_impl->range().start()); |
| EXPECT_EQ(SK_ColorGREEN, layer_impl->background_color()); |
| // The deadline resets back to 0 (no deadline) after the first commit. |
| EXPECT_EQ(0u, layer_impl->deadline_in_frames()); |
| EXPECT_FALSE(layer_impl->stretch_content_to_fill_bounds()); |
| } |
| |
| // This test verifies the list of surface ids is correct when there are cloned |
| // surface layers. This emulates the flow of maximize and minimize animations on |
| // Chrome OS. |
| TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) { |
| const viz::SurfaceId old_surface_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| |
| // This layer will always contain the old surface id and will be deleted when |
| // animation is done. |
| scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create(); |
| layer1->SetLayerTreeHost(layer_tree_host_.get()); |
| layer1->SetSurfaceId(old_surface_id, DeadlinePolicy::UseDefaultDeadline()); |
| layer1->SetOldestAcceptableFallback(old_surface_id); |
| |
| // This layer will eventually be switched be switched to show the new surface |
| // id and will be retained when animation is done. |
| scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create(); |
| layer2->SetLayerTreeHost(layer_tree_host_.get()); |
| layer2->SetSurfaceId(old_surface_id, DeadlinePolicy::UseDefaultDeadline()); |
| layer2->SetOldestAcceptableFallback(old_surface_id); |
| |
| std::unique_ptr<SurfaceLayerImpl> layer_impl1 = |
| SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer1->id()); |
| std::unique_ptr<SurfaceLayerImpl> layer_impl2 = |
| SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer2->id()); |
| |
| SynchronizeTrees(); |
| |
| // Verify that only |old_surface_id| is going to be referenced. |
| EXPECT_THAT(layer_tree_host_->SurfaceRanges(), |
| ElementsAre(viz::SurfaceRange(old_surface_id))); |
| EXPECT_THAT(host_impl_.pending_tree()->SurfaceRanges(), |
| ElementsAre(viz::SurfaceRange(old_surface_id))); |
| |
| const viz::SurfaceId new_surface_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(2, base::UnguessableToken::Create())); |
| |
| // Switch the new layer to use |new_surface_id|. |
| layer2->SetSurfaceId(new_surface_id, DeadlinePolicy::UseDefaultDeadline()); |
| layer2->SetOldestAcceptableFallback(new_surface_id); |
| |
| SynchronizeTrees(); |
| |
| // Verify that both surface ids are going to be referenced. |
| EXPECT_THAT(layer_tree_host_->SurfaceRanges(), |
| ElementsAre(viz::SurfaceRange(old_surface_id), |
| viz::SurfaceRange(new_surface_id))); |
| EXPECT_THAT(host_impl_.pending_tree()->SurfaceRanges(), |
| ElementsAre(viz::SurfaceRange(old_surface_id), |
| viz::SurfaceRange(new_surface_id))); |
| |
| // Unparent the old layer like it's being destroyed at the end of animation. |
| layer1->SetLayerTreeHost(nullptr); |
| |
| SynchronizeTrees(); |
| |
| // Verify that only |new_surface_id| is going to be referenced. |
| EXPECT_THAT(layer_tree_host_->SurfaceRanges(), |
| ElementsAre(viz::SurfaceRange(new_surface_id))); |
| EXPECT_THAT(host_impl_.pending_tree()->SurfaceRanges(), |
| ElementsAre(viz::SurfaceRange(new_surface_id))); |
| |
| // Cleanup for destruction. |
| layer2->SetLayerTreeHost(nullptr); |
| } |
| |
| // This test verifies LayerTreeHost::needs_surface_ranges_sync() is correct when |
| // there are cloned surface layers. |
| TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) { |
| const viz::SurfaceId surface_id( |
| kArbitraryFrameSinkId, |
| viz::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| |
| scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create(); |
| layer1->SetLayerTreeHost(layer_tree_host_.get()); |
| layer1->SetSurfaceId(surface_id, DeadlinePolicy::UseDefaultDeadline()); |
| layer1->SetOldestAcceptableFallback(surface_id); |
| |
| // Verify the surface id is in SurfaceLayerIds() and |
| // needs_surface_ranges_sync() is true. |
| EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync()); |
| EXPECT_THAT(layer_tree_host_->SurfaceRanges(), SizeIs(1)); |
| |
| std::unique_ptr<SurfaceLayerImpl> layer_impl1 = |
| SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer1->id()); |
| SynchronizeTrees(); |
| |
| // After syncchronizing trees verify needs_surface_ranges_sync() is false. |
| EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync()); |
| |
| // Create the second layer that is a clone of the first. |
| scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create(); |
| layer2->SetLayerTreeHost(layer_tree_host_.get()); |
| layer2->SetSurfaceId(surface_id, DeadlinePolicy::UseDefaultDeadline()); |
| layer2->SetOldestAcceptableFallback(surface_id); |
| |
| // Verify that after creating the second layer with the same surface id that |
| // needs_surface_ranges_sync() is still false. |
| EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync()); |
| EXPECT_THAT(layer_tree_host_->SurfaceRanges(), SizeIs(1)); |
| |
| std::unique_ptr<SurfaceLayerImpl> layer_impl2 = |
| SurfaceLayerImpl::Create(host_impl_.pending_tree(), layer2->id()); |
| SynchronizeTrees(); |
| |
| // Verify needs_surface_ranges_sync() is still false after synchronizing |
| // trees. |
| EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync()); |
| |
| // Destroy one of the layers, leaving one layer with the surface id. |
| layer1->SetLayerTreeHost(nullptr); |
| |
| // Verify needs_surface_ranges_sync() is still false. |
| EXPECT_FALSE(layer_tree_host_->needs_surface_ranges_sync()); |
| |
| // Destroy the last layer, this should change the set of layer surface ids. |
| layer2->SetLayerTreeHost(nullptr); |
| |
| // Verify SurfaceLayerIds() is empty and needs_surface_ranges_sync() is true. |
| EXPECT_TRUE(layer_tree_host_->needs_surface_ranges_sync()); |
| EXPECT_THAT(layer_tree_host_->SurfaceRanges(), SizeIs(0)); |
| } |
| |
| } // namespace |
| } // namespace cc |