// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cc/layers/picture_layer.h" #include #include "base/thread_task_runner_handle.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/empty_content_layer_client.h" #include "cc/layers/picture_layer_impl.h" #include "cc/playback/display_item_list_settings.h" #include "cc/proto/layer.pb.h" #include "cc/test/fake_display_list_recording_source.h" #include "cc/test/fake_image_serialization_processor.h" #include "cc/test/fake_layer_tree_host.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_picture_layer.h" #include "cc/test/fake_picture_layer_impl.h" #include "cc/test/fake_proxy.h" #include "cc/test/skia_common.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_task_graph_runner.h" #include "cc/trees/single_thread_proxy.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { class TestSerializationPictureLayer : public PictureLayer { public: static scoped_refptr Create( const gfx::Size& recording_source_viewport) { return make_scoped_refptr(new TestSerializationPictureLayer( EmptyContentLayerClient::GetInstance(), FakeDisplayListRecordingSource::CreateFilledRecordingSource( recording_source_viewport), recording_source_viewport)); } FakeDisplayListRecordingSource* recording_source() { return static_cast( recording_source_.get()); } void set_invalidation(const Region& invalidation) { *invalidation_.region() = invalidation; } void set_last_updated_visible_layer_rect(const gfx::Rect& rect) { last_updated_visible_layer_rect_ = rect; } void set_update_source_frame_number(int number) { update_source_frame_number_ = number; } void set_is_mask(bool is_mask) { is_mask_ = is_mask; } void set_nearest_neighbor(bool nearest_neighbor) { nearest_neighbor_ = nearest_neighbor; } void ValidateSerialization() { proto::LayerProperties proto; LayerSpecificPropertiesToProto(&proto); FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; LayerTreeSettings settings; scoped_ptr fake_image_serialization_processor = make_scoped_ptr(new FakeImageSerializationProcessor); scoped_ptr host = FakeLayerTreeHost::Create(&host_client, &task_graph_runner, settings, CompositorMode::SINGLE_THREADED, fake_image_serialization_processor.get()); scoped_refptr layer = TestSerializationPictureLayer::Create(recording_source_viewport_); host->SetRootLayer(layer); layer->FromLayerSpecificPropertiesProto(proto); // Validate that the PictureLayer specific fields are properly set. EXPECT_TRUE(recording_source()->EqualsTo(*layer->recording_source())); EXPECT_EQ(last_updated_visible_layer_rect_, layer->last_updated_visible_layer_rect_); EXPECT_EQ(update_source_frame_number_, layer->update_source_frame_number_); EXPECT_EQ(is_mask_, layer->is_mask_); EXPECT_EQ(nearest_neighbor_, layer->nearest_neighbor_); } private: TestSerializationPictureLayer(ContentLayerClient* client, scoped_ptr source, const gfx::Size& recording_source_viewport) : PictureLayer(client, std::move(source)), recording_source_viewport_(recording_source_viewport) {} ~TestSerializationPictureLayer() override {} gfx::Size recording_source_viewport_; DISALLOW_COPY_AND_ASSIGN(TestSerializationPictureLayer); }; namespace { TEST(PictureLayerTest, TestSetAllPropsSerializationDeserialization) { FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; LayerTreeSettings settings; scoped_ptr fake_image_serialization_processor = make_scoped_ptr(new FakeImageSerializationProcessor); scoped_ptr host = FakeLayerTreeHost::Create(&host_client, &task_graph_runner, settings, CompositorMode::SINGLE_THREADED, fake_image_serialization_processor.get()); gfx::Size recording_source_viewport(256, 256); scoped_refptr layer = TestSerializationPictureLayer::Create(recording_source_viewport); host->SetRootLayer(layer); Region region(gfx::Rect(14, 15, 16, 17)); layer->set_invalidation(region); layer->set_last_updated_visible_layer_rect(gfx::Rect(5, 6, 7, 8)); layer->set_is_mask(true); layer->set_nearest_neighbor(true); layer->SetBounds(recording_source_viewport); layer->set_update_source_frame_number(0); layer->recording_source()->SetDisplayListUsesCachedPicture(false); layer->recording_source()->add_draw_rect( gfx::Rect(recording_source_viewport)); layer->recording_source()->SetGenerateDiscardableImagesMetadata(true); layer->recording_source()->Rerecord(); layer->ValidateSerialization(); } TEST(PictureLayerTest, TestSerializationDeserialization) { FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; scoped_ptr fake_image_serialization_processor = make_scoped_ptr(new FakeImageSerializationProcessor); scoped_ptr host = FakeLayerTreeHost::Create( &host_client, &task_graph_runner, LayerTreeSettings(), CompositorMode::SINGLE_THREADED, fake_image_serialization_processor.get()); gfx::Size recording_source_viewport(256, 256); scoped_refptr layer = TestSerializationPictureLayer::Create(recording_source_viewport); host->SetRootLayer(layer); layer->SetBounds(recording_source_viewport); layer->set_update_source_frame_number(0); layer->recording_source()->SetDisplayListUsesCachedPicture(false); layer->recording_source()->add_draw_rect( gfx::Rect(recording_source_viewport)); layer->recording_source()->SetGenerateDiscardableImagesMetadata(true); layer->recording_source()->Rerecord(); layer->ValidateSerialization(); } TEST(PictureLayerTest, TestEmptySerializationDeserialization) { FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; scoped_ptr host = FakeLayerTreeHost::Create(&host_client, &task_graph_runner); gfx::Size recording_source_viewport(256, 256); scoped_refptr layer = TestSerializationPictureLayer::Create(recording_source_viewport); host->SetRootLayer(layer); layer->ValidateSerialization(); } TEST(PictureLayerTest, NoTilesIfEmptyBounds) { ContentLayerClient* client = EmptyContentLayerClient::GetInstance(); scoped_refptr layer = PictureLayer::Create(client); layer->SetBounds(gfx::Size(10, 10)); FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; scoped_ptr host = FakeLayerTreeHost::Create(&host_client, &task_graph_runner); host->SetRootLayer(layer); layer->SetIsDrawable(true); layer->SavePaintProperties(); layer->Update(); EXPECT_EQ(0, host->source_frame_number()); host->CommitComplete(); EXPECT_EQ(1, host->source_frame_number()); layer->SetBounds(gfx::Size(0, 0)); layer->SavePaintProperties(); // Intentionally skipping Update since it would normally be skipped on // a layer with empty bounds. FakeImplTaskRunnerProvider impl_task_runner_provider; TestSharedBitmapManager shared_bitmap_manager; scoped_ptr output_surface = FakeOutputSurface::CreateSoftware( make_scoped_ptr(new SoftwareOutputDevice)); FakeLayerTreeHostImpl host_impl(LayerTreeSettings(), &impl_task_runner_provider, &shared_bitmap_manager, &task_graph_runner); host_impl.InitializeRenderer(output_surface.get()); host_impl.CreatePendingTree(); scoped_ptr layer_impl = FakePictureLayerImpl::Create(host_impl.pending_tree(), 1); layer->PushPropertiesTo(layer_impl.get()); EXPECT_FALSE(layer_impl->CanHaveTilings()); EXPECT_TRUE(layer_impl->bounds() == gfx::Size(0, 0)); EXPECT_EQ(gfx::Size(), layer_impl->raster_source()->GetSize()); EXPECT_FALSE(layer_impl->raster_source()->HasRecordings()); } TEST(PictureLayerTest, ClearVisibleRectWhenNoTiling) { gfx::Size layer_size(50, 50); FakeContentLayerClient client; client.set_bounds(layer_size); skia::RefPtr image = CreateDiscardableImage(layer_size); client.add_draw_image(image.get(), gfx::Point(), SkPaint()); scoped_refptr layer = PictureLayer::Create(&client); layer->SetBounds(gfx::Size(10, 10)); FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; scoped_ptr host = FakeLayerTreeHost::Create(&host_client, &task_graph_runner); host->SetRootLayer(layer); layer->SetIsDrawable(true); layer->SavePaintProperties(); layer->Update(); EXPECT_EQ(0, host->source_frame_number()); host->CommitComplete(); EXPECT_EQ(1, host->source_frame_number()); layer->SavePaintProperties(); layer->Update(); FakeImplTaskRunnerProvider impl_task_runner_provider; TestSharedBitmapManager shared_bitmap_manager; scoped_ptr output_surface(FakeOutputSurface::Create3d()); LayerTreeSettings layer_tree_settings = LayerTreeSettings(); layer_tree_settings.image_decode_tasks_enabled = true; FakeLayerTreeHostImpl host_impl(layer_tree_settings, &impl_task_runner_provider, &shared_bitmap_manager, &task_graph_runner); host_impl.SetVisible(true); EXPECT_TRUE(host_impl.InitializeRenderer(output_surface.get())); host_impl.CreatePendingTree(); host_impl.pending_tree()->SetRootLayer( FakePictureLayerImpl::Create(host_impl.pending_tree(), 1)); FakePictureLayerImpl* layer_impl = static_cast( host_impl.pending_tree()->root_layer()); layer->PushPropertiesTo(layer_impl); host->CommitComplete(); EXPECT_EQ(2, host->source_frame_number()); host_impl.ActivateSyncTree(); // By updating the draw proprties on the active tree, we will set the viewport // rect for tile priorities to something non-empty. const bool can_use_lcd_text = false; host_impl.active_tree()->property_trees()->needs_rebuild = true; host_impl.active_tree()->BuildPropertyTreesForTesting(); host_impl.active_tree()->UpdateDrawProperties(can_use_lcd_text); layer->SetBounds(gfx::Size(11, 11)); layer->SavePaintProperties(); host_impl.CreatePendingTree(); layer_impl = static_cast( host_impl.pending_tree()->root_layer()); // We should now have invalid contents and should therefore clear the // recording source. layer->PushPropertiesTo(layer_impl); host_impl.ActivateSyncTree(); scoped_ptr render_pass = RenderPass::Create(); AppendQuadsData data; host_impl.active_tree()->root_layer()->WillDraw(DRAW_MODE_SOFTWARE, nullptr); host_impl.active_tree()->root_layer()->AppendQuads(render_pass.get(), &data); host_impl.active_tree()->root_layer()->DidDraw(nullptr); } TEST(PictureLayerTest, SuitableForGpuRasterization) { scoped_ptr recording_source_owned( new FakeDisplayListRecordingSource); FakeDisplayListRecordingSource* recording_source = recording_source_owned.get(); ContentLayerClient* client = EmptyContentLayerClient::GetInstance(); scoped_refptr layer = FakePictureLayer::CreateWithRecordingSource( client, std::move(recording_source_owned)); FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; scoped_ptr host = FakeLayerTreeHost::Create(&host_client, &task_graph_runner); host->SetRootLayer(layer); // Update layers to initialize the recording source. gfx::Size layer_bounds(200, 200); gfx::Rect layer_rect(layer_bounds); Region invalidation(layer_rect); recording_source->UpdateAndExpandInvalidation( client, &invalidation, layer_bounds, layer_rect, 1, DisplayListRecordingSource::RECORD_NORMALLY); // Layer is suitable for gpu rasterization by default. EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization()); EXPECT_TRUE(layer->IsSuitableForGpuRasterization()); // Veto gpu rasterization. recording_source->SetUnsuitableForGpuRasterization(); EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization()); EXPECT_FALSE(layer->IsSuitableForGpuRasterization()); } // PicturePile uses the source frame number as a unit for measuring invalidation // frequency. When a pile moves between compositors, the frame number increases // non-monotonically. This executes that code path under this scenario allowing // for the code to verify correctness with DCHECKs. TEST(PictureLayerTest, NonMonotonicSourceFrameNumber) { LayerTreeSettings settings; settings.single_thread_proxy_scheduler = false; settings.use_zero_copy = true; FakeLayerTreeHostClient host_client1(FakeLayerTreeHostClient::DIRECT_3D); FakeLayerTreeHostClient host_client2(FakeLayerTreeHostClient::DIRECT_3D); TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; ContentLayerClient* client = EmptyContentLayerClient::GetInstance(); scoped_refptr layer = FakePictureLayer::Create(client); LayerTreeHost::InitParams params; params.client = &host_client1; params.shared_bitmap_manager = &shared_bitmap_manager; params.settings = &settings; params.task_graph_runner = &task_graph_runner; params.main_task_runner = base::ThreadTaskRunnerHandle::Get(); scoped_ptr host1 = LayerTreeHost::CreateSingleThreaded(&host_client1, ¶ms); host1->SetVisible(true); host_client1.SetLayerTreeHost(host1.get()); params.client = &host_client2; scoped_ptr host2 = LayerTreeHost::CreateSingleThreaded(&host_client2, ¶ms); host2->SetVisible(true); host_client2.SetLayerTreeHost(host2.get()); // The PictureLayer is put in one LayerTreeHost. host1->SetRootLayer(layer); // Do a main frame, record the picture layers. EXPECT_EQ(0, layer->update_count()); layer->SetNeedsDisplay(); host1->Composite(base::TimeTicks::Now()); EXPECT_EQ(1, layer->update_count()); EXPECT_EQ(1, host1->source_frame_number()); // The source frame number in |host1| is now higher than host2. layer->SetNeedsDisplay(); host1->Composite(base::TimeTicks::Now()); EXPECT_EQ(2, layer->update_count()); EXPECT_EQ(2, host1->source_frame_number()); // Then moved to another LayerTreeHost. host1->SetRootLayer(nullptr); host2->SetRootLayer(layer); // Do a main frame, record the picture layers. The frame number has changed // non-monotonically. layer->SetNeedsDisplay(); host2->Composite(base::TimeTicks::Now()); EXPECT_EQ(3, layer->update_count()); EXPECT_EQ(1, host2->source_frame_number()); } } // namespace } // namespace cc