| // 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 <stddef.h> |
| |
| #include "base/location.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "cc/layers/effect_tree_layer_list_iterator.h" |
| #include "cc/test/fake_content_layer_client.h" |
| #include "cc/test/fake_picture_layer.h" |
| #include "cc/test/layer_tree_test.h" |
| #include "cc/trees/layer_tree_impl.h" |
| #include "components/viz/common/frame_sinks/copy_output_request.h" |
| #include "components/viz/common/frame_sinks/copy_output_result.h" |
| #include "components/viz/service/display/direct_renderer.h" |
| #include "components/viz/test/fake_output_surface.h" |
| #include "components/viz/test/test_gles2_interface.h" |
| #include "components/viz/test/test_layer_tree_frame_sink.h" |
| #include "gpu/GLES2/gl2extchromium.h" |
| |
| namespace cc { |
| namespace { |
| |
| // These tests only use direct rendering, as there is no output to copy for |
| // delegated renderers. |
| class LayerTreeHostCopyRequestTest : public LayerTreeTest {}; |
| |
| class LayerTreeHostCopyRequestTestMultipleRequests |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root = FakePictureLayer::Create(&client_); |
| root->SetBounds(gfx::Size(20, 20)); |
| |
| child = FakePictureLayer::Create(&client_); |
| child->SetBounds(gfx::Size(10, 10)); |
| root->AddChild(child); |
| |
| grand_child = FakePictureLayer::Create(&client_); |
| grand_child->SetBounds(gfx::Size(5, 5)); |
| child->AddChild(grand_child); |
| |
| layer_tree_host()->SetRootLayer(root); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root->bounds()); |
| } |
| |
| void BeginTest() override { PostSetNeedsCommitToMainThread(); } |
| |
| void DidCommit() override { WaitForCallback(); } |
| |
| void WaitForCallback() { |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests::NextStep, |
| base::Unretained(this))); |
| } |
| |
| void NextStep() { |
| int frame = layer_tree_host()->SourceFrameNumber(); |
| switch (frame) { |
| case 1: |
| child->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| CopyOutputCallback, |
| base::Unretained(this), 0))); |
| EXPECT_EQ(0u, callbacks_.size()); |
| break; |
| case 2: |
| // This commit is triggered by the copy request having been completed. |
| break; |
| case 3: |
| if (callbacks_.size() < 1u) { |
| WaitForCallback(); |
| return; |
| } |
| EXPECT_EQ(1u, callbacks_.size()); |
| EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString()); |
| |
| child->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| CopyOutputCallback, |
| base::Unretained(this), 1))); |
| root->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| CopyOutputCallback, |
| base::Unretained(this), 2))); |
| grand_child->RequestCopyOfOutput( |
| std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests:: |
| CopyOutputCallback, |
| base::Unretained(this), 3))); |
| EXPECT_EQ(1u, callbacks_.size()); |
| break; |
| case 4: |
| // This commit is triggered by the copy request having been completed. |
| break; |
| case 5: |
| if (callbacks_.size() < 4u) { |
| WaitForCallback(); |
| return; |
| } |
| EXPECT_EQ(4u, callbacks_.size()); |
| |
| // The |child| was copied to a bitmap and passed back in Case 1. |
| EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString()); |
| |
| // The |child| was copied to a bitmap and passed back in Case 2. |
| EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[1].ToString()); |
| // The |root| was copied to a bitmap and passed back also in Case 2. |
| EXPECT_EQ(gfx::Size(20, 20).ToString(), callbacks_[2].ToString()); |
| // The |grand_child| was copied to a bitmap and passed back in Case 2. |
| EXPECT_EQ(gfx::Size(5, 5).ToString(), callbacks_[3].ToString()); |
| EndTest(); |
| break; |
| } |
| } |
| |
| void CopyOutputCallback(size_t id, |
| std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread()); |
| EXPECT_FALSE(result->IsEmpty()); |
| const SkBitmap& bitmap = result->AsSkBitmap(); |
| EXPECT_TRUE(bitmap.readyToDraw()); |
| EXPECT_EQ(result->size(), gfx::Size(bitmap.width(), bitmap.height())); |
| callbacks_[id] = result->size(); |
| } |
| |
| void AfterTest() override { EXPECT_EQ(4u, callbacks_.size()); } |
| |
| std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( |
| scoped_refptr<viz::ContextProvider> compositor_context_provider) |
| override { |
| if (!use_gl_renderer_) { |
| return viz::FakeOutputSurface::CreateSoftware( |
| std::make_unique<viz::SoftwareOutputDevice>()); |
| } |
| |
| scoped_refptr<viz::TestContextProvider> display_context_provider = |
| viz::TestContextProvider::Create(); |
| viz::TestContextSupport* context_support = |
| display_context_provider->support(); |
| context_support->set_out_of_order_callbacks(out_of_order_callbacks_); |
| display_context_provider->BindToCurrentThread(); |
| |
| return viz::FakeOutputSurface::Create3d( |
| std::move(display_context_provider)); |
| } |
| |
| bool use_gl_renderer_; |
| bool out_of_order_callbacks_ = false; |
| std::map<size_t, gfx::Size> callbacks_; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root; |
| scoped_refptr<FakePictureLayer> child; |
| scoped_refptr<FakePictureLayer> grand_child; |
| }; |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| GLRenderer_RunSingleThread) { |
| use_gl_renderer_ = true; |
| RunTest(CompositorMode::SINGLE_THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| GLRenderer_RunMultiThread) { |
| use_gl_renderer_ = true; |
| RunTest(CompositorMode::THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| GLRenderer_RunSingleThread_OutOfOrderCallbacks) { |
| use_gl_renderer_ = true; |
| out_of_order_callbacks_ = true; |
| RunTest(CompositorMode::SINGLE_THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| GLRenderer_RunMultiThread_OutOfOrderCallbacks) { |
| use_gl_renderer_ = true; |
| out_of_order_callbacks_ = true; |
| RunTest(CompositorMode::THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| SkiaRenderer_RunSingleThread) { |
| use_gl_renderer_ = true; |
| use_skia_renderer_ = true; |
| RunTest(CompositorMode::SINGLE_THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| SkiaRenderer_RunMultiThread) { |
| use_gl_renderer_ = true; |
| use_skia_renderer_ = true; |
| RunTest(CompositorMode::THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| SkiaRenderer_RunSingleThread_OutOfOrderCallbacks) { |
| use_gl_renderer_ = true; |
| use_skia_renderer_ = true; |
| out_of_order_callbacks_ = true; |
| RunTest(CompositorMode::SINGLE_THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| SkiaRenderer_RunMultiThread_OutOfOrderCallbacks) { |
| use_gl_renderer_ = true; |
| use_skia_renderer_ = true; |
| out_of_order_callbacks_ = true; |
| RunTest(CompositorMode::THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| SoftwareRenderer_RunSingleThread) { |
| use_gl_renderer_ = false; |
| RunTest(CompositorMode::SINGLE_THREADED); |
| } |
| |
| TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, |
| SoftwareRenderer_RunMultiThread) { |
| use_gl_renderer_ = false; |
| RunTest(CompositorMode::THREADED); |
| } |
| |
| // TODO(crbug.com/564832): Remove this test when the workaround it tests is no |
| // longer needed. |
| class LayerTreeHostCopyRequestCompletionCausesCommit |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| layer_ = FakePictureLayer::Create(&client_); |
| layer_->SetBounds(gfx::Size(15, 15)); |
| root_->AddChild(layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void BeginTest() override { |
| PostSetNeedsCommitToMainThread(); |
| } |
| |
| void DidCommit() override { |
| int frame = layer_tree_host()->SourceFrameNumber(); |
| switch (frame) { |
| case 1: |
| layer_->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce(&LayerTreeHostCopyRequestCompletionCausesCommit:: |
| CopyOutputCallback))); |
| break; |
| case 2: |
| // This commit is triggered by the copy request. |
| break; |
| case 3: |
| // This commit is triggered by the completion of the copy request. |
| EndTest(); |
| break; |
| } |
| } |
| |
| static void CopyOutputCallback( |
| std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_FALSE(result->IsEmpty()); |
| } |
| |
| void AfterTest() override {} |
| |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestCompletionCausesCommit); |
| |
| class LayerTreeHostCopyRequestTestLayerDestroyed |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| main_destroyed_ = FakePictureLayer::Create(&client_); |
| main_destroyed_->SetBounds(gfx::Size(15, 15)); |
| root_->AddChild(main_destroyed_); |
| |
| impl_destroyed_ = FakePictureLayer::Create(&client_); |
| impl_destroyed_->SetBounds(gfx::Size(10, 10)); |
| root_->AddChild(impl_destroyed_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void BeginTest() override { |
| callback_count_ = 0; |
| PostSetNeedsCommitToMainThread(); |
| } |
| |
| void DidCommit() override { |
| int frame = layer_tree_host()->SourceFrameNumber(); |
| switch (frame) { |
| case 1: |
| main_destroyed_->RequestCopyOfOutput(std::make_unique< |
| viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback, |
| base::Unretained(this)))); |
| impl_destroyed_->RequestCopyOfOutput(std::make_unique< |
| viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback, |
| base::Unretained(this)))); |
| EXPECT_EQ(0, callback_count_); |
| |
| // Destroy the main thread layer right away. |
| main_destroyed_->RemoveFromParent(); |
| main_destroyed_ = nullptr; |
| |
| // Should callback with a NULL bitmap. |
| EXPECT_EQ(1, callback_count_); |
| |
| // Prevent drawing so we can't make a copy of the impl_destroyed layer. |
| layer_tree_host()->SetViewportSizeAndScale( |
| gfx::Size(), 1.f, viz::LocalSurfaceIdAllocation()); |
| break; |
| case 2: |
| // Flush the message loops and make sure the callbacks run. |
| layer_tree_host()->SetNeedsCommit(); |
| break; |
| case 3: |
| // No drawing means no readback yet. |
| EXPECT_EQ(1, callback_count_); |
| |
| // Destroy the impl thread layer. |
| impl_destroyed_->RemoveFromParent(); |
| impl_destroyed_ = nullptr; |
| |
| // No callback yet because it's on the impl side. |
| EXPECT_EQ(1, callback_count_); |
| break; |
| case 4: |
| // Flush the message loops and make sure the callbacks run. |
| layer_tree_host()->SetNeedsCommit(); |
| break; |
| case 5: |
| // We should get another callback with a NULL bitmap. |
| EXPECT_EQ(2, callback_count_); |
| EndTest(); |
| break; |
| } |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread()); |
| EXPECT_TRUE(result->IsEmpty()); |
| ++callback_count_; |
| } |
| |
| void AfterTest() override {} |
| |
| int callback_count_; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> main_destroyed_; |
| scoped_refptr<FakePictureLayer> impl_destroyed_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestLayerDestroyed); |
| |
| class LayerTreeHostCopyRequestTestInHiddenSubtree |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| grand_parent_layer_ = FakePictureLayer::Create(&client_); |
| grand_parent_layer_->SetBounds(gfx::Size(15, 15)); |
| root_->AddChild(grand_parent_layer_); |
| |
| // parent_layer_ owns a render surface. |
| parent_layer_ = FakePictureLayer::Create(&client_); |
| parent_layer_->SetBounds(gfx::Size(15, 15)); |
| parent_layer_->SetForceRenderSurfaceForTesting(true); |
| grand_parent_layer_->AddChild(parent_layer_); |
| |
| copy_layer_ = FakePictureLayer::Create(&client_); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| parent_layer_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void AddCopyRequest(Layer* layer) { |
| layer->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestInHiddenSubtree::CopyOutputCallback, |
| base::Unretained(this)))); |
| } |
| |
| void BeginTest() override { |
| callback_count_ = 0; |
| PostSetNeedsCommitToMainThread(); |
| |
| AddCopyRequest(copy_layer_.get()); |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| ++callback_count_; |
| EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread()); |
| EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()) |
| << callback_count_; |
| switch (callback_count_) { |
| case 1: |
| // Hide the copy request layer. |
| grand_parent_layer_->SetHideLayerAndSubtree(false); |
| parent_layer_->SetHideLayerAndSubtree(false); |
| copy_layer_->SetHideLayerAndSubtree(true); |
| AddCopyRequest(copy_layer_.get()); |
| break; |
| case 2: |
| // Hide the copy request layer's parent only. |
| grand_parent_layer_->SetHideLayerAndSubtree(false); |
| parent_layer_->SetHideLayerAndSubtree(true); |
| copy_layer_->SetHideLayerAndSubtree(false); |
| AddCopyRequest(copy_layer_.get()); |
| break; |
| case 3: |
| // Hide the copy request layer's grand parent only. |
| grand_parent_layer_->SetHideLayerAndSubtree(true); |
| parent_layer_->SetHideLayerAndSubtree(false); |
| copy_layer_->SetHideLayerAndSubtree(false); |
| AddCopyRequest(copy_layer_.get()); |
| break; |
| case 4: |
| // Hide the copy request layer's parent and grandparent. |
| grand_parent_layer_->SetHideLayerAndSubtree(true); |
| parent_layer_->SetHideLayerAndSubtree(true); |
| copy_layer_->SetHideLayerAndSubtree(false); |
| AddCopyRequest(copy_layer_.get()); |
| break; |
| case 5: |
| // Hide the copy request layer as well as its parent and grandparent. |
| grand_parent_layer_->SetHideLayerAndSubtree(true); |
| parent_layer_->SetHideLayerAndSubtree(true); |
| copy_layer_->SetHideLayerAndSubtree(true); |
| AddCopyRequest(copy_layer_.get()); |
| break; |
| case 6: |
| EndTest(); |
| break; |
| } |
| } |
| |
| void AfterTest() override {} |
| |
| int callback_count_; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> grand_parent_layer_; |
| scoped_refptr<FakePictureLayer> parent_layer_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestInHiddenSubtree); |
| |
| class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| grand_parent_layer_ = FakePictureLayer::Create(&client_); |
| grand_parent_layer_->SetBounds(gfx::Size(15, 15)); |
| grand_parent_layer_->SetHideLayerAndSubtree(true); |
| root_->AddChild(grand_parent_layer_); |
| |
| // parent_layer_ owns a render surface. |
| parent_layer_ = FakePictureLayer::Create(&client_); |
| parent_layer_->SetBounds(gfx::Size(15, 15)); |
| parent_layer_->SetForceRenderSurfaceForTesting(true); |
| grand_parent_layer_->AddChild(parent_layer_); |
| |
| copy_layer_ = FakePictureLayer::Create(&client_); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| parent_layer_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink( |
| const viz::RendererSettings& renderer_settings, |
| double refresh_rate, |
| scoped_refptr<viz::ContextProvider> compositor_context_provider, |
| scoped_refptr<viz::RasterContextProvider> worker_context_provider) |
| override { |
| auto frame_sink = LayerTreeHostCopyRequestTest::CreateLayerTreeFrameSink( |
| renderer_settings, refresh_rate, std::move(compositor_context_provider), |
| std::move(worker_context_provider)); |
| frame_sink_ = frame_sink.get(); |
| return frame_sink; |
| } |
| |
| void BeginTest() override { |
| PostSetNeedsCommitToMainThread(); |
| |
| copy_layer_->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest:: |
| CopyOutputCallback, |
| base::Unretained(this)))); |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread()); |
| EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); |
| EndTest(); |
| } |
| |
| void DisplayWillDrawAndSwapOnThread( |
| bool will_draw_and_swap, |
| const viz::RenderPassList& render_passes) override { |
| EXPECT_TRUE(will_draw_and_swap) << did_swap_; |
| if (did_swap_) { |
| // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy |
| // completion. This can be removed when the extra commit is removed. |
| EXPECT_EQ(1u, render_passes.size()); |
| return; |
| } |
| |
| EXPECT_EQ(2u, render_passes.size()); |
| // The root pass is the back of the list. |
| copy_layer_render_pass_id = render_passes[0]->id; |
| parent_render_pass_id = render_passes[1]->id; |
| } |
| |
| void DisplayDidDrawAndSwapOnThread() override { |
| viz::DirectRenderer* renderer = |
| frame_sink_->display()->renderer_for_testing(); |
| |
| // |parent| owns a surface, but it was hidden and not part of the copy |
| // request so it should not allocate any resource. |
| EXPECT_FALSE( |
| renderer->HasAllocatedResourcesForTesting(parent_render_pass_id)); |
| |
| // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy |
| // completion. This can be removed when the extra commit is removed. |
| if (did_swap_) { |
| EXPECT_FALSE( |
| renderer->HasAllocatedResourcesForTesting(copy_layer_render_pass_id)); |
| } else { |
| // |copy_layer| should have been rendered to a texture since it was needed |
| // for a copy request. |
| EXPECT_TRUE( |
| renderer->HasAllocatedResourcesForTesting(copy_layer_render_pass_id)); |
| } |
| |
| did_swap_ = true; |
| } |
| |
| void AfterTest() override { EXPECT_TRUE(did_swap_); } |
| |
| viz::RenderPassId parent_render_pass_id = 0; |
| viz::RenderPassId copy_layer_render_pass_id = 0; |
| viz::TestLayerTreeFrameSink* frame_sink_ = nullptr; |
| bool did_swap_ = false; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> grand_parent_layer_; |
| scoped_refptr<FakePictureLayer> parent_layer_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F( |
| LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest); |
| |
| class LayerTreeHostCopyRequestTestClippedOut |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| parent_layer_ = FakePictureLayer::Create(&client_); |
| parent_layer_->SetBounds(gfx::Size(15, 15)); |
| parent_layer_->SetMasksToBounds(true); |
| root_->AddChild(parent_layer_); |
| |
| copy_layer_ = FakePictureLayer::Create(&client_); |
| copy_layer_->SetPosition(gfx::PointF(15.f, 15.f)); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| parent_layer_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void BeginTest() override { |
| PostSetNeedsCommitToMainThread(); |
| |
| copy_layer_->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestClippedOut::CopyOutputCallback, |
| base::Unretained(this)))); |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| // We should still get the content even if the copy requested layer was |
| // completely clipped away. |
| EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread()); |
| EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString()); |
| EndTest(); |
| } |
| |
| void AfterTest() override {} |
| |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> parent_layer_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestClippedOut); |
| |
| class LayerTreeHostCopyRequestTestScaledLayer |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void InitializeSettings(LayerTreeSettings* settings) override { |
| settings->layer_transforms_should_scale_layer_contents = true; |
| } |
| |
| void SetupTree() override { |
| root_ = Layer::Create(); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| gfx::Transform scale; |
| scale.Scale(2, 2); |
| |
| copy_layer_ = Layer::Create(); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| copy_layer_->SetTransform(scale); |
| root_->AddChild(copy_layer_); |
| |
| child_layer_ = FakePictureLayer::Create(&client_); |
| child_layer_->SetBounds(gfx::Size(10, 10)); |
| copy_layer_->AddChild(child_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void BeginTest() override { |
| PostSetNeedsCommitToMainThread(); |
| |
| std::unique_ptr<viz::CopyOutputRequest> request = |
| std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestScaledLayer::CopyOutputCallback, |
| base::Unretained(this))); |
| request->set_area(gfx::Rect(5, 5)); |
| copy_layer_->RequestCopyOfOutput(std::move(request)); |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| // The request area is expressed in layer space, but the result's size takes |
| // into account the transform from layer space to surface space. |
| EXPECT_EQ(gfx::Size(10, 10), result->size()); |
| EndTest(); |
| } |
| |
| void AfterTest() override {} |
| |
| FakeContentLayerClient client_; |
| scoped_refptr<Layer> root_; |
| scoped_refptr<Layer> copy_layer_; |
| scoped_refptr<FakePictureLayer> child_layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestScaledLayer); |
| |
| class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| copy_layer_ = FakePictureLayer::Create(&client_); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| root_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void AddCopyRequest(Layer* layer) { |
| layer->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostTestAsyncTwoReadbacksWithoutDraw::CopyOutputCallback, |
| base::Unretained(this)))); |
| } |
| |
| void BeginTest() override { |
| saw_copy_request_ = false; |
| callback_count_ = 0; |
| PostSetNeedsCommitToMainThread(); |
| |
| // Prevent drawing. |
| layer_tree_host()->SetViewportSizeAndScale(gfx::Size(0, 0), 1.f, |
| viz::LocalSurfaceIdAllocation()); |
| |
| AddCopyRequest(copy_layer_.get()); |
| } |
| |
| void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { |
| if (impl->active_tree()->source_frame_number() == 0) { |
| EXPECT_TRUE(impl->active_tree()->LayerById(copy_layer_->id())); |
| saw_copy_request_ = true; |
| } |
| } |
| |
| void DidCommit() override { |
| if (layer_tree_host()->SourceFrameNumber() == 1) { |
| // Allow drawing. |
| layer_tree_host()->SetViewportSizeAndScale( |
| gfx::Size(root_->bounds()), 1.f, viz::LocalSurfaceIdAllocation()); |
| |
| AddCopyRequest(copy_layer_.get()); |
| } |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread()); |
| |
| // The first frame can't be drawn. |
| switch (callback_count_) { |
| case 0: |
| EXPECT_TRUE(result->IsEmpty()); |
| EXPECT_EQ(gfx::Size(), result->size()); |
| break; |
| case 1: |
| EXPECT_FALSE(result->IsEmpty()); |
| EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString()); |
| EndTest(); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| ++callback_count_; |
| } |
| |
| void AfterTest() override { EXPECT_TRUE(saw_copy_request_); } |
| |
| bool saw_copy_request_; |
| int callback_count_; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestAsyncTwoReadbacksWithoutDraw); |
| |
| class LayerTreeHostCopyRequestTestDeleteTexture |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( |
| scoped_refptr<viz::ContextProvider> compositor_context_provider) |
| override { |
| display_context_provider_ = viz::TestContextProvider::Create(); |
| display_context_provider_->BindToCurrentThread(); |
| return viz::FakeOutputSurface::Create3d(display_context_provider_); |
| } |
| |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| copy_layer_ = FakePictureLayer::Create(&client_); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| root_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void BeginTest() override { PostSetNeedsCommitToMainThread(); } |
| |
| void ReceiveCopyRequestOutputAndCommit( |
| std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_TRUE(layer_tree_host()->GetTaskRunnerProvider()->IsMainThread()); |
| EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString()); |
| EXPECT_EQ(result->format(), viz::CopyOutputResult::Format::RGBA_TEXTURE); |
| EXPECT_NE(result->GetTextureResult(), nullptr); |
| |
| // Save the result for later. |
| EXPECT_FALSE(result_); |
| result_ = std::move(result); |
| |
| // Post a commit to lose the output surface. |
| layer_tree_host()->SetNeedsCommit(); |
| } |
| |
| void InsertCopyRequest() { |
| copy_layer_->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, |
| base::BindOnce(&LayerTreeHostCopyRequestTestDeleteTexture:: |
| ReceiveCopyRequestOutputAndCommit, |
| base::Unretained(this)))); |
| } |
| |
| void DestroyCopyResultAndCheckNumTextures() { |
| EXPECT_TRUE(result_); |
| result_ = nullptr; |
| |
| ImplThreadTaskRunner()->PostTask( |
| FROM_HERE, base::BindOnce(&LayerTreeHostCopyRequestTestDeleteTexture:: |
| CheckNumTexturesAfterReadbackDestroyed, |
| base::Unretained(this))); |
| } |
| |
| void CheckNumTexturesAfterReadbackDestroyed() { |
| // After the copy we had |num_textures_after_readback_| many textures, but |
| // releasing the copy output request should cause the texture in the request |
| // to be destroyed by the compositor, so we should have 1 less by now. |
| EXPECT_EQ(num_textures_after_readback_ - 1, |
| display_context_provider_->TestContextGL()->NumTextures()); |
| |
| // Drop the reference to the context provider on the compositor thread. |
| display_context_provider_ = nullptr; |
| EndTest(); |
| } |
| |
| void DisplayDidDrawAndSwapOnThread() override { |
| switch (num_swaps_++) { |
| case 0: |
| // The layers have been drawn, so any textures required for drawing have |
| // been allocated. |
| EXPECT_FALSE(result_); |
| num_textures_without_readback_ = |
| display_context_provider_->TestContextGL()->NumTextures(); |
| |
| // Request a copy of the layer. This will use another texture. |
| MainThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestDeleteTexture::InsertCopyRequest, |
| base::Unretained(this))); |
| break; |
| case 1: |
| // Copy requests cause a followup commit and draw without the separate |
| // RenderPass required. This changes the number of active textures. So |
| // wait for that draw before counting textures and proceeding. |
| break; |
| case 2: |
| // We did a readback, so there will be a readback texture around now. |
| num_textures_after_readback_ = |
| display_context_provider_->TestContextGL()->NumTextures(); |
| EXPECT_LT(num_textures_without_readback_, num_textures_after_readback_); |
| |
| // Now destroy the CopyOutputResult, releasing the texture inside back |
| // to the compositor. Then check the resulting number of allocated |
| // textures. |
| MainThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&LayerTreeHostCopyRequestTestDeleteTexture:: |
| DestroyCopyResultAndCheckNumTextures, |
| base::Unretained(this))); |
| break; |
| } |
| } |
| |
| void AfterTest() override {} |
| |
| scoped_refptr<viz::TestContextProvider> display_context_provider_; |
| int num_swaps_ = 0; |
| size_t num_textures_without_readback_ = 0; |
| size_t num_textures_after_readback_ = 0; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| std::unique_ptr<viz::CopyOutputResult> result_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestDeleteTexture); |
| |
| class LayerTreeHostCopyRequestTestCountTextures |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( |
| scoped_refptr<viz::ContextProvider> compositor_context_provider) |
| override { |
| // These tests expect the LayerTreeHostImpl to share a context with |
| // the Display so that sync points are not needed and the texture counts |
| // are visible together. |
| // Since this test does not override CreateLayerTreeFrameSink, the |
| // |compositor_context_provider| will be a viz::TestContextProvider. |
| display_context_provider_ = static_cast<viz::TestContextProvider*>( |
| compositor_context_provider.get()); |
| return viz::FakeOutputSurface::Create3d( |
| std::move(compositor_context_provider)); |
| } |
| |
| void SetupTree() override { |
| // The layers in this test have solid color content, so they don't |
| // actually allocate any textures, making counting easier. |
| |
| root_ = FakePictureLayer::Create(&root_client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| root_client_.set_bounds(root_->bounds()); |
| |
| copy_layer_ = FakePictureLayer::Create(©_client_); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| copy_client_.set_bounds(copy_layer_->bounds()); |
| PaintFlags flags; |
| flags.setColor(SK_ColorRED); |
| // Ensure the layer isn't completely transparent so the RenderPass isn't |
| // optimized away. |
| copy_client_.add_draw_rect(gfx::Rect(0, 0, 10, 10), flags); |
| // Doing a copy makes the layer have a render surface which can cause |
| // texture allocations. So get those allocations out of the way in the |
| // first frame by forcing it to have a render surface. |
| copy_layer_->SetForceRenderSurfaceForTesting(true); |
| root_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| } |
| |
| void BeginTest() override { |
| waited_sync_token_after_readback_.Clear(); |
| PostSetNeedsCommitToMainThread(); |
| } |
| |
| virtual void RequestCopy(Layer* layer) = 0; |
| |
| void DidCommit() override { |
| switch (layer_tree_host()->SourceFrameNumber()) { |
| case 1: |
| // The layers have been pushed to the impl side and drawn. Any textures |
| // that are created in that process will have been allocated. |
| RequestCopy(copy_layer_.get()); |
| break; |
| } |
| } |
| |
| void DisplayDidDrawAndSwapOnThread() override { |
| switch (num_swaps_++) { |
| case 0: |
| // The first frame has been drawn, so textures for drawing have been |
| // allocated. |
| num_textures_without_readback_ = |
| display_context_provider_->TestContextGL()->NumTextures(); |
| break; |
| case 1: |
| // We did a readback, so there will be a readback texture around now. |
| num_textures_with_readback_ = |
| display_context_provider_->TestContextGL()->NumTextures(); |
| waited_sync_token_after_readback_ = |
| display_context_provider_->TestContextGL() |
| ->last_waited_sync_token(); |
| |
| // End the test after main thread has a chance to hear about the |
| // readback. |
| MainThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestCountTextures::DoEndTest, |
| base::Unretained(this))); |
| break; |
| } |
| } |
| |
| virtual void DoEndTest() { EndTest(); } |
| |
| scoped_refptr<viz::TestContextProvider> display_context_provider_; |
| int num_swaps_ = 0; |
| size_t num_textures_without_readback_ = 0; |
| size_t num_textures_with_readback_ = 0; |
| gpu::SyncToken waited_sync_token_after_readback_; |
| FakeContentLayerClient root_client_; |
| FakeContentLayerClient copy_client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| }; |
| |
| class LayerTreeHostCopyRequestTestCreatesTexture |
| : public LayerTreeHostCopyRequestTestCountTextures { |
| protected: |
| void RequestCopy(Layer* layer) override { |
| // Request a normal texture copy. This should create a new texture. |
| copy_layer_->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestCreatesTexture::CopyOutputCallback, |
| base::Unretained(this)))); |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_FALSE(result->IsEmpty()); |
| EXPECT_EQ(result->format(), viz::CopyOutputResult::Format::RGBA_TEXTURE); |
| ASSERT_NE(nullptr, result->GetTextureResult()); |
| release_ = result->TakeTextureOwnership(); |
| EXPECT_TRUE(release_); |
| } |
| |
| void AfterTest() override { |
| release_->Run(gpu::SyncToken(), false); |
| |
| // No sync point was needed. |
| EXPECT_FALSE(waited_sync_token_after_readback_.HasData()); |
| // Except the copy to have made another texture. |
| EXPECT_EQ(num_textures_without_readback_ + 1, num_textures_with_readback_); |
| } |
| |
| std::unique_ptr<viz::SingleReleaseCallback> release_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestCreatesTexture); |
| |
| class LayerTreeHostCopyRequestTestDestroyBeforeCopy |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| copy_layer_ = FakePictureLayer::Create(&client_); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| root_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void BeginTest() override { |
| callback_count_ = 0; |
| PostSetNeedsCommitToMainThread(); |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_TRUE(result->IsEmpty()); |
| ++callback_count_; |
| } |
| |
| void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { |
| MainThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestDestroyBeforeCopy::DidActivate, |
| base::Unretained(this))); |
| } |
| |
| void DidActivate() { |
| switch (layer_tree_host()->SourceFrameNumber()) { |
| case 1: { |
| EXPECT_EQ(0, callback_count_); |
| // Put a copy request on the layer, but then don't allow any |
| // drawing to take place. |
| std::unique_ptr<viz::CopyOutputRequest> request = |
| std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, |
| base::BindOnce(&LayerTreeHostCopyRequestTestDestroyBeforeCopy:: |
| CopyOutputCallback, |
| base::Unretained(this))); |
| copy_layer_->RequestCopyOfOutput(std::move(request)); |
| |
| layer_tree_host()->SetViewportSizeAndScale( |
| gfx::Size(), 1.f, viz::LocalSurfaceIdAllocation()); |
| break; |
| } |
| case 2: |
| EXPECT_EQ(0, callback_count_); |
| // Remove the copy layer before we were able to draw. |
| copy_layer_->RemoveFromParent(); |
| break; |
| case 3: |
| EXPECT_EQ(1, callback_count_); |
| // Allow us to draw now. |
| layer_tree_host()->SetViewportSizeAndScale( |
| layer_tree_host()->root_layer()->bounds(), 1.f, |
| viz::LocalSurfaceIdAllocation()); |
| break; |
| case 4: |
| EXPECT_EQ(1, callback_count_); |
| // We should not have crashed. |
| EndTest(); |
| } |
| } |
| |
| void AfterTest() override {} |
| |
| int callback_count_; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestDestroyBeforeCopy); |
| |
| class LayerTreeHostCopyRequestTestShutdownBeforeCopy |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| root_ = FakePictureLayer::Create(&client_); |
| root_->SetBounds(gfx::Size(20, 20)); |
| |
| copy_layer_ = FakePictureLayer::Create(&client_); |
| copy_layer_->SetBounds(gfx::Size(10, 10)); |
| root_->AddChild(copy_layer_); |
| |
| layer_tree_host()->SetRootLayer(root_); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root_->bounds()); |
| } |
| |
| void BeginTest() override { |
| callback_count_ = 0; |
| PostSetNeedsCommitToMainThread(); |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_TRUE(result->IsEmpty()); |
| ++callback_count_; |
| } |
| |
| void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { |
| MainThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestShutdownBeforeCopy::DidActivate, |
| base::Unretained(this))); |
| } |
| |
| void DidActivate() { |
| switch (layer_tree_host()->SourceFrameNumber()) { |
| case 1: { |
| EXPECT_EQ(0, callback_count_); |
| // Put a copy request on the layer, but then don't allow any |
| // drawing to take place. |
| std::unique_ptr<viz::CopyOutputRequest> request = |
| std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, |
| base::BindOnce(&LayerTreeHostCopyRequestTestShutdownBeforeCopy:: |
| CopyOutputCallback, |
| base::Unretained(this))); |
| copy_layer_->RequestCopyOfOutput(std::move(request)); |
| |
| layer_tree_host()->SetViewportSizeAndScale( |
| gfx::Size(), 1.f, viz::LocalSurfaceIdAllocation()); |
| break; |
| } |
| case 2: |
| DestroyLayerTreeHost(); |
| // End the test after the copy result has had a chance to get back to |
| // the main thread. |
| MainThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestShutdownBeforeCopy::EndTest, |
| base::Unretained(this))); |
| break; |
| } |
| } |
| |
| void AfterTest() override { EXPECT_EQ(1, callback_count_); } |
| |
| int callback_count_; |
| FakeContentLayerClient client_; |
| scoped_refptr<FakePictureLayer> root_; |
| scoped_refptr<FakePictureLayer> copy_layer_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestShutdownBeforeCopy); |
| |
| class LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest |
| : public LayerTreeHostCopyRequestTest { |
| protected: |
| void SetupTree() override { |
| scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_); |
| root->SetBounds(gfx::Size(20, 20)); |
| |
| child_ = FakePictureLayer::Create(&client_); |
| child_->SetBounds(gfx::Size(10, 10)); |
| root->AddChild(child_); |
| child_->SetHideLayerAndSubtree(true); |
| |
| layer_tree_host()->SetRootLayer(root); |
| LayerTreeHostCopyRequestTest::SetupTree(); |
| client_.set_bounds(root->bounds()); |
| } |
| |
| void BeginTest() override { |
| num_draws_ = 0; |
| copy_happened_ = false; |
| draw_happened_ = false; |
| PostSetNeedsCommitToMainThread(); |
| } |
| |
| void DidCommit() override { |
| // Send a copy request after the first commit. |
| if (layer_tree_host()->SourceFrameNumber() == 1) { |
| child_->RequestCopyOfOutput(std::make_unique<viz::CopyOutputRequest>( |
| viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest:: |
| CopyOutputCallback, |
| base::Unretained(this)))); |
| } |
| } |
| |
| DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, |
| LayerTreeHostImpl::FrameData* frame_data, |
| DrawResult draw_result) override { |
| LayerImpl* root = host_impl->active_tree()->root_layer_for_testing(); |
| LayerImpl* child = host_impl->active_tree()->LayerById(child_->id()); |
| |
| bool saw_root = false; |
| bool saw_child = false; |
| for (EffectTreeLayerListIterator it(host_impl->active_tree()); |
| it.state() != EffectTreeLayerListIterator::State::END; ++it) { |
| if (it.state() == EffectTreeLayerListIterator::State::LAYER) { |
| if (it.current_layer() == root) |
| saw_root = true; |
| else if (it.current_layer() == child) |
| saw_child = true; |
| else |
| NOTREACHED(); |
| } |
| } |
| |
| ++num_draws_; |
| // The first draw has no copy request. The 2nd draw has a copy request, the |
| // 3rd should not again. |
| switch (num_draws_) { |
| case 1: |
| // Only the root layer draws, the child is hidden. |
| EXPECT_TRUE(saw_root); |
| EXPECT_FALSE(saw_child); |
| break; |
| case 2: |
| // Copy happening here, the child will draw. |
| EXPECT_TRUE(saw_root); |
| EXPECT_TRUE(saw_child); |
| // Make another draw happen after doing the copy request. |
| host_impl->SetViewportDamage(gfx::Rect(1, 1)); |
| host_impl->SetNeedsRedraw(); |
| break; |
| case 3: |
| // If LayerTreeHostImpl does the wrong thing, it will try to draw the |
| // layer which had a copy request. But only the root should draw. |
| EXPECT_TRUE(saw_root); |
| EXPECT_FALSE(saw_child); |
| |
| // End the test! Don't race with copy request callbacks, so post the end |
| // to the main thread. |
| MainThreadTaskRunner()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest:: |
| TryEndTest, |
| base::Unretained(this), WhatHappened::DRAW)); |
| break; |
| } |
| return draw_result; |
| } |
| |
| void CopyOutputCallback(std::unique_ptr<viz::CopyOutputResult> result) { |
| EXPECT_FALSE(TestEnded()); |
| TryEndTest(WhatHappened::COPY); |
| } |
| |
| enum class WhatHappened { |
| DRAW, |
| COPY, |
| }; |
| |
| void TryEndTest(WhatHappened what) { |
| switch (what) { |
| case WhatHappened::DRAW: |
| draw_happened_ = true; |
| break; |
| case WhatHappened::COPY: |
| copy_happened_ = true; |
| break; |
| } |
| if (draw_happened_ && copy_happened_) |
| EndTest(); |
| } |
| |
| void AfterTest() override {} |
| |
| scoped_refptr<FakePictureLayer> child_; |
| FakeContentLayerClient client_; |
| int num_draws_; |
| bool copy_happened_; |
| bool draw_happened_; |
| }; |
| |
| SINGLE_AND_MULTI_THREAD_TEST_F( |
| LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest); |
| |
| } // namespace |
| } // namespace cc |